GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/cvmfs_talk.cc Lines: 0 104 0.0 %
Date: 2019-02-03 02:48:13 Branches: 0 68 0.0 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 *
4
 * cvmfs_talk runs query-response cycles against a running cvmfs instance.
5
 */
6
7
#include <errno.h>
8
#include <unistd.h>
9
10
#include <cassert>
11
#include <cstring>
12
#include <string>
13
#include <vector>
14
15
#include "logging.h"
16
#include "options.h"
17
#include "util/pointer.h"
18
#include "util/posix.h"
19
#include "util/string.h"
20
21
22
struct InstanceInfo {
23
  bool IsDefined() {
24
    return !socket_path.empty() || !instance_name.empty();
25
  }
26
27
  // Called at most once by DeterminePath
28
  static std::string GetDefaultDomain() {
29
    std::string result;
30
    BashOptionsManager options_mgr;
31
    options_mgr.ParseDefault("");
32
    bool retval = options_mgr.GetValue("CVMFS_DEFAULT_DOMAIN", &result);
33
    if (!retval) {
34
      LogCvmfs(kLogCvmfs, kLogStderr,
35
               "Error: could not determin CVMFS_DEFAULT_DOMAIN");
36
    }
37
    return result;
38
  }
39
40
  bool DeterminePaths() {
41
    std::string fqrn = instance_name;
42
    if (fqrn.find('.') == std::string::npos) {
43
      static std::string default_domain = GetDefaultDomain();
44
      fqrn = fqrn + "." + default_domain;
45
    }
46
47
    BashOptionsManager options_mgr;
48
    options_mgr.ParseDefault(fqrn);
49
    if (!options_mgr.GetValue("CVMFS_WORKSPACE", &workspace)) {
50
      if (!options_mgr.GetValue("CVMFS_CACHE_DIR", &workspace)) {
51
        bool retval = options_mgr.GetValue("CVMFS_CACHE_BASE", &workspace);
52
        if (!retval) {
53
          LogCvmfs(kLogCvmfs, kLogStderr,
54
                   "CVMFS_WORKSPACE, CVMFS_CACHE_DIR, and CVMFS_CACHE_BASE "
55
                   "missing");
56
          return false;
57
        }
58
59
        std::string optarg;
60
        if (options_mgr.GetValue("CVMFS_SHARED_CACHE", &optarg) &&
61
            options_mgr.IsOn(optarg))
62
        {
63
          workspace += "/shared";
64
        } else {
65
          workspace += "/" + fqrn;
66
        }
67
      }
68
    }
69
70
    socket_path = workspace + "/cvmfs_io." + fqrn;
71
    return true;
72
  }
73
74
  bool CompleteInfo() {
75
    assert(IsDefined());
76
77
    if (socket_path.empty()) {
78
      bool retval = DeterminePaths();
79
      if (!retval)
80
        return false;
81
      identifier = "instance '" + instance_name + "' active in " + workspace;
82
    } else {
83
      workspace = GetParentPath(socket_path);
84
      identifier = "instance listening at " + socket_path;
85
    }
86
    return true;
87
  }
88
89
  std::string socket_path;
90
  std::string instance_name;
91
  std::string workspace;
92
  std::string identifier;
93
};
94
95
96
static bool ReadResponse(int fd) {
97
  std::string line;
98
  char buf;
99
  int retval;
100
  while ((retval = read(fd, &buf, 1)) == 1) {
101
    if (buf == '\n') {
102
      LogCvmfs(kLogCvmfs, kLogStdout, "%s", line.c_str());
103
      line.clear();
104
      continue;
105
    }
106
    line.push_back(buf);
107
  }
108
  return retval == 0;
109
}
110
111
112
bool SendCommand(const std::string &command, InstanceInfo instance_info) {
113
  bool retval = instance_info.CompleteInfo();
114
  if (!retval) return false;
115
116
  int fd = ConnectSocket(instance_info.socket_path);
117
  if (fd < 0) {
118
    if (errno == ENOENT) {
119
      LogCvmfs(kLogCvmfs, kLogStderr,
120
               "Seems like CernVM-FS is not running in %s (not found: %s)",
121
               instance_info.workspace.c_str(),
122
               instance_info.socket_path.c_str());
123
    } else {
124
      LogCvmfs(kLogCvmfs, kLogStderr, "Could not access %s (%d - %s)",
125
               instance_info.identifier.c_str(), errno, strerror(errno));
126
    }
127
    return false;
128
  }
129
130
  WritePipe(fd, command.data(), command.size());
131
  retval = ReadResponse(fd);
132
  close(fd);
133
134
  if (!retval) {
135
    LogCvmfs(kLogCvmfs, kLogStderr, "Broken connection to %s (%d - %s)",
136
             instance_info.identifier.c_str(), errno, strerror(errno));
137
    return false;
138
  }
139
  return true;
140
}
141
142
143
static void Usage(const std::string &exe) {
144
  LogCvmfs(kLogCvmfs, kLogStdout,
145
    "Usage: %s [-i instance | -p socket] <command>                     \n"
146
    "   By default, iteratate through all instances.                   \n"
147
    "\n"
148
    "Example:                                                          \n"
149
    "  %s -i atlas.cern.ch pid                                         \n"
150
    "\n"
151
    "Commands:                                                         \n"
152
    "  tracebuffer flush      flushes the trace buffer to disk         \n"
153
    "  cache instance         describes the active cache manager       \n"
154
    "  cache size             gets current size of file cache          \n"
155
    "  cache list             gets files in cache                      \n"
156
    "  cache list pinned      gets pinned file catalogs in cache       \n"
157
    "  cache list catalogs    gets all file catalogs in cache          \n"
158
    "  cleanup <MB>           cleans file cache until size <= <MB>     \n"
159
    "  cleanup rate <period>  n.o. cleanups in the last <period> min   \n"
160
    "  evict <path>           removes <path> from the cache            \n"
161
    "  pin <path>             pins <path> in the cache                 \n"
162
    "  mountpoint             returns the mount point                  \n"
163
    "  remount [sync]         look for new catalogs                    \n"
164
    "  revision               gets the repository revision             \n"
165
    "  max ttl info           gets the maximum ttl                     \n"
166
    "  max ttl set <minutes>  sets the maximum ttl                     \n"
167
    "  nameserver get         get the DNS server                       \n"
168
    "  nameserver set <host>  sets a DNS server                        \n"
169
    "  host info              get host chain and their rtt,            \n"
170
    "                         if already probed                        \n"
171
    "  host probe             orders the host chain according to rtt   \n"
172
    "  host probe geo         let Stratum 1s order the host chain and  \n"
173
    "                         fallback proxies using the Geo-API       \n"
174
    "  host switch            switches to the next host in the chain   \n"
175
    "  host set <host list>   sets a new host chain                    \n"
176
    "  proxy info             gets load-balance proxy groups           \n"
177
    "  proxy rebalance        randomly selects a new proxy server      \n"
178
    "                         from the current load-balance group      \n"
179
    "  proxy group switch     switches to the next load-balance        \n"
180
    "                         proxy group in the chain                 \n"
181
    "  proxy set <proxy list> sets a new chain of load-balance proxy   \n"
182
    "                         groups (not including fallback proxies)  \n"
183
    "  proxy fallback <list>  sets a new list of fallback proxies      \n"
184
    "  external host info     gets info about external host chain      \n"
185
    "  external host switch   switches to the next external host       \n"
186
    "  external host set                                               \n"
187
    "       <host list>       sets external host chain                 \n"
188
    "  external proxy info    gets info about external proxy groups    \n"
189
    "  external proxy set                                              \n"
190
    "       <proxy list>      sets chain of external proxy groups      \n"
191
    "  timeout info           gets the network timeouts                \n"
192
    "  timeout set                                                     \n"
193
    "       <proxy> <direct>  sets the network timeouts in seconds     \n"
194
    "  pid                    gets the pid                             \n"
195
    "  pid cachemgr           gets the pid of the shared cache manager \n"
196
    "  pid watchdog           gets the pid of the crash handler process\n"
197
    "  parameters             dumps the effective parameters           \n"
198
    "  reset error counters   resets the counter for I/O errors        \n"
199
    "  hotpatch history       shows timestamps and version info of     \n"
200
    "                         loaded (hotpatched) Fuse modules         \n"
201
    "  version                gets cvmfs version                       \n"
202
    "  version patchlevel     gets cvmfs patchlevel                    \n"
203
    "  open catalogs          shows information about currently        \n"
204
    "                         loaded catalogs (_not_ all cached ones)  \n"
205
    "\n",
206
    exe.c_str(), exe.c_str());
207
}
208
209
210
int main(int argc, char *argv[]) {
211
  InstanceInfo instance_info;
212
  std::string command;
213
214
  int c;
215
  // 's' for socket would have been a better option letter but we keep 'p'
216
  // for backwards compatibility.  The '+' at the beginning of the option stirng
217
  // prevents permutation of the option and non-option arguments.
218
  while ((c = getopt(argc, argv, "+hi:p:")) != -1) {
219
    switch (c) {
220
      case 'h':
221
        Usage(argv[0]);
222
        return 0;
223
      case 'p':
224
        instance_info.socket_path = optarg;
225
        break;
226
      case 'i':
227
        instance_info.instance_name = optarg;
228
        break;
229
      case '?':
230
      default:
231
        Usage(argv[0]);
232
        return 1;
233
    }
234
  }
235
236
  for (; optind < argc; ++optind) {
237
    command += argv[optind];
238
    if (optind < (argc - 1))
239
      command.push_back(' ');
240
  }
241
  if (command.empty()) {
242
    LogCvmfs(kLogCvmfs, kLogStderr, "Command missing");
243
    return 1;
244
  }
245
246
  int retcode = 0;
247
  if (!instance_info.IsDefined()) {
248
    BashOptionsManager options_mgr;
249
    options_mgr.ParseDefault("");
250
    std::string opt_repos;
251
    options_mgr.GetValue("CVMFS_REPOSITORIES", &opt_repos);
252
    std::vector<std::string> repos = SplitString(opt_repos, ',');
253
    for (unsigned i = 0; i < repos.size(); ++i) {
254
      if (repos[i].empty())
255
        continue;
256
      instance_info.instance_name = repos[i];
257
      LogCvmfs(kLogCvmfs, kLogStdout, "%s:", repos[i].c_str());
258
      bool retval = SendCommand(command, instance_info);
259
      if (!retval) retcode = 1;
260
    }
261
  } else {
262
    bool retval = SendCommand(command, instance_info);
263
    if (!retval) retcode = 1;
264
  }
265
  return retcode;
266
}