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