Fix: add missing semicolons after MSG, DBG, ERR print macros
[lttng-tools.git] / src / common / runas.c
CommitLineData
60b6c79c
MD
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
d14d33bf
AM
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
60b6c79c
MD
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
d14d33bf 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
60b6c79c
MD
12 * more details.
13 *
d14d33bf
AM
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
60b6c79c
MD
17 */
18
19#define _GNU_SOURCE
6c1c0768 20#define _LGPL_SOURCE
60b6c79c
MD
21#include <errno.h>
22#include <limits.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/wait.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <unistd.h>
30#include <fcntl.h>
c2b75c49 31#include <sched.h>
730389d9 32#include <sys/signal.h>
9f21bc2c 33#include <assert.h>
8c40c9d0 34#include <sys/prctl.h>
60b6c79c 35
90e535ef 36#include <common/common.h>
3fd15a74 37#include <common/utils.h>
e8fa9fb0 38#include <common/compat/getenv.h>
0e904f3e 39#include <common/sessiond-comm/unix.h>
60b6c79c 40
0857097f
DG
41#include "runas.h"
42
0e904f3e
MD
43struct run_as_data;
44typedef int (*run_as_fct)(struct run_as_data *data);
c2b75c49 45
e11d277b 46struct run_as_mkdir_data {
0e904f3e 47 char path[PATH_MAX];
60b6c79c
MD
48 mode_t mode;
49};
50
e11d277b 51struct run_as_open_data {
0e904f3e 52 char path[PATH_MAX];
60b6c79c
MD
53 int flags;
54 mode_t mode;
55};
56
4628484a 57struct run_as_unlink_data {
0e904f3e 58 char path[PATH_MAX];
4628484a
MD
59};
60
0e904f3e
MD
61struct run_as_rmdir_recursive_data {
62 char path[PATH_MAX];
63};
64
65enum run_as_cmd {
66 RUN_AS_MKDIR,
67 RUN_AS_OPEN,
68 RUN_AS_UNLINK,
69 RUN_AS_RMDIR_RECURSIVE,
70 RUN_AS_MKDIR_RECURSIVE,
71};
72
73struct run_as_data {
74 enum run_as_cmd cmd;
75 union {
76 struct run_as_mkdir_data mkdir;
77 struct run_as_open_data open;
78 struct run_as_unlink_data unlink;
79 struct run_as_rmdir_recursive_data rmdir_recursive;
80 } u;
81 uid_t uid;
82 gid_t gid;
4628484a
MD
83};
84
a68b8851
MD
85struct run_as_ret {
86 int ret;
87 int _errno;
88};
89
0e904f3e
MD
90struct run_as_worker {
91 pid_t pid; /* Worker PID. */
92 int sockpair[2];
93 char *procname;
94};
95
96/* Single global worker per process (for now). */
97static struct run_as_worker *global_worker;
98/* Lock protecting the worker. */
99static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
100
8f0044bf
MD
101#ifdef VALGRIND
102static
103int use_clone(void)
104{
105 return 0;
106}
107#else
108static
109int use_clone(void)
110{
e8fa9fb0 111 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
8f0044bf
MD
112}
113#endif
114
d85144f4
JG
115LTTNG_HIDDEN
116int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode);
117
60b6c79c
MD
118/*
119 * Create recursively directory using the FULL path.
120 */
121static
0e904f3e 122int _mkdir_recursive(struct run_as_data *data)
60b6c79c 123{
60b6c79c 124 const char *path;
60b6c79c 125 mode_t mode;
60b6c79c 126
0e904f3e
MD
127 path = data->u.mkdir.path;
128 mode = data->u.mkdir.mode;
60b6c79c 129
d85144f4
JG
130 /* Safe to call as we have transitioned to the requested uid/gid. */
131 return _utils_mkdir_recursive_unsafe(path, mode);
60b6c79c
MD
132}
133
134static
0e904f3e 135int _mkdir(struct run_as_data *data)
60b6c79c 136{
0e904f3e
MD
137 return mkdir(data->u.mkdir.path, data->u.mkdir.mode);
138}
7ce36756 139
0e904f3e
MD
140static
141int _open(struct run_as_data *data)
142{
143 return open(data->u.open.path, data->u.open.flags, data->u.open.mode);
144}
145
146static
147int _unlink(struct run_as_data *data)
148{
149 return unlink(data->u.unlink.path);
60b6c79c
MD
150}
151
152static
0e904f3e 153int _rmdir_recursive(struct run_as_data *data)
60b6c79c 154{
0e904f3e
MD
155 return utils_recursive_rmdir(data->u.rmdir_recursive.path);
156}
a68b8851 157
0e904f3e
MD
158static
159run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd)
160{
161 switch (cmd) {
162 case RUN_AS_MKDIR:
163 return _mkdir;
164 case RUN_AS_OPEN:
165 return _open;
166 case RUN_AS_UNLINK:
167 return _unlink;
168 case RUN_AS_RMDIR_RECURSIVE:
169 return _rmdir_recursive;
170 case RUN_AS_MKDIR_RECURSIVE:
171 return _mkdir_recursive;
172 default:
b75c559e 173 ERR("Unknown command %d", (int) cmd);
0e904f3e
MD
174 return NULL;
175 }
60b6c79c
MD
176}
177
4628484a 178static
0e904f3e
MD
179int do_send_fd(struct run_as_worker *worker,
180 enum run_as_cmd cmd, int fd)
4628484a 181{
0e904f3e 182 ssize_t len;
4628484a 183
0e904f3e
MD
184 switch (cmd) {
185 case RUN_AS_OPEN:
186 break;
187 default:
188 return 0;
189 }
190 if (fd < 0) {
191 return 0;
192 }
193 len = lttcomm_send_fds_unix_sock(worker->sockpair[1], &fd, 1);
194 if (len < 0) {
195 PERROR("lttcomm_send_fds_unix_sock");
196 return -1;
197 }
198 if (close(fd) < 0) {
199 PERROR("close");
200 return -1;
201 }
202 return 0;
4628484a
MD
203}
204
205static
0e904f3e
MD
206int do_recv_fd(struct run_as_worker *worker,
207 enum run_as_cmd cmd, int *fd)
4628484a 208{
0e904f3e 209 ssize_t len;
4628484a 210
0e904f3e
MD
211 switch (cmd) {
212 case RUN_AS_OPEN:
213 break;
214 default:
215 return 0;
216 }
217 if (*fd < 0) {
218 return 0;
219 }
220 len = lttcomm_recv_fds_unix_sock(worker->sockpair[0], fd, 1);
ec601027
JG
221 if (!len) {
222 return -1;
223 } else if (len < 0) {
0e904f3e
MD
224 PERROR("lttcomm_recv_fds_unix_sock");
225 return -1;
226 }
227 return 0;
4628484a
MD
228}
229
0e904f3e
MD
230/*
231 * Return < 0 on error, 0 if OK, 1 on hangup.
232 */
c2b75c49 233static
0e904f3e 234int handle_one_cmd(struct run_as_worker *worker)
c2b75c49 235{
0e904f3e
MD
236 int ret = 0;
237 struct run_as_data data;
238 ssize_t readlen, writelen;
a68b8851 239 struct run_as_ret sendret;
0e904f3e
MD
240 run_as_fct cmd;
241 uid_t prev_euid;
242
243 /* Read data */
244 readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data,
245 sizeof(data));
246 if (readlen == 0) {
247 /* hang up */
248 ret = 1;
249 goto end;
250 }
251 if (readlen < sizeof(data)) {
252 PERROR("lttcomm_recv_unix_sock error");
253 ret = -1;
254 goto end;
255 }
c2b75c49 256
0e904f3e
MD
257 cmd = run_as_enum_to_fct(data.cmd);
258 if (!cmd) {
259 ret = -1;
260 goto end;
261 }
262
263 prev_euid = getuid();
264 if (data.gid != getegid()) {
265 ret = setegid(data.gid);
1576d582 266 if (ret < 0) {
4c462e79 267 PERROR("setegid");
6d73c4ef 268 goto write_return;
1576d582 269 }
c2b75c49 270 }
0e904f3e
MD
271 if (data.uid != prev_euid) {
272 ret = seteuid(data.uid);
1576d582 273 if (ret < 0) {
4c462e79 274 PERROR("seteuid");
6d73c4ef 275 goto write_return;
1576d582 276 }
c2b75c49
MD
277 }
278 /*
279 * Also set umask to 0 for mkdir executable bit.
280 */
281 umask(0);
0e904f3e 282 ret = (*cmd)(&data);
6d73c4ef
MD
283
284write_return:
a68b8851
MD
285 sendret.ret = ret;
286 sendret._errno = errno;
c2b75c49 287 /* send back return value */
0e904f3e
MD
288 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
289 sizeof(sendret));
6cd525e8 290 if (writelen < sizeof(sendret)) {
0e904f3e
MD
291 PERROR("lttcomm_send_unix_sock error");
292 ret = -1;
293 goto end;
294 }
295 ret = do_send_fd(worker, data.cmd, ret);
296 if (ret) {
297 PERROR("do_send_fd error");
298 ret = -1;
299 goto end;
300 }
301 if (seteuid(prev_euid) < 0) {
302 PERROR("seteuid");
303 ret = -1;
304 goto end;
305 }
306 ret = 0;
307end:
308 return ret;
309}
310
311static
312int run_as_worker(struct run_as_worker *worker)
313{
314 int ret;
315 ssize_t writelen;
316 struct run_as_ret sendret;
317 size_t proc_orig_len;
318
319 /*
320 * Initialize worker. Set a different process cmdline.
321 */
322 proc_orig_len = strlen(worker->procname);
323 memset(worker->procname, 0, proc_orig_len);
324 strncpy(worker->procname, DEFAULT_RUN_AS_WORKER_NAME, proc_orig_len);
325
8c40c9d0 326 ret = prctl(PR_SET_NAME, DEFAULT_RUN_AS_WORKER_NAME, 0, 0, 0);
0e904f3e 327 if (ret) {
8c40c9d0
JG
328 /* Don't fail as this is not essential. */
329 PERROR("prctl PR_SET_NAME");
330 ret = 0;
6cd525e8 331 }
0e904f3e
MD
332
333 sendret.ret = 0;
334 sendret._errno = 0;
335 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
336 sizeof(sendret));
337 if (writelen < sizeof(sendret)) {
338 PERROR("lttcomm_send_unix_sock error");
339 ret = EXIT_FAILURE;
340 goto end;
341 }
342
343 for (;;) {
344 ret = handle_one_cmd(worker);
345 if (ret < 0) {
346 ret = EXIT_FAILURE;
347 goto end;
348 } else if (ret > 0) {
349 break;
350 } else {
351 continue; /* Next command. */
352 }
353 }
354 ret = EXIT_SUCCESS;
355end:
356 return ret;
c2b75c49
MD
357}
358
60b6c79c 359static
0e904f3e
MD
360int run_as_cmd(struct run_as_worker *worker,
361 enum run_as_cmd cmd,
362 struct run_as_data *data,
363 uid_t uid, gid_t gid)
60b6c79c 364{
0e904f3e 365 ssize_t readlen, writelen;
a68b8851 366 struct run_as_ret recvret;
60b6c79c
MD
367
368 /*
369 * If we are non-root, we can only deal with our own uid.
370 */
371 if (geteuid() != 0) {
372 if (uid != geteuid()) {
a68b8851
MD
373 recvret.ret = -1;
374 recvret._errno = EPERM;
60b6c79c
MD
375 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
376 uid, geteuid());
a68b8851 377 goto end;
60b6c79c 378 }
60b6c79c
MD
379 }
380
0e904f3e
MD
381 data->cmd = cmd;
382 data->uid = uid;
383 data->gid = gid;
384
385 writelen = lttcomm_send_unix_sock(worker->sockpair[0], data,
386 sizeof(*data));
387 if (writelen < sizeof(*data)) {
388 PERROR("Error writing message to run_as");
a68b8851
MD
389 recvret.ret = -1;
390 recvret._errno = errno;
60b6c79c 391 goto end;
c2b75c49 392 }
0e904f3e 393
c2b75c49 394 /* receive return value */
0e904f3e
MD
395 readlen = lttcomm_recv_unix_sock(worker->sockpair[0], &recvret,
396 sizeof(recvret));
ec601027
JG
397 if (!readlen) {
398 ERR("Run-as worker has hung-up during run_as_cmd");
399 recvret.ret = -1;
400 recvret._errno = EIO;
401 goto end;
402 } else if (readlen < sizeof(recvret)) {
0e904f3e 403 PERROR("Error reading response from run_as");
a68b8851
MD
404 recvret.ret = -1;
405 recvret._errno = errno;
6cd525e8 406 }
0e904f3e 407 if (do_recv_fd(worker, cmd, &recvret.ret)) {
a68b8851 408 recvret.ret = -1;
ec601027 409 recvret._errno = EIO;
4c462e79 410 }
0e904f3e 411
60b6c79c 412end:
a68b8851
MD
413 errno = recvret._errno;
414 return recvret.ret;
60b6c79c
MD
415}
416
2d85a600 417/*
0e904f3e 418 * This is for debugging ONLY and should not be considered secure.
2d85a600
MD
419 */
420static
0e904f3e
MD
421int run_as_noworker(enum run_as_cmd cmd,
422 struct run_as_data *data, uid_t uid, gid_t gid)
2d85a600 423{
a68b8851 424 int ret, saved_errno;
5b73926f 425 mode_t old_mask;
0e904f3e 426 run_as_fct fct;
5b73926f 427
0e904f3e
MD
428 fct = run_as_enum_to_fct(cmd);
429 if (!fct) {
430 errno = -ENOSYS;
431 ret = -1;
432 goto end;
433 }
5b73926f 434 old_mask = umask(0);
0e904f3e 435 ret = fct(data);
a68b8851 436 saved_errno = errno;
5b73926f 437 umask(old_mask);
a68b8851 438 errno = saved_errno;
0e904f3e 439end:
5b73926f 440 return ret;
2d85a600
MD
441}
442
443static
9f21bc2c 444int run_as(enum run_as_cmd cmd, struct run_as_data *data, uid_t uid, gid_t gid)
2d85a600 445{
0e904f3e
MD
446 int ret;
447
9f21bc2c 448 if (use_clone()) {
0e904f3e 449 DBG("Using run_as worker");
9f21bc2c
JG
450 pthread_mutex_lock(&worker_lock);
451 assert(global_worker);
452 ret = run_as_cmd(global_worker, cmd, data, uid, gid);
453 pthread_mutex_unlock(&worker_lock);
454
2d85a600 455 } else {
0e904f3e
MD
456 DBG("Using run_as without worker");
457 ret = run_as_noworker(cmd, data, uid, gid);
2d85a600 458 }
0e904f3e 459 return ret;
2d85a600
MD
460}
461
90e535ef 462LTTNG_HIDDEN
e11d277b 463int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 464{
0e904f3e 465 struct run_as_data data;
60b6c79c
MD
466
467 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
468 path, mode, uid, gid);
0e904f3e
MD
469 strncpy(data.u.mkdir.path, path, PATH_MAX - 1);
470 data.u.mkdir.path[PATH_MAX - 1] = '\0';
471 data.u.mkdir.mode = mode;
9f21bc2c 472 return run_as(RUN_AS_MKDIR_RECURSIVE, &data, uid, gid);
60b6c79c
MD
473}
474
90e535ef 475LTTNG_HIDDEN
e11d277b 476int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 477{
0e904f3e 478 struct run_as_data data;
60b6c79c
MD
479
480 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
481 path, mode, uid, gid);
0e904f3e
MD
482 strncpy(data.u.mkdir.path, path, PATH_MAX - 1);
483 data.u.mkdir.path[PATH_MAX - 1] = '\0';
484 data.u.mkdir.mode = mode;
9f21bc2c 485 return run_as(RUN_AS_MKDIR, &data, uid, gid);
60b6c79c
MD
486}
487
488/*
489 * Note: open_run_as is currently not working. We'd need to pass the fd
490 * opened in the child to the parent.
491 */
90e535ef 492LTTNG_HIDDEN
e11d277b 493int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 494{
0e904f3e 495 struct run_as_data data;
c2b75c49 496
47fb7563
MD
497 DBG3("open() %s with flags %X mode %d for uid %d and gid %d",
498 path, flags, mode, uid, gid);
0e904f3e
MD
499 strncpy(data.u.open.path, path, PATH_MAX - 1);
500 data.u.open.path[PATH_MAX - 1] = '\0';
501 data.u.open.flags = flags;
502 data.u.open.mode = mode;
9f21bc2c 503 return run_as(RUN_AS_OPEN, &data, uid, gid);
60b6c79c 504}
4628484a
MD
505
506LTTNG_HIDDEN
507int run_as_unlink(const char *path, uid_t uid, gid_t gid)
508{
0e904f3e 509 struct run_as_data data;
4628484a
MD
510
511 DBG3("unlink() %s with for uid %d and gid %d",
512 path, uid, gid);
0e904f3e
MD
513 strncpy(data.u.unlink.path, path, PATH_MAX - 1);
514 data.u.unlink.path[PATH_MAX - 1] = '\0';
9f21bc2c 515 return run_as(RUN_AS_UNLINK, &data, uid, gid);
4628484a
MD
516}
517
518LTTNG_HIDDEN
0e904f3e 519int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid)
4628484a 520{
0e904f3e 521 struct run_as_data data;
4628484a 522
0e904f3e 523 DBG3("rmdir_recursive() %s with for uid %d and gid %d",
4628484a 524 path, uid, gid);
0e904f3e
MD
525 strncpy(data.u.rmdir_recursive.path, path, PATH_MAX - 1);
526 data.u.rmdir_recursive.path[PATH_MAX - 1] = '\0';
9f21bc2c 527 return run_as(RUN_AS_RMDIR_RECURSIVE, &data, uid, gid);
0e904f3e
MD
528}
529
1358c609 530static
8ce28af8 531int reset_sighandler(void)
1358c609 532{
8ce28af8 533 int sig, ret = 0;
1358c609
JG
534
535 for (sig = SIGHUP; sig <= SIGUNUSED; sig++) {
536 /* Skip unblockable signals. */
537 if (sig == SIGKILL || sig == SIGSTOP) {
538 continue;
539 }
540 if (signal(sig, SIG_DFL) == SIG_ERR) {
541 PERROR("reset signal %d", sig);
8ce28af8
JG
542 ret = -1;
543 goto end;
1358c609
JG
544 }
545 }
8ce28af8
JG
546end:
547 return ret;
548}
549
550static
551void worker_sighandler(int sig)
552{
553 const char *signame;
554
555 /*
556 * The worker will its parent's signals since they are part of the same
557 * process group. However, in the case of SIGINT and SIGTERM, we want
558 * to give the worker a chance to teardown gracefully when its parent
559 * closes the command socket.
560 */
561 switch (sig) {
562 case SIGINT:
563 signame = "SIGINT";
564 break;
565 case SIGTERM:
566 signame = "SIGTERM";
567 break;
568 default:
569 signame = "Unknown";
570 }
571
572 DBG("run_as worker received signal %s", signame);
573}
574
575static
576int set_worker_sighandlers(void)
577{
578 int ret = 0;
579 sigset_t sigset;
580 struct sigaction sa;
581
582 if ((ret = sigemptyset(&sigset)) < 0) {
583 PERROR("sigemptyset");
584 goto end;
585 }
586
587 sa.sa_handler = worker_sighandler;
588 sa.sa_mask = sigset;
589 sa.sa_flags = 0;
590 if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
591 PERROR("sigaction SIGINT");
592 goto end;
593 }
594
595 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
596 PERROR("sigaction SIGTERM");
597 goto end;
598 }
599
600 DBG("run_as signal handler set for SIGTERM and SIGINT");
601end:
602 return ret;
1358c609
JG
603}
604
0e904f3e
MD
605LTTNG_HIDDEN
606int run_as_create_worker(char *procname)
607{
608 pid_t pid;
609 int i, ret = 0;
610 ssize_t readlen;
611 struct run_as_ret recvret;
612 struct run_as_worker *worker;
613
9f21bc2c
JG
614 pthread_mutex_lock(&worker_lock);
615 assert(!global_worker);
0e904f3e 616 if (!use_clone()) {
9f21bc2c
JG
617 /*
618 * Don't initialize a worker, all run_as tasks will be performed
619 * in the current process.
620 */
0e904f3e
MD
621 ret = 0;
622 goto end;
623 }
624 worker = zmalloc(sizeof(*worker));
625 if (!worker) {
626 ret = -ENOMEM;
627 goto end;
628 }
629 worker->procname = procname;
630 /* Create unix socket. */
631 if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) {
632 ret = -1;
633 goto error_sock;
634 }
635 /* Fork worker. */
636 pid = fork();
637 if (pid < 0) {
638 PERROR("fork");
639 ret = -1;
640 goto error_fork;
641 } else if (pid == 0) {
642 /* Child */
643
1358c609
JG
644 reset_sighandler();
645
8ce28af8
JG
646 set_worker_sighandlers();
647
9f21bc2c
JG
648 /* The child has no use for this lock. */
649 pthread_mutex_unlock(&worker_lock);
0e904f3e
MD
650 /* Just close, no shutdown. */
651 if (close(worker->sockpair[0])) {
652 PERROR("close");
653 exit(EXIT_FAILURE);
654 }
655 worker->sockpair[0] = -1;
656 ret = run_as_worker(worker);
657 if (lttcomm_close_unix_sock(worker->sockpair[1])) {
658 PERROR("close");
659 ret = -1;
660 }
661 worker->sockpair[1] = -1;
662 exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
663 } else {
664 /* Parent */
665
666 /* Just close, no shutdown. */
667 if (close(worker->sockpair[1])) {
668 PERROR("close");
669 ret = -1;
670 goto error_fork;
671 }
672 worker->sockpair[1] = -1;
673 worker->pid = pid;
674 /* Wait for worker to become ready. */
675 readlen = lttcomm_recv_unix_sock(worker->sockpair[0],
676 &recvret, sizeof(recvret));
677 if (readlen < sizeof(recvret)) {
678 ERR("readlen: %zd", readlen);
679 PERROR("Error reading response from run_as at creation");
680 ret = -1;
681 goto error_fork;
682 }
683 global_worker = worker;
684 }
685end:
9f21bc2c 686 pthread_mutex_unlock(&worker_lock);
0e904f3e
MD
687 return ret;
688
689 /* Error handling. */
690error_fork:
691 for (i = 0; i < 2; i++) {
692 if (worker->sockpair[i] < 0) {
693 continue;
694 }
695 if (lttcomm_close_unix_sock(worker->sockpair[i])) {
696 PERROR("close");
697 }
698 worker->sockpair[i] = -1;
699 }
700error_sock:
701 free(worker);
9f21bc2c 702 pthread_mutex_unlock(&worker_lock);
0e904f3e
MD
703 return ret;
704}
705
706LTTNG_HIDDEN
707void run_as_destroy_worker(void)
708{
709 struct run_as_worker *worker = global_worker;
0e904f3e 710
9f21bc2c 711 pthread_mutex_lock(&worker_lock);
0e904f3e 712 if (!worker) {
9f21bc2c 713 goto end;
0e904f3e
MD
714 }
715 /* Close unix socket */
716 if (lttcomm_close_unix_sock(worker->sockpair[0])) {
717 PERROR("close");
718 }
719 worker->sockpair[0] = -1;
720 /* Wait for worker. */
1358c609
JG
721 for (;;) {
722 int status;
723 pid_t wait_ret;
724
725 wait_ret = waitpid(worker->pid, &status, 0);
726 if (wait_ret < 0) {
727 if (errno == EINTR) {
728 continue;
729 }
730 PERROR("waitpid");
731 break;
732 }
733
734 if (WIFEXITED(status)) {
735 LOG(WEXITSTATUS(status) == 0 ? PRINT_DBG : PRINT_ERR,
736 DEFAULT_RUN_AS_WORKER_NAME " terminated with status code %d",
737 WEXITSTATUS(status));
738 break;
739 } else if (WIFSIGNALED(status)) {
740 ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d",
741 WTERMSIG(status));
742 break;
743 }
0e904f3e
MD
744 }
745 free(worker);
746 global_worker = NULL;
9f21bc2c
JG
747end:
748 pthread_mutex_unlock(&worker_lock);
4628484a 749}
This page took 0.075024 seconds and 4 git commands to generate.