1 /* Copyright 2012-present Facebook, Inc.
2 * Licensed under the Apache License, Version 2.0 */
3 #include "ChildProcess.h"
4 #include "Logging.h"
5 #include "ThreadPool.h"
6 #include "watchman.h"
7 #ifndef _WIN32
8 #include <poll.h>
9 #endif
10
11 using watchman::ChildProcess;
12 using watchman::FileDescriptor;
13 using Options = ChildProcess::Options;
14
15 static int show_help = 0;
16 static int show_version = 0;
17 static enum w_pdu_type server_pdu = is_bser;
18 static enum w_pdu_type output_pdu = is_json_pretty;
19 static uint32_t server_capabilities = 0;
20 static uint32_t output_capabilities = 0;
21 static char *server_encoding = NULL;
22 static char *output_encoding = NULL;
23 static char *test_state_dir = NULL;
24 static char *sock_name = NULL;
25 char *log_name = NULL;
26 static char *pid_file = NULL;
27 char *watchman_state_file = NULL;
28 static char **daemon_argv = NULL;
29 const char *watchman_tmp_dir = NULL;
30 static int persistent = 0;
31 int dont_save_state = 0;
32 static int foreground = 0;
33 static int no_pretty = 0;
34 static int no_spawn = 0;
35 static int no_local = 0;
36 #ifndef _WIN32
37 static int inetd_style = 0;
38 static struct sockaddr_un un;
39 #endif
40 static int json_input_arg = 0;
41
42 #ifdef __APPLE__
43 #include <mach-o/dyld.h>
44 #endif
45
46 static const char *compute_user_name(void);
47 static void compute_file_name(char **strp, const char *user, const char *suffix,
48 const char *what);
49
lock_pidfile(void)50 static bool lock_pidfile(void) {
51 #if !defined(USE_GIMLI) && !defined(_WIN32)
52 struct flock lock;
53 pid_t mypid;
54
55 // We defer computing this path until we're in the server context because
56 // eager evaluation can trigger integration test failures unless all clients
57 // are aware of both the pidfile and the sockpath being used in the tests.
58 compute_file_name(&pid_file, compute_user_name(), "pid", "pidfile");
59
60 mypid = getpid();
61 memset(&lock, 0, sizeof(lock));
62 lock.l_type = F_WRLCK;
63 lock.l_start = 0;
64 lock.l_whence = SEEK_SET;
65 lock.l_len = 0;
66
67 FileDescriptor fd(open(pid_file, O_RDWR | O_CREAT, 0644));
68
69 if (!fd) {
70 w_log(W_LOG_ERR, "Failed to open pidfile %s for write: %s\n", pid_file,
71 strerror(errno));
72 return false;
73 }
74 // Ensure that no children inherit the locked pidfile descriptor
75 fd.setCloExec();
76
77 if (fcntl(fd.fd(), F_SETLK, &lock) != 0) {
78 char pidstr[32];
79 int len;
80
81 len = read(fd.fd(), pidstr, sizeof(pidstr) - 1);
82 pidstr[len] = '\0';
83
84 w_log(W_LOG_ERR, "Failed to lock pidfile %s: process %s owns it: %s\n",
85 pid_file, pidstr, strerror(errno));
86 return false;
87 }
88
89 // Replace contents of the pidfile with our pid string
90 if (ftruncate(fd.fd(), 0)) {
91 w_log(W_LOG_ERR, "Failed to truncate pidfile %s: %s\n",
92 pid_file, strerror(errno));
93 return false;
94 }
95
96 dprintf(fd.fd(), "%d", mypid);
97 fsync(fd.fd());
98
99 /* We are intentionally not closing the fd and intentionally not storing
100 * a reference to it anywhere: the intention is that it remain locked
101 * for the rest of the lifetime of our process.
102 * close(fd); // NOPE!
103 */
104 fd.release();
105 return true;
106 #else
107 // ze-googles, they do nothing!!
108 return true;
109 #endif
110 }
111
run_service(void)112 static void run_service(void)
113 {
114 int fd;
115 bool res;
116
117 #ifndef _WIN32
118 // Before we redirect stdin/stdout to the log files, move any inetd-provided
119 // socket to a different descriptor number.
120 if (inetd_style) {
121 w_listener_prep_inetd();
122 }
123 #endif
124
125 // redirect std{in,out,err}
126 fd = open("/dev/null", O_RDONLY);
127 if (fd != -1) {
128 ignore_result(dup2(fd, STDIN_FILENO));
129 close(fd);
130 }
131 fd = open(log_name, O_WRONLY|O_APPEND|O_CREAT, 0600);
132 if (fd != -1) {
133 ignore_result(dup2(fd, STDOUT_FILENO));
134 ignore_result(dup2(fd, STDERR_FILENO));
135 close(fd);
136 }
137
138 if (!lock_pidfile()) {
139 return;
140 }
141
142 #ifndef _WIN32
143 /* we are the child, let's set things up */
144 ignore_result(chdir("/"));
145 #endif
146
147 w_set_thread_name("listener");
148 {
149 char hostname[256];
150 gethostname(hostname, sizeof(hostname));
151 hostname[sizeof(hostname) - 1] = '\0';
152 w_log(W_LOG_ERR, "Watchman %s %s starting up on %s\n",
153 PACKAGE_VERSION,
154 #ifdef WATCHMAN_BUILD_INFO
155 WATCHMAN_BUILD_INFO,
156 #else
157 "<no build info set>",
158 #endif
159 hostname);
160 }
161
162 #ifndef _WIN32
163 // Block SIGCHLD by default; we only want it to be delivered
164 // to the reaper thread and only when it is ready to reap.
165 // This MUST happen before we spawn any threads so that they
166 // can pick up our default blocked signal mask.
167 {
168 sigset_t sigset;
169
170 sigemptyset(&sigset);
171 sigaddset(&sigset, SIGCHLD);
172 sigprocmask(SIG_BLOCK, &sigset, NULL);
173 }
174 #endif
175
176 watchman::getThreadPool().start(
177 cfg_get_int("thread_pool_worker_threads", 16),
178 cfg_get_int("thread_pool_max_items", 1024 * 1024));
179
180 ClockSpec::init();
181 w_state_load();
182 res = w_start_listener(sock_name);
183 w_root_free_watched_roots();
184 cfg_shutdown();
185
186 watchman::log(watchman::ERR, "Exiting from service with res=", res, "\n");
187
188 if (res) {
189 exit(0);
190 }
191 exit(1);
192 }
193
194 #ifndef _WIN32
195 // close any random descriptors that we may have inherited,
196 // leaving only the main stdio descriptors open, if we execute a
197 // child process.
close_random_fds(void)198 static void close_random_fds(void) {
199 struct rlimit limit;
200 long open_max = 0;
201 int max_fd;
202
203 // Deduce the upper bound for number of descriptors
204 limit.rlim_cur = 0;
205 #ifdef RLIMIT_NOFILE
206 if (getrlimit(RLIMIT_NOFILE, &limit) != 0) {
207 limit.rlim_cur = 0;
208 }
209 #elif defined(RLIM_OFILE)
210 if (getrlimit(RLIMIT_OFILE, &limit) != 0) {
211 limit.rlim_cur = 0;
212 }
213 #endif
214 #ifdef _SC_OPEN_MAX
215 open_max = sysconf(_SC_OPEN_MAX);
216 #endif
217 if (open_max <= 0) {
218 open_max = 36; /* POSIX_OPEN_MAX (20) + some padding */
219 }
220 if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > INT_MAX) {
221 // "no limit", which seems unlikely
222 limit.rlim_cur = INT_MAX;
223 }
224 // Take the larger of the two values we compute
225 if (limit.rlim_cur > (rlim_t)open_max) {
226 open_max = limit.rlim_cur;
227 }
228
229 for (max_fd = open_max; max_fd > STDERR_FILENO; --max_fd) {
230 close(max_fd);
231 }
232 }
233 #endif
234
235 #if !defined(USE_GIMLI) && !defined(_WIN32)
daemonize(void)236 static void daemonize(void)
237 {
238 close_random_fds();
239
240 // the double-fork-and-setsid trick establishes a
241 // child process that runs in its own process group
242 // with its own session and that won't get killed
243 // off when your shell exits (for example).
244 if (fork()) {
245 // The parent of the first fork is the client
246 // process that is being run by the user, and
247 // we want to allow that to continue.
248 return;
249 }
250 setsid();
251 if (fork()) {
252 // The parent of the second fork has served its
253 // purpose, so we simply exit here, otherwise
254 // we'll duplicate the effort of either the
255 // client or the server depending on if we
256 // return or not.
257 _exit(0);
258 }
259
260 // we are the child, let's set things up
261 run_service();
262 }
263 #endif
264
265 #ifdef _WIN32
spawn_win32(void)266 static void spawn_win32(void) {
267 char module_name[WATCHMAN_NAME_MAX];
268 GetModuleFileName(NULL, module_name, sizeof(module_name));
269
270 Options opts;
271 opts.setFlags(POSIX_SPAWN_SETPGROUP);
272 opts.open(STDIN_FILENO, "/dev/null", O_RDONLY, 0666);
273 opts.open(STDOUT_FILENO, log_name, O_WRONLY | O_CREAT | O_APPEND, 0600);
274 opts.dup2(STDOUT_FILENO, STDERR_FILENO);
275
276 std::vector<w_string_piece> args{module_name, "--foreground"};
277 for (size_t i = 0; daemon_argv[i]; i++) {
278 args.push_back(daemon_argv[i]);
279 }
280
281 ChildProcess proc(args, std::move(opts));
282 proc.disown();
283 }
284 #endif
285
286 #ifdef USE_GIMLI
spawn_via_gimli(void)287 static void spawn_via_gimli(void)
288 {
289 std::vector<w_string_piece> args{
290 GIMLI_MONITOR_PATH,
291 #ifdef WATCHMAN_STATE_DIR
292 "--trace-dir=" WATCHMAN_STATE_DIR "/traces",
293 #endif
294 "--pidfile",
295 pid_file,
296 "watchman",
297 "--foreground",
298 };
299
300 for (size_t i = 0; daemon_argv[i]; i++) {
301 args.push_back(daemon_argv[i]);
302 }
303
304 close_random_fds();
305
306 Options opts;
307 opts.open(STDIN_FILENO, "/dev/null", O_RDONLY, 0666);
308 opts.open(STDOUT_FILENO, log_name, O_WRONLY | O_CREAT | O_APPEND, 0600);
309 opts.dup2(STDOUT_FILENO, STDERR_FILENO);
310
311 ChildProcess proc(args, std::move(opts));
312 proc.disown();
313 }
314 #endif
315
316 #ifndef _WIN32
317 // Spawn watchman via a site-specific spawn helper program.
318 // We'll pass along any daemon-appropriate arguments that
319 // we noticed during argument parsing.
spawn_site_specific(const char * spawner)320 static void spawn_site_specific(const char *spawner)
321 {
322 std::vector<w_string_piece> args{
323 spawner,
324 };
325
326 for (size_t i = 0; daemon_argv[i]; i++) {
327 args.push_back(daemon_argv[i]);
328 }
329
330 close_random_fds();
331
332 Options opts;
333 opts.open(STDIN_FILENO, "/dev/null", O_RDONLY, 0666);
334 opts.open(STDOUT_FILENO, log_name, O_WRONLY | O_CREAT | O_APPEND, 0600);
335 opts.dup2(STDOUT_FILENO, STDERR_FILENO);
336
337 try {
338 ChildProcess proc(args, std::move(opts));
339
340 auto res = proc.wait();
341
342 if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
343 return;
344 }
345
346 if (WIFEXITED(res)) {
347 watchman::log(
348 watchman::FATAL,
349 spawner,
350 ": exited with status ",
351 WEXITSTATUS(res),
352 "\n");
353 } else if (WIFSIGNALED(res)) {
354 watchman::log(
355 watchman::FATAL, spawner, ": signaled with ", WTERMSIG(res), "\n");
356 }
357 watchman::log(
358 watchman::ERR, spawner, ": failed to start, exit status ", res, "\n");
359
360 } catch (const std::exception& exc) {
361 watchman::log(
362 watchman::FATAL,
363 "Failed to spawn watchman via `",
364 spawner,
365 "': ",
366 exc.what(),
367 "\n");
368 }
369 }
370 #endif
371
372 #ifdef __APPLE__
spawn_via_launchd(void)373 static void spawn_via_launchd(void)
374 {
375 char watchman_path[WATCHMAN_NAME_MAX];
376 uint32_t size = sizeof(watchman_path);
377 char plist_path[WATCHMAN_NAME_MAX];
378 FILE *fp;
379 struct passwd *pw;
380 uid_t uid;
381
382 close_random_fds();
383
384 if (_NSGetExecutablePath(watchman_path, &size) == -1) {
385 w_log(W_LOG_ERR, "_NSGetExecutablePath: path too long; size %u\n", size);
386 abort();
387 }
388
389 uid = getuid();
390 pw = getpwuid(uid);
391 if (!pw) {
392 w_log(W_LOG_ERR, "getpwuid(%d) failed: %s. I don't know who you are\n",
393 uid, strerror(errno));
394 abort();
395 }
396
397 snprintf(plist_path, sizeof(plist_path),
398 "%s/Library/LaunchAgents", pw->pw_dir);
399 // Best effort attempt to ensure that the agents dir exists. We'll detect
400 // and report the failure in the fopen call below.
401 mkdir(plist_path, 0755);
402 snprintf(plist_path, sizeof(plist_path),
403 "%s/Library/LaunchAgents/com.github.facebook.watchman.plist", pw->pw_dir);
404
405 if (access(plist_path, R_OK) == 0) {
406 // Unload any that may already exist, as it is likely wrong
407
408 ChildProcess unload_proc(
409 {"/bin/launchctl", "unload", "-F", plist_path}, Options());
410 unload_proc.wait();
411
412 // Forcibly remove the plist. In some cases it may have some attributes
413 // set that prevent launchd from loading it. This can happen where
414 // the system was re-imaged or restored from a backup
415 unlink(plist_path);
416 }
417
418 fp = fopen(plist_path, "w");
419 if (!fp) {
420 w_log(W_LOG_ERR, "Failed to open %s for write: %s\n",
421 plist_path, strerror(errno));
422 abort();
423 }
424
425 compute_file_name(&pid_file, compute_user_name(), "pid", "pidfile");
426
427 auto plist_content = watchman::to<std::string>(
428 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
429 "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
430 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
431 "<plist version=\"1.0\">\n"
432 "<dict>\n"
433 " <key>Label</key>\n"
434 " <string>com.github.facebook.watchman</string>\n"
435 " <key>Disabled</key>\n"
436 " <false/>\n"
437 " <key>ProgramArguments</key>\n"
438 " <array>\n"
439 " <string>",
440 watchman_path,
441 "</string>\n"
442 " <string>--foreground</string>\n"
443 " <string>--logfile=",
444 log_name,
445 "</string>\n"
446 " <string>--log-level=",
447 log_level,
448 "</string>\n"
449 " <string>--sockname=",
450 sock_name,
451 "</string>\n"
452 " <string>--statefile=",
453 watchman_state_file,
454 "</string>\n"
455 " <string>--pidfile=",
456 pid_file,
457 "</string>\n"
458 " </array>\n"
459 " <key>KeepAlive</key>\n"
460 " <dict>\n"
461 " <key>Crashed</key>\n"
462 " <true/>\n"
463 " </dict>\n"
464 " <key>RunAtLoad</key>\n"
465 " <true/>\n"
466 " <key>EnvironmentVariables</key>\n"
467 " <dict>\n"
468 " <key>PATH</key>\n"
469 " <string><![CDATA[",
470 getenv("PATH"),
471 "]]></string>\n"
472 " </dict>\n"
473 " <key>ProcessType</key>\n"
474 " <string>Interactive</string>\n"
475 " <key>Nice</key>\n"
476 " <integer>-5</integer>\n"
477 "</dict>\n"
478 "</plist>\n");
479 fwrite(plist_content.data(), 1, plist_content.size(), fp);
480 fclose(fp);
481 // Don't rely on umask, ensure we have the correct perms
482 chmod(plist_path, 0644);
483
484 ChildProcess load_proc(
485 {"/bin/launchctl", "load", "-F", plist_path}, Options());
486 auto res = load_proc.wait();
487
488 if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
489 return;
490 }
491
492 // Most likely cause is "headless" operation with no GUI context
493 if (WIFEXITED(res)) {
494 w_log(W_LOG_ERR, "launchctl: exited with status %d\n", WEXITSTATUS(res));
495 } else if (WIFSIGNALED(res)) {
496 w_log(W_LOG_ERR, "launchctl: signaled with %d\n", WTERMSIG(res));
497 }
498 w_log(W_LOG_ERR, "Falling back to daemonize\n");
499 daemonize();
500 }
501 #endif
502
parse_encoding(const char * enc,enum w_pdu_type * pdu)503 static void parse_encoding(const char *enc, enum w_pdu_type *pdu)
504 {
505 if (!enc) {
506 return;
507 }
508 if (!strcmp(enc, "json")) {
509 *pdu = is_json_compact;
510 return;
511 }
512 if (!strcmp(enc, "bser")) {
513 *pdu = is_bser;
514 return;
515 }
516 if (!strcmp(enc, "bser-v2")) {
517 *pdu = is_bser_v2;
518 return;
519 }
520 w_log(W_LOG_ERR, "Invalid encoding '%s', use one of json, bser or bser-v2\n",
521 enc);
522 exit(EX_USAGE);
523 }
524
get_env_with_fallback(const char * name1,const char * name2,const char * fallback)525 static const char *get_env_with_fallback(const char *name1,
526 const char *name2, const char *fallback)
527 {
528 const char *val;
529
530 val = getenv(name1);
531 if (!val || *val == 0) {
532 val = getenv(name2);
533 }
534 if (!val || *val == 0) {
535 val = fallback;
536 }
537
538 return val;
539 }
540
compute_file_name(char ** strp,const char * user,const char * suffix,const char * what)541 static void compute_file_name(char **strp,
542 const char *user,
543 const char *suffix,
544 const char *what)
545 {
546 char *str = NULL;
547
548 str = *strp;
549
550 if (!str) {
551 /* We'll put our various artifacts in a user specific dir
552 * within the state dir location */
553 char *state_dir = NULL;
554 const char *state_parent = test_state_dir ? test_state_dir :
555 #ifdef WATCHMAN_STATE_DIR
556 WATCHMAN_STATE_DIR
557 #else
558 watchman_tmp_dir
559 #endif
560 ;
561
562 ignore_result(asprintf(&state_dir, "%s/%s-state", state_parent, user));
563
564 if (!state_dir) {
565 w_log(W_LOG_ERR, "out of memory computing %s\n", what);
566 exit(1);
567 }
568
569 if (mkdir(state_dir, 0700) == 0 || errno == EEXIST) {
570 #ifndef _WIN32
571 // verify ownership
572 struct stat st;
573 int dir_fd;
574 int ret = 0;
575 uid_t euid = geteuid();
576 // TODO: also allow a gid to be specified here
577 const char* sock_group_name = cfg_get_string("sock_group", nullptr);
578 // S_ISGID is set so that files inside this directory inherit the group
579 // name
580 mode_t dir_perms =
581 cfg_get_perms(
582 "sock_access", false /* write bits */, true /* execute bits */) |
583 S_ISGID;
584
585 auto dirp =
586 w_dir_open(state_dir, false /* don't need strict symlink rules */);
587
588 dir_fd = dirp->getFd();
589 if (dir_fd == -1) {
590 w_log(W_LOG_ERR, "dirfd(%s): %s\n", state_dir, strerror(errno));
591 goto bail;
592 }
593
594 if (fstat(dir_fd, &st) != 0) {
595 w_log(W_LOG_ERR, "fstat(%s): %s\n", state_dir, strerror(errno));
596 ret = 1;
597 goto bail;
598 }
599 if (euid != st.st_uid) {
600 w_log(W_LOG_ERR,
601 "the owner of %s is uid %d and doesn't match your euid %d\n",
602 state_dir, st.st_uid, euid);
603 ret = 1;
604 goto bail;
605 }
606 if (st.st_mode & 0022) {
607 w_log(W_LOG_ERR,
608 "the permissions on %s allow others to write to it. "
609 "Verify that you own the contents and then fix its "
610 "permissions by running `chmod 0700 %s`\n",
611 state_dir,
612 state_dir);
613 ret = 1;
614 goto bail;
615 }
616
617 if (sock_group_name) {
618 const struct group *sock_group = w_get_group(sock_group_name);
619 if (!sock_group) {
620 ret = 1;
621 goto bail;
622 }
623
624 if (fchown(dir_fd, -1, sock_group->gr_gid) == -1) {
625 w_log(W_LOG_ERR, "setting up group '%s' failed: %s\n",
626 sock_group_name, strerror(errno));
627 ret = 1;
628 goto bail;
629 }
630 }
631
632 // Depending on group and world accessibility, change permissions on the
633 // directory. We can't leave the directory open and set permissions on the
634 // socket because not all POSIX systems respect permissions on UNIX domain
635 // sockets, but all POSIX systems respect permissions on the containing
636 // directory.
637 w_log(W_LOG_DBG, "Setting permissions on state dir to 0%o\n", dir_perms);
638 if (fchmod(dir_fd, dir_perms) == -1) {
639 w_log(W_LOG_ERR, "fchmod(%s, %#o): %s\n", state_dir, dir_perms,
640 strerror(errno));
641 ret = 1;
642 goto bail;
643 }
644
645 bail:
646 if (ret) {
647 exit(ret);
648 }
649 #endif
650 } else {
651 w_log(W_LOG_ERR, "while computing %s: failed to create %s: %s\n", what,
652 state_dir, strerror(errno));
653 exit(1);
654 }
655
656 ignore_result(asprintf(&str, "%s/%s", state_dir, suffix));
657
658 if (!str) {
659 w_log(W_LOG_ERR, "out of memory computing %s", what);
660 abort();
661 }
662
663 free(state_dir);
664 }
665
666 #ifndef _WIN32
667 if (str[0] != '/') {
668 w_log(W_LOG_ERR, "invalid %s: %s", what, str);
669 abort();
670 }
671 #endif
672
673 *strp = str;
674 }
675
676 #ifndef _WIN32
w_get_group(const char * group_name)677 const struct group *w_get_group(const char *group_name) {
678 // This explicit errno statement is necessary to distinguish between the
679 // group not existing and an error.
680 errno = 0;
681 struct group *group = getgrnam(group_name);
682 if (!group) {
683 if (errno == 0) {
684 w_log(W_LOG_ERR, "group '%s' does not exist\n", group_name);
685 } else {
686 w_log(W_LOG_ERR, "getting gid for '%s' failed: %s\n", group_name,
687 strerror(errno));
688 }
689 return nullptr;
690 }
691 return group;
692 }
693 #endif // ndef _WIN32
694
compute_user_name(void)695 static const char *compute_user_name(void) {
696 const char *user = get_env_with_fallback("USER", "LOGNAME", NULL);
697 #ifdef _WIN32
698 static char user_buf[256];
699 #endif
700
701 if (!user) {
702 #ifdef _WIN32
703 DWORD size = sizeof(user_buf);
704 if (GetUserName(user_buf, &size)) {
705 user_buf[size] = 0;
706 user = user_buf;
707 } else {
708 w_log(W_LOG_FATAL, "GetUserName failed: %s. I don't know who you are\n",
709 win32_strerror(GetLastError()));
710 }
711 #else
712 uid_t uid = getuid();
713 struct passwd *pw;
714
715 pw = getpwuid(uid);
716 if (!pw) {
717 w_log(W_LOG_FATAL, "getpwuid(%d) failed: %s. I don't know who you are\n",
718 uid, strerror(errno));
719 }
720
721 user = pw->pw_name;
722 #endif
723
724 if (!user) {
725 w_log(W_LOG_ERR, "watchman requires that you set $USER in your env\n");
726 abort();
727 }
728 }
729
730 return user;
731 }
732
setup_sock_name(void)733 static void setup_sock_name(void)
734 {
735 const char *user = compute_user_name();
736
737 watchman_tmp_dir = get_env_with_fallback("TMPDIR", "TMP", "/tmp");
738
739 #ifdef _WIN32
740 if (!sock_name) {
741 asprintf(&sock_name, "\\\\.\\pipe\\watchman-%s", user);
742 }
743 #else
744 compute_file_name(&sock_name, user, "sock", "sockname");
745 #endif
746 compute_file_name(&watchman_state_file, user, "state", "statefile");
747 compute_file_name(&log_name, user, "log", "logname");
748 #ifdef USE_GIMLI
749 compute_file_name(&pid_file, user, "pid", "pidfile");
750 #endif
751
752 #ifndef _WIN32
753 if (strlen(sock_name) >= sizeof(un.sun_path) - 1) {
754 w_log(W_LOG_ERR, "%s: path is too long\n",
755 sock_name);
756 abort();
757 }
758
759 un.sun_family = PF_LOCAL;
760 memcpy(un.sun_path, sock_name, strlen(sock_name) + 1);
761 #endif
762 }
763
should_start(int err)764 static bool should_start(int err)
765 {
766 if (err == ECONNREFUSED) {
767 return true;
768 }
769 if (err == ENOENT) {
770 return true;
771 }
772 return false;
773 }
774
try_command(json_t * cmd,int timeout)775 static bool try_command(json_t *cmd, int timeout)
776 {
777 w_jbuffer_t buffer;
778 w_jbuffer_t output_pdu_buffer;
779 int err;
780
781 auto client = w_stm_connect(sock_name, timeout * 1000);
782 if (!client) {
783 return false;
784 }
785
786 if (!cmd) {
787 return true;
788 }
789
790 // Send command
791 if (!buffer.pduEncodeToStream(
792 server_pdu, server_capabilities, cmd, client.get())) {
793 err = errno;
794 w_log(W_LOG_ERR, "error sending PDU to server\n");
795 errno = err;
796 return false;
797 }
798
799 buffer.clear();
800
801 do {
802 if (!buffer.passThru(
803 output_pdu,
804 output_capabilities,
805 &output_pdu_buffer,
806 client.get())) {
807 return false;
808 }
809 } while (persistent);
810
811 return true;
812 }
813
814 static struct watchman_getopt opts[] = {
815 { "help", 'h', "Show this help",
816 OPT_NONE, &show_help, NULL, NOT_DAEMON },
817 #ifndef _WIN32
818 { "inetd", 0, "Spawning from an inetd style supervisor",
819 OPT_NONE, &inetd_style, NULL, IS_DAEMON },
820 #endif
821 { "version", 'v', "Show version number",
822 OPT_NONE, &show_version, NULL, NOT_DAEMON },
823 { "sockname", 'U', "Specify alternate sockname",
824 REQ_STRING, &sock_name, "PATH", IS_DAEMON },
825 { "logfile", 'o', "Specify path to logfile",
826 REQ_STRING, &log_name, "PATH", IS_DAEMON },
827 { "log-level", 0, "set the log level (0 = off, default is 1, verbose = 2)",
828 REQ_INT, &log_level, NULL, IS_DAEMON },
829 #ifdef USE_GIMLI
830 { "pidfile", 0, "Specify path to gimli monitor pidfile",
831 REQ_STRING, &pid_file, "PATH", NOT_DAEMON },
832 #else
833 { "pidfile", 0, "Specify path to pidfile",
834 REQ_STRING, &pid_file, "PATH", IS_DAEMON },
835 #endif
836 { "persistent", 'p', "Persist and wait for further responses",
837 OPT_NONE, &persistent, NULL, NOT_DAEMON },
838 { "no-save-state", 'n', "Don't save state between invocations",
839 OPT_NONE, &dont_save_state, NULL, IS_DAEMON },
840 { "statefile", 0, "Specify path to file to hold watch and trigger state",
841 REQ_STRING, &watchman_state_file, "PATH", IS_DAEMON },
842 { "json-command", 'j', "Instead of parsing CLI arguments, take a single "
843 "json object from stdin",
844 OPT_NONE, &json_input_arg, NULL, NOT_DAEMON },
845 { "output-encoding", 0, "CLI output encoding. json (default) or bser",
846 REQ_STRING, &output_encoding, NULL, NOT_DAEMON },
847 { "server-encoding", 0, "CLI<->server encoding. bser (default) or json",
848 REQ_STRING, &server_encoding, NULL, NOT_DAEMON },
849 { "foreground", 'f', "Run the service in the foreground",
850 OPT_NONE, &foreground, NULL, NOT_DAEMON },
851 { "no-pretty", 0, "Don't pretty print JSON",
852 OPT_NONE, &no_pretty, NULL, NOT_DAEMON },
853 { "no-spawn", 0, "Don't try to start the service if it is not available",
854 OPT_NONE, &no_spawn, NULL, NOT_DAEMON },
855 { "no-local", 0, "When no-spawn is enabled, don't try to handle request"
856 " in client mode if service is unavailable",
857 OPT_NONE, &no_local, NULL, NOT_DAEMON },
858 // test-state-dir is for testing only and should not be used in production:
859 // instead, use the compile-time WATCHMAN_STATE_DIR option
860 { "test-state-dir", 0, NULL, REQ_STRING, &test_state_dir, "DIR", NOT_DAEMON },
861 { 0, 0, 0, OPT_NONE, 0, 0, 0 }
862 };
863
parse_cmdline(int * argcp,char *** argvp)864 static void parse_cmdline(int *argcp, char ***argvp)
865 {
866 cfg_load_global_config_file();
867 w_getopt(opts, argcp, argvp, &daemon_argv);
868 if (show_help) {
869 usage(opts, stdout);
870 }
871 if (show_version) {
872 printf("%s\n", PACKAGE_VERSION);
873 exit(0);
874 }
875 watchman::getLog().setStdErrLoggingLevel(
876 static_cast<enum watchman::LogLevel>(log_level));
877 setup_sock_name();
878 parse_encoding(server_encoding, &server_pdu);
879 parse_encoding(output_encoding, &output_pdu);
880 if (!output_encoding) {
881 output_pdu = no_pretty ? is_json_compact : is_json_pretty;
882 }
883 }
884
build_command(int argc,char ** argv)885 static json_ref build_command(int argc, char** argv) {
886 int i;
887
888 // Read blob from stdin
889 if (json_input_arg) {
890 json_error_t err;
891 w_jbuffer_t buf;
892
893 memset(&err, 0, sizeof(err));
894 auto cmd = buf.decodeNext(w_stm_stdin(), &err);
895
896 if (buf.pdu_type == is_bser) {
897 // If they used bser for the input, select bser for output
898 // unless they explicitly requested something else
899 if (!server_encoding) {
900 server_pdu = is_bser;
901 }
902 if (!output_encoding) {
903 output_pdu = is_bser;
904 }
905 } else if (buf.pdu_type == is_bser_v2) {
906 // If they used bser v2 for the input, select bser v2 for output
907 // unless they explicitly requested something else
908 if (!server_encoding) {
909 server_pdu = is_bser_v2;
910 }
911 if (!output_encoding) {
912 output_pdu = is_bser_v2;
913 }
914 }
915
916 if (!cmd) {
917 fprintf(
918 stderr,
919 "failed to parse command from stdin: "
920 "line %d, column %d, position %d: %s\n",
921 err.line,
922 err.column,
923 err.position,
924 err.text);
925 exit(1);
926 }
927 return cmd;
928 }
929
930 // Special case: no arguments means that we just want
931 // to verify that the service is up, starting it if
932 // needed
933 if (argc == 0) {
934 return nullptr;
935 }
936
937 auto cmd = json_array();
938 for (i = 0; i < argc; i++) {
939 json_array_append_new(cmd, typed_string_to_json(argv[i], W_STRING_UNICODE));
940 }
941
942 return cmd;
943 }
944
get_sock_name(void)945 const char *get_sock_name(void)
946 {
947 return sock_name;
948 }
949
spawn_watchman(void)950 static void spawn_watchman(void) {
951 #ifndef _WIN32
952 // If we have a site-specific spawning requirement, then we'll
953 // invoke that spawner rather than using any of the built-in
954 // spawning functionality.
955 const char* site_spawn = cfg_get_string("spawn_watchman_service", nullptr);
956 if (site_spawn) {
957 spawn_site_specific(site_spawn);
958 return;
959 }
960 #endif
961
962 #ifdef USE_GIMLI
963 spawn_via_gimli();
964 #elif defined(__APPLE__)
965 spawn_via_launchd();
966 #elif defined(_WIN32)
967 spawn_win32();
968 #else
969 daemonize();
970 #endif
971 }
972
main(int argc,char ** argv)973 int main(int argc, char **argv)
974 {
975 bool ran;
976
977 parse_cmdline(&argc, &argv);
978
979 if (foreground) {
980 run_service();
981 return 0;
982 }
983
984 w_set_thread_name("cli");
985 auto cmd = build_command(argc, argv);
986 preprocess_command(cmd, output_pdu, output_capabilities);
987
988 ran = try_command(cmd, 0);
989 if (!ran && should_start(errno)) {
990 if (no_spawn) {
991 if (!no_local) {
992 ran = try_client_mode_command(cmd, !no_pretty);
993 }
994 } else {
995 spawn_watchman();
996 // Some site spawner scripts will asynchronously launch the service.
997 // When that happens we may encounter ECONNREFUSED. We need to
998 // tolerate this, so we add some retries.
999 int attempts = 10;
1000 std::chrono::milliseconds interval(10);
1001 while (true) {
1002 ran = try_command(cmd, 10);
1003 if (!ran && should_start(errno) && attempts-- > 0) {
1004 /* sleep override */ std::this_thread::sleep_for(interval);
1005 interval *= 2;
1006 continue;
1007 }
1008 // Success or terminal failure
1009 break;
1010 }
1011 }
1012 }
1013
1014 if (ran) {
1015 return 0;
1016 }
1017
1018 if (!no_spawn) {
1019 w_log(W_LOG_ERR, "unable to talk to your watchman on %s! (%s)\n",
1020 sock_name, strerror(errno));
1021 #ifdef __APPLE__
1022 if (getenv("TMUX")) {
1023 w_log(W_LOG_ERR, "\n"
1024 "You may be hitting a tmux related session issue.\n"
1025 "An immediate workaround is to run:\n"
1026 "\n"
1027 " watchman version\n"
1028 "\n"
1029 "just once, from *outside* your tmux session, to allow the launchd\n"
1030 "registration to be setup. Once done, you can continue to access\n"
1031 "watchman from inside your tmux sessions as usual.\n"
1032 "\n"
1033 "Longer term, you may wish to install this tool:\n"
1034 "\n"
1035 " https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard\n"
1036 "\n"
1037 "and configure tmux to use `reattach-to-user-namespace`\n"
1038 "when it launches your shell.\n");
1039 }
1040 #endif
1041 }
1042 return 1;
1043 }
1044
1045 /* vim:ts=2:sw=2:et:
1046 */
1047