CernVM-FS  2.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
swissknife_info.cc
Go to the documentation of this file.
1 
8 #define __STDC_FORMAT_MACROS
9 
10 #include "swissknife_info.h"
11 #include "cvmfs_config.h"
12 
13 #include <string>
14 
15 #include "download.h"
16 #include "hash.h"
17 #include "logging.h"
18 #include "manifest.h"
19 #include "util/posix.h"
20 #include "util/string.h"
21 
22 using namespace std; // NOLINT
23 
24 namespace swissknife {
25 
29 static bool IsRemote(const string &repository) {
30  return repository.substr(0, 7) == "http://";
31 }
32 
36 bool CommandInfo::Exists(const string &repository, const string &file) const {
37  if (IsRemote(repository)) {
38  const string url = repository + "/" + file;
39  download::JobInfo head(&url, false);
40  return download_manager()->Fetch(&head) == download::kFailOk;
41  } else {
42  return FileExists(file);
43  }
44 }
45 
46 ParameterList CommandInfo::GetParams() const {
48  r.push_back(Parameter::Mandatory('r', "repository directory / url"));
49  r.push_back(Parameter::Optional('u', "repository mount point"));
50  r.push_back(Parameter::Optional('l', "log level (0-4, default: 2)"));
51  r.push_back(Parameter::Switch('c', "show root catalog hash"));
52  r.push_back(Parameter::Switch('C', "show mounted root catalog hash"));
53  r.push_back(Parameter::Switch('n', "show fully qualified repository name"));
54  r.push_back(Parameter::Switch('t', "show time stamp"));
55  r.push_back(Parameter::Switch('m',
56  "check if repository is marked as "
57  "replication master copy"));
58  r.push_back(Parameter::Switch('v', "repository revision number"));
59  r.push_back(Parameter::Switch('g',
60  "check if repository is garbage "
61  "collectable"));
62  r.push_back(Parameter::Switch('o',
63  "check if the repository maintains a "
64  "reference log file"));
65  r.push_back(Parameter::Switch('h', "print results in human readable form"));
66  r.push_back(Parameter::Switch('L', "follow HTTP redirects"));
67  r.push_back(Parameter::Switch('X',
68  "show whether external data is supported "
69  "in the root catalog."));
70  r.push_back(Parameter::Switch('M', "print repository meta info."));
71  r.push_back(Parameter::Switch('R', "print raw manifest."));
72  r.push_back(Parameter::Switch('e', "check if the repository is empty"));
73  return r;
74 }
75 
77  if (args.find('l') != args.end()) {
78  unsigned log_level =
79  1 << (kLogLevel0 + String2Uint64(*args.find('l')->second));
80  if (log_level > kLogNone) {
81  LogCvmfs(kLogCvmfs, kLogStderr, "invalid log level");
82  return 1;
83  }
84  SetLogVerbosity(static_cast<LogLevels>(log_level));
85  }
86  const string mount_point =
87  (args.find('u') != args.end()) ? *args.find('u')->second : "";
88  const string repository = MakeCanonicalPath(*args.find('r')->second);
89 
90  // sanity check
91  if (args.count('C') > 0 && mount_point.empty()) {
92  LogCvmfs(kLogCvmfs, kLogStderr, "need a CernVM-FS mountpoint (-u) for -C");
93  return 1;
94  }
95 
96  if (IsRemote(repository)) {
97  const bool follow_redirects = args.count('L') > 0;
98  if (!this->InitDownloadManager(follow_redirects)) {
99  return 1;
100  }
101  }
102 
103  // Check if we should be human readable
104  const bool human_readable = (args.count('h') > 0);
105 
106  if (args.count('e') > 0) {
107  string manifest_path = IsRemote(repository)
108  ? ".cvmfspublished"
109  : repository + "/.cvmfspublished";
110  bool is_empty = !Exists(repository, manifest_path);
111  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
112  (human_readable) ? "Empty Repository: " : "",
113  StringifyBool(is_empty).c_str());
114  if (is_empty) return 0;
115  }
116 
117  // Load manifest file
118  // Repository can be HTTP address or on local file system
119  // TODO(jblomer): do this using Manifest::Fetch
120  // currently this is not possible, since Manifest::Fetch asks for the
121  // repository name... Which we want to figure out with the tool at hand.
122  // Possible Fix: Allow for a Manifest::Fetch with an empty name.
124  if (IsRemote(repository)) {
125  const string url = repository + "/.cvmfspublished";
126  download::JobInfo download_manifest(&url, false, false, NULL);
127  download::Failures retval = download_manager()->Fetch(&download_manifest);
128  if (retval != download::kFailOk) {
129  LogCvmfs(kLogCvmfs, kLogStderr, "failed to download manifest (%d - %s)",
130  retval, download::Code2Ascii(retval));
131  return 1;
132  }
133  char *buffer = download_manifest.destination_mem.data;
134  const unsigned length = download_manifest.destination_mem.pos;
135  manifest = manifest::Manifest::LoadMem(
136  reinterpret_cast<const unsigned char *>(buffer), length);
137  free(download_manifest.destination_mem.data);
138  } else {
139  if (chdir(repository.c_str()) != 0) {
140  LogCvmfs(kLogCvmfs, kLogStderr, "failed to switch to directory %s",
141  repository.c_str());
142  return 1;
143  }
144  manifest = manifest::Manifest::LoadFile(".cvmfspublished");
145  }
146 
147  if (!manifest.IsValid()) {
148  LogCvmfs(kLogCvmfs, kLogStderr, "failed to load repository manifest");
149  return 1;
150  }
151 
152  // Validate Manifest
153  const string certificate_path = "data/" + manifest->certificate().MakePath();
154  if (!Exists(repository, certificate_path)) {
155  LogCvmfs(kLogCvmfs, kLogStderr, "failed to find certificate (%s)",
156  certificate_path.c_str());
157  return 1;
158  }
159 
160  // Get information from the mount point
161  if (args.count('C') > 0) {
162  assert(!mount_point.empty());
163  const std::string root_hash_xattr = "user.root_hash";
164  std::string root_hash;
165  const bool success =
166  platform_getxattr(mount_point, root_hash_xattr, &root_hash);
167  if (!success) {
169  "failed to retrieve extended attribute "
170  " '%s' from '%s' (errno: %d)",
171  root_hash_xattr.c_str(), mount_point.c_str(), errno);
172  return 1;
173  }
174  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
175  (human_readable) ? "Mounted Root Hash: " : "",
176  root_hash.c_str());
177  }
178 
179  // Get information about external data
180  if (args.count('X') > 0) {
181  assert(!mount_point.empty());
182  const std::string external_data_xattr = "user.external_data";
183  std::string external_data;
184  const bool success =
185  platform_getxattr(mount_point, external_data_xattr, &external_data);
186  if (!success) {
188  "failed to retrieve extended attribute "
189  " '%s' from '%s' (errno: %d)",
190  external_data_xattr.c_str(), mount_point.c_str(), errno);
191  return 1;
192  }
193  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
194  (human_readable) ? "External data enabled: " : "",
195  external_data.c_str());
196  }
197 
198  // Get information from the Manifest
199  if (args.count('c') > 0) {
200  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
201  (human_readable) ? "Root Catalog Hash: " : "",
202  manifest->catalog_hash().ToString().c_str());
203  }
204 
205  if (args.count('n') > 0) {
206  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
207  (human_readable) ? "Fully Qualified Repository Name: " : "",
208  manifest->repository_name().c_str());
209  }
210 
211  if (args.count('t') > 0) {
212  LogCvmfs(kLogCvmfs, kLogStdout, "%s%d",
213  (human_readable) ? "Time Stamp: " : "",
214  manifest->publish_timestamp());
215  }
216 
217  if (args.count('m') > 0) {
218  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
219  (human_readable) ? "Replication Master Copy: " : "",
220  (Exists(repository, ".cvmfs_master_replica")) ? "true" : "false");
221  }
222 
223  if (args.count('v') > 0) {
224  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
225  (human_readable) ? "Revision: " : "",
226  (StringifyInt(manifest->revision())).c_str());
227  }
228 
229  if (args.count('g') > 0) {
230  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
231  (human_readable) ? "Garbage Collectable: " : "",
232  (StringifyBool(manifest->garbage_collectable())).c_str());
233  }
234 
235  if (args.count('o') > 0) {
236  LogCvmfs(kLogCvmfs, kLogStdout, "%s%s",
237  (human_readable) ? "Maintains Reference Log: " : "",
238  (Exists(repository, ".cvmfsreflog")) ? "true" : "false");
239  }
240 
241  if (args.count('M') > 0) {
242  shash::Any meta_info(manifest->meta_info());
243  if (meta_info.IsNull()) {
244  if (human_readable)
245  LogCvmfs(kLogCvmfs, kLogStderr, "no meta info available");
246  return 0;
247  }
248  const string url = repository + "/data/" + meta_info.MakePath();
249  download::JobInfo download_metainfo(&url, true, false, &meta_info);
250  download::Failures retval = download_manager()->Fetch(&download_metainfo);
251  if (retval != download::kFailOk) {
252  if (human_readable)
254  "failed to download meta info (%d - %s)", retval,
255  download::Code2Ascii(retval));
256  return 1;
257  }
258  string info(download_metainfo.destination_mem.data,
259  download_metainfo.destination_mem.pos);
260  LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak, "%s", info.c_str());
261  }
262 
263  if (args.count('R') > 0) {
265  manifest->ExportString().c_str());
266  }
267 
268  return 0;
269 }
270 
271 //------------------------------------------------------------------------------
272 
273 int CommandVersion::Main(const ArgumentList &args) {
274  LogCvmfs(kLogCvmfs, kLogStdout, "%s", PACKAGE_VERSION);
275  return 0;
276 }
277 
278 } // namespace swissknife
static bool IsRemote(const string &repository)
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
const manifest::Manifest * manifest() const
Definition: repository.h:123
static Manifest * LoadMem(const unsigned char *buffer, const unsigned length)
Definition: manifest.cc:68
std::vector< Parameter > ParameterList
Definition: swissknife.h:71
assert((mem||(size==0))&&"Out Of Memory")
string StringifyBool(const bool value)
Definition: string.cc:75
bool FileExists(const std::string &path)
Definition: posix.cc:725
const char * Code2Ascii(const Failures error)
Definition: download.h:86
bool platform_getxattr(const std::string &path, const std::string &name, std::string *value)
void SetLogVerbosity(const LogLevels min_level)
Definition: logging.cc:207
string StringifyInt(const int64_t value)
Definition: string.cc:77
bool IsValid() const
Definition: pointer.h:44
uint64_t String2Uint64(const string &value)
Definition: string.cc:227
std::map< char, SharedPtr< std::string > > ArgumentList
Definition: swissknife.h:72
struct download::JobInfo::@3 destination_mem
std::string meta_info() const
Definition: repository.h:126
std::string MakeCanonicalPath(const std::string &path)
Definition: posix.cc:95
static Manifest * LoadFile(const std::string &path)
Definition: manifest.cc:78
int Main(const ArgumentList &args)