CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
loader_talk.cc
Go to the documentation of this file.
1 
5 #include "cvmfs_config.h"
6 #include "loader_talk.h"
7 
8 #include <errno.h>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11 #include <unistd.h>
12 
13 #include <cassert>
14 #include <cstdlib>
15 
16 #include "loader.h"
17 #include "util/exception.h"
18 #include "util/logging.h"
19 #include "util/platform.h"
20 #include "util/posix.h"
21 
22 using namespace std; // NOLINT
23 
24 namespace loader {
25 namespace loader_talk {
26 
27 bool spawned_ = false;
28 string *socket_path_ = NULL;
29 int socket_fd_ = -1;
30 pthread_t thread_talk_;
31 
32 bool Init(const string &socket_path) {
33  spawned_ = false;
34  socket_path_ = new string(socket_path);
35 
37  if (socket_fd_ == -1)
38  return false;
39  if (listen(socket_fd_, 1) == -1) {
40  LogCvmfs(kLogCvmfs, kLogDebug, "listening on socket failed (%d)", errno);
41  return false;
42  }
43 
44  unlink((socket_path + ".paused.crashed").c_str());
45  unlink((socket_path + ".paused").c_str());
46 
47  return true;
48 }
49 
50 
51 static void *MainTalk(void *data __attribute__((unused))) {
52  struct sockaddr_un remote;
53  socklen_t socket_size = sizeof(remote);
54  int con_fd = -1;
55  while (true) {
56  if (con_fd >= 0) {
57  shutdown(con_fd, SHUT_RDWR);
58  close(con_fd);
59  }
60  if ((con_fd = accept(socket_fd_, (struct sockaddr *)&remote, &socket_size))
61  < 0)
62  {
63  break;
64  }
65 
66  char command;
67  ReloadMode reload_mode = kReloadLegacy;
68  if (recv(con_fd, &command, 1, 0) > 0) {
69  if ((command == 'd') || (command == 'n')) {
70  // version that specifies reloading in debug or non-debug mode
71  // receives 2 commands
72  // first: debug (d) / non-debug(n)
73  // second: 'R' or 'S'
74  reload_mode = command == 'd' ? kReloadDebug : kReloadNoDebug;
75  if (recv(con_fd, &command, 1, 0) > 0) {
76  if ((command != 'R') && (command != 'S')) {
77  SendMsg2Socket(con_fd, "unknown command\n");
78  continue;
79  }
80  }
81  } else if ((command != 'R') && (command != 'S')) { // legacy support
82  SendMsg2Socket(con_fd, "unknown command\n");
83  continue;
84  }
85 
87  LogCvmfs(kLogCvmfs, kLogSyslog, "reloading Fuse module. Reload mode=%d",
88  reload_mode);
89  int retval = Reload(con_fd, command == 'S', reload_mode);
90  SendMsg2Socket(con_fd, "~");
91  (void)send(con_fd, &retval, sizeof(retval), MSG_NOSIGNAL);
92  if (retval != kFailOk) {
93  PANIC(kLogSyslogErr, "reloading Fuse module failed (%d - %s)", retval,
94  Code2Ascii(static_cast<Failures>(retval)));
95  }
97  }
98  }
99 
100  return NULL;
101 }
102 
103 
104 void Spawn() {
105  int retval;
106  retval = pthread_create(&thread_talk_, NULL, MainTalk, NULL);
107  assert(retval == 0);
108  spawned_ = true;
109 }
110 
111 
112 void Fini() {
113  unlink(socket_path_->c_str());
114  shutdown(socket_fd_, SHUT_RDWR);
115  close(socket_fd_);
116  if (spawned_) pthread_join(thread_talk_, NULL);
117 
118  delete socket_path_;
119  socket_path_ = NULL;
120  spawned_ = false;
121  socket_fd_ = -1;
122 }
123 
124 
128 int MainReload(const std::string &socket_path, const bool stop_and_go,
129  const bool debug) {
131  "Connecting to CernVM-FS loader... ");
132  int socket_fd = ConnectSocket(socket_path);
133  if (socket_fd < 0) {
134  LogCvmfs(kLogCvmfs, kLogStdout, "failed!");
135  return 100;
136  }
137  LogCvmfs(kLogCvmfs, kLogStdout, "done");
138 
139  // reload mode: debug (d) or non-debug (n)
140  char commands[2];
141  commands[0] = debug ? 'd' : 'n';
142  commands[1] = stop_and_go ? 'S' : 'R';
143 
144  // Loaders before version 2.11 won't recognize 'd' or 'n'. They will
145  // send "unknown command" and close the connection. We try to send
146  // both the commands and react according to what we read from the socket.
147 
148  ssize_t retval;
149  do {
150  retval = send(socket_fd, commands, 2, MSG_NOSIGNAL);
151  } while ((retval <= 0) && (errno == EINTR));
152 
153  if (retval <= 0) {
154  LogCvmfs(kLogCvmfs, kLogStderr, "Sending reload command failed!");
155  return 103;
156  }
157 
158  char buf;
159  std::string first_line;
160  bool past_first_line = false;
161  while ((retval = read(socket_fd, &buf, 1)) == 1) {
162  if (buf == '~')
163  break;
164 
165  if (first_line == "unknown command") {
166  // We have a pre-2.11 loader, reconnect to the socket
168  "Connecting in backwards compatibility mode");
169  close(socket_fd);
170  socket_fd = ConnectSocket(socket_path);
171  if (socket_fd < 0) {
172  LogCvmfs(kLogCvmfs, kLogStderr, "reconnecting failed!");
173  return 104;
174  }
175  WritePipe(socket_fd, &commands[1], 1);
176  first_line.clear();
177  past_first_line = true;
178  continue;
179  }
180 
181  // chars are received one by one; in order to check if we get
182  // "unknown command" a string is constructed here
183  if (!past_first_line) {
184  if (buf == '\n') {
185  LogCvmfs(kLogCvmfs, kLogStdout, "%s", first_line.c_str());
186  past_first_line = true;
187  } else {
188  first_line.push_back(buf);
189  }
190  continue;
191  }
192 
194  }
195  if (retval != 1) {
196  LogCvmfs(kLogCvmfs, kLogStderr, "Reload CRASHED! "
197  "CernVM-FS mountpoints unusable.");
198  return 101;
199  }
200 
201  int result = 102;
202  if (read(socket_fd, &result, sizeof(result)) < 0) {
203  LogCvmfs(kLogCvmfs, kLogStderr, "Socket read FAILED! "
204  "CernVM-FS mountpoints unusable.");
205  } else {
206  if (result != kFailOk) {
207  LogCvmfs(kLogCvmfs, kLogStderr, "Reload FAILED! "
208  "CernVM-FS mountpoints unusable.");
209  }
210  }
211 
212  return result;
213 }
214 
215 } // namespace loader_talk
216 } // namespace loader
const char * Code2Ascii(const ObjectFetcherFailures::Failures error)
static void * MainTalk(void *data __attribute__((unused)))
Definition: loader_talk.cc:51
int MakeSocket(const std::string &path, const int mode)
Definition: posix.cc:331
Failures Reload(const int fd_progress, const bool stop_and_go, const ReloadMode reload_mode)
Definition: loader.cc:546
ReloadMode
Definition: loader.h:246
#define PANIC(...)
Definition: exception.h:29
string * usyslog_path_
Definition: loader.cc:129
pthread_t thread_talk_
Definition: loader_talk.cc:30
void SendMsg2Socket(const int fd, const std::string &msg)
Definition: posix.cc:659
assert((mem||(size==0))&&"Out Of Memory")
void SetLogMicroSyslog(const std::string &filename)
Definition: logging.cc:272
struct cvmcache_object_info __attribute__
Definition: atomic.h:24
string * socket_path_
Definition: loader.cc:128
static int Init(const loader::LoaderExports *loader_exports)
Definition: cvmfs.cc:2296
int MainReload(const std::string &socket_path, const bool stop_and_go, const bool debug)
Definition: loader_talk.cc:128
int ConnectSocket(const std::string &path)
Definition: posix.cc:427
static void Fini()
Definition: cvmfs.cc:2519
static void Spawn()
Definition: cvmfs.cc:2427
#define MSG_NOSIGNAL
Definition: platform_osx.h:53
void WritePipe(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:501
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528