2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
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.
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
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
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.
26 #include <sys/types.h>
35 #include <common/lttng-kernel.h>
36 #include <common/common.h>
37 #include <common/utils.h>
38 #include <common/compat/getenv.h>
39 #include <common/compat/prctl.h>
40 #include <common/unix.h>
41 #include <common/defaults.h>
42 #include <common/lttng-elf.h>
44 #include <lttng/constant.h>
50 typedef int (*run_as_fct
)(struct run_as_data
*data
, struct run_as_ret
*ret_value
);
52 struct run_as_mkdir_data
{
57 struct run_as_open_data
{
63 struct run_as_unlink_data
{
67 struct run_as_rmdir_recursive_data
{
71 struct run_as_extract_elf_symbol_offset_data
{
72 char function
[LTTNG_SYMBOL_NAME_LEN
];
75 struct run_as_extract_sdt_probe_offsets_data
{
76 char probe_name
[LTTNG_SYMBOL_NAME_LEN
];
77 char provider_name
[LTTNG_SYMBOL_NAME_LEN
];
80 struct run_as_mkdir_ret
{
84 struct run_as_open_ret
{
88 struct run_as_unlink_ret
{
92 struct run_as_rmdir_recursive_ret
{
96 struct run_as_extract_elf_symbol_offset_ret
{
100 struct run_as_extract_sdt_probe_offsets_ret
{
102 uint64_t offsets
[LTTNG_KERNEL_MAX_UPROBE_NUM
];
109 RUN_AS_RMDIR_RECURSIVE
,
110 RUN_AS_MKDIR_RECURSIVE
,
111 RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
,
112 RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
,
119 struct run_as_mkdir_data mkdir
;
120 struct run_as_open_data open
;
121 struct run_as_unlink_data unlink
;
122 struct run_as_rmdir_recursive_data rmdir_recursive
;
123 struct run_as_extract_elf_symbol_offset_data extract_elf_symbol_offset
;
124 struct run_as_extract_sdt_probe_offsets_data extract_sdt_probe_offsets
;
131 * The run_as_ret structure holds the returned value and status of the command.
133 * The `u` union field holds the return value of the command; in most cases it
134 * represents the success or the failure of the command. In more complex
135 * commands, it holds a computed value.
137 * The _errno field is the errno recorded after the execution of the command.
139 * The _error fields is used the signify that return status of the command. For
140 * simple commands returning `int` the _error field will be the same as the
141 * ret_int field. In complex commands, it signify the success or failure of the
148 struct run_as_mkdir_ret mkdir
;
149 struct run_as_open_ret open
;
150 struct run_as_unlink_ret unlink
;
151 struct run_as_rmdir_recursive_ret rmdir_recursive
;
152 struct run_as_extract_elf_symbol_offset_ret extract_elf_symbol_offset
;
153 struct run_as_extract_sdt_probe_offsets_ret extract_sdt_probe_offsets
;
159 struct run_as_worker
{
160 pid_t pid
; /* Worker PID. */
165 /* Single global worker per process (for now). */
166 static struct run_as_worker
*global_worker
;
167 /* Lock protecting the worker. */
168 static pthread_mutex_t worker_lock
= PTHREAD_MUTEX_INITIALIZER
;
180 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
185 int _utils_mkdir_recursive_unsafe(const char *path
, mode_t mode
);
188 * Create recursively directory using the FULL path.
191 int _mkdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
196 path
= data
->u
.mkdir
.path
;
197 mode
= data
->u
.mkdir
.mode
;
199 /* Safe to call as we have transitioned to the requested uid/gid. */
200 ret_value
->u
.mkdir
.ret
= _utils_mkdir_recursive_unsafe(path
, mode
);
201 ret_value
->_errno
= errno
;
202 ret_value
->_error
= (ret_value
->u
.mkdir
.ret
) ? true : false;
203 return ret_value
->u
.mkdir
.ret
;
207 int _mkdir(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
209 ret_value
->u
.mkdir
.ret
= mkdir(data
->u
.mkdir
.path
, data
->u
.mkdir
.mode
);
210 ret_value
->_errno
= errno
;
211 ret_value
->_error
= (ret_value
->u
.mkdir
.ret
) ? true : false;
212 return ret_value
->u
.mkdir
.ret
;
216 int _open(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
218 ret_value
->u
.open
.ret
= open(data
->u
.open
.path
, data
->u
.open
.flags
, data
->u
.open
.mode
);
219 ret_value
->fd
= ret_value
->u
.open
.ret
;
220 ret_value
->_errno
= errno
;
221 ret_value
->_error
= (ret_value
->u
.open
.ret
) ? true : false;
222 return ret_value
->u
.open
.ret
;
226 int _unlink(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
228 ret_value
->u
.unlink
.ret
= unlink(data
->u
.unlink
.path
);
229 ret_value
->_errno
= errno
;
230 ret_value
->_error
= (ret_value
->u
.unlink
.ret
) ? true : false;
231 return ret_value
->u
.unlink
.ret
;
235 int _rmdir_recursive(struct run_as_data
*data
, struct run_as_ret
*ret_value
)
237 ret_value
->u
.rmdir_recursive
.ret
= utils_recursive_rmdir(data
->u
.rmdir_recursive
.path
);
238 ret_value
->_errno
= errno
;
239 ret_value
->_error
= (ret_value
->u
.rmdir_recursive
.ret
) ? true : false;
240 return ret_value
->u
.rmdir_recursive
.ret
;
244 int _extract_elf_symbol_offset(struct run_as_data
*data
,
245 struct run_as_ret
*ret_value
)
248 ret_value
->_error
= false;
250 ret
= lttng_elf_get_symbol_offset(data
->fd
,
251 data
->u
.extract_elf_symbol_offset
.function
,
252 &ret_value
->u
.extract_elf_symbol_offset
.offset
);
254 DBG("Failed to extract ELF function offset");
255 ret_value
->_error
= true;
262 int _extract_sdt_probe_offsets(struct run_as_data
*data
,
263 struct run_as_ret
*ret_value
)
266 uint64_t *offsets
= NULL
;
269 ret_value
->_error
= false;
271 /* On success, this call allocates the offsets paramater. */
272 ret
= lttng_elf_get_sdt_probe_offsets(data
->fd
,
273 data
->u
.extract_sdt_probe_offsets
.provider_name
,
274 data
->u
.extract_sdt_probe_offsets
.probe_name
,
275 &offsets
, &num_offset
);
278 DBG("Failed to extract SDT probe offsets");
279 ret_value
->_error
= true;
283 if (num_offset
<= 0 || num_offset
> LTTNG_KERNEL_MAX_UPROBE_NUM
) {
284 DBG("Wrong number of probes.");
286 ret_value
->_error
= true;
290 /* Copy the content of the offsets array to the ret struct. */
291 memcpy(ret_value
->u
.extract_sdt_probe_offsets
.offsets
,
292 offsets
, num_offset
* sizeof(uint64_t));
294 ret_value
->u
.extract_sdt_probe_offsets
.num_offset
= num_offset
;
303 run_as_fct
run_as_enum_to_fct(enum run_as_cmd cmd
)
312 case RUN_AS_RMDIR_RECURSIVE
:
313 return _rmdir_recursive
;
314 case RUN_AS_MKDIR_RECURSIVE
:
315 return _mkdir_recursive
;
316 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
317 return _extract_elf_symbol_offset
;
318 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
319 return _extract_sdt_probe_offsets
;
321 ERR("Unknown command %d", (int) cmd
);
327 int do_send_fd(int sock
, int fd
)
332 ERR("Invalid file description");
336 len
= lttcomm_send_fds_unix_sock(sock
, &fd
, 1);
338 PERROR("lttcomm_send_fds_unix_sock");
345 int do_recv_fd(int sock
, int *fd
)
350 ERR("Invalid file description");
354 len
= lttcomm_recv_fds_unix_sock(sock
, fd
, 1);
358 } else if (len
< 0) {
359 PERROR("lttcomm_recv_fds_unix_sock");
366 int send_fd_to_worker(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int fd
)
371 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
372 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
378 ret
= do_send_fd(worker
->sockpair
[0], fd
);
380 PERROR("do_send_fd");
388 int send_fd_to_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int fd
)
390 int ret
= 0, ret_close
= 0;
399 ret
= do_send_fd(worker
->sockpair
[1], fd
);
401 PERROR("do_send_fd error");
408 ret_close
= close(fd
);
417 int recv_fd_from_worker(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int *fd
)
428 ret
= do_recv_fd(worker
->sockpair
[0], fd
);
430 PERROR("do_recv_fd error");
438 int recv_fd_from_master(struct run_as_worker
*worker
, enum run_as_cmd cmd
, int *fd
)
443 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
444 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
450 ret
= do_recv_fd(worker
->sockpair
[1], fd
);
452 PERROR("do_recv_fd error");
460 int cleanup_received_fd(enum run_as_cmd cmd
, int fd
)
465 case RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
:
466 case RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
:
477 PERROR("close error");
485 * Return < 0 on error, 0 if OK, 1 on hangup.
488 int handle_one_cmd(struct run_as_worker
*worker
)
491 struct run_as_data data
;
492 ssize_t readlen
, writelen
;
493 struct run_as_ret sendret
;
497 memset(&sendret
, 0, sizeof(sendret
));
501 * Stage 1: Receive run_as_data struct from the master.
502 * The structure contains the command type and all the parameters needed for
505 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[1], &data
,
512 if (readlen
< sizeof(data
)) {
513 PERROR("lttcomm_recv_unix_sock error");
518 cmd
= run_as_enum_to_fct(data
.cmd
);
525 * Stage 2: Receive file descriptor from master.
526 * Some commands need a file descriptor as input so if it's needed we
527 * receive the fd using the Unix socket.
529 ret
= recv_fd_from_master(worker
, data
.cmd
, &data
.fd
);
531 PERROR("recv_fd_from_master error");
536 prev_euid
= getuid();
537 if (data
.gid
!= getegid()) {
538 ret
= setegid(data
.gid
);
540 sendret
._error
= true;
541 sendret
._errno
= errno
;
546 if (data
.uid
!= prev_euid
) {
547 ret
= seteuid(data
.uid
);
549 sendret
._error
= true;
550 sendret
._errno
= errno
;
557 * Also set umask to 0 for mkdir executable bit.
562 * Stage 3: Execute the command
564 ret
= (*cmd
)(&data
, &sendret
);
566 DBG("Execution of command returned an error");
570 ret
= cleanup_received_fd(data
.cmd
, data
.fd
);
572 ERR("Error cleaning up FD");
577 * Stage 4: Send run_as_ret structure to the master.
578 * This structure contain the return value of the command and the errno.
580 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
582 if (writelen
< sizeof(sendret
)) {
583 PERROR("lttcomm_send_unix_sock error");
589 * Stage 5: Send file descriptor to the master
590 * Some commands return a file descriptor so if it's needed we pass it back
591 * to the master using the Unix socket.
593 ret
= send_fd_to_master(worker
, data
.cmd
, sendret
.fd
);
595 DBG("Sending FD to master returned an error");
599 if (seteuid(prev_euid
) < 0) {
610 int run_as_worker(struct run_as_worker
*worker
)
614 struct run_as_ret sendret
;
615 size_t proc_orig_len
;
618 * Initialize worker. Set a different process cmdline.
620 proc_orig_len
= strlen(worker
->procname
);
621 memset(worker
->procname
, 0, proc_orig_len
);
622 strncpy(worker
->procname
, DEFAULT_RUN_AS_WORKER_NAME
, proc_orig_len
);
624 ret
= lttng_prctl(PR_SET_NAME
,
625 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME
, 0, 0, 0);
626 if (ret
&& ret
!= -ENOSYS
) {
627 /* Don't fail as this is not essential. */
628 PERROR("prctl PR_SET_NAME");
631 memset(&sendret
, 0, sizeof(sendret
));
633 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[1], &sendret
,
635 if (writelen
< sizeof(sendret
)) {
636 PERROR("lttcomm_send_unix_sock error");
642 ret
= handle_one_cmd(worker
);
646 } else if (ret
> 0) {
649 continue; /* Next command. */
658 int run_as_cmd(struct run_as_worker
*worker
,
660 struct run_as_data
*data
,
661 struct run_as_ret
*ret_value
,
662 uid_t uid
, gid_t gid
)
665 ssize_t readlen
, writelen
;
668 * If we are non-root, we can only deal with our own uid.
670 if (geteuid() != 0) {
671 if (uid
!= geteuid()) {
673 ret_value
->_errno
= EPERM
;
674 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
675 (int) uid
, (int) geteuid());
685 * Stage 1: Send the run_as_data struct to the worker process
687 writelen
= lttcomm_send_unix_sock(worker
->sockpair
[0], data
,
689 if (writelen
< sizeof(*data
)) {
690 PERROR("Error writing message to run_as");
692 ret_value
->_errno
= EIO
;
697 * Stage 2: Send file descriptor to the worker process if needed
699 ret
= send_fd_to_worker(worker
, data
->cmd
, data
->fd
);
701 PERROR("do_send_fd error");
703 ret_value
->_errno
= EIO
;
708 * Stage 3: Wait for the execution of the command
712 * Stage 4: Receive the run_as_ret struct containing the return value and
715 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0], ret_value
,
718 ERR("Run-as worker has hung-up during run_as_cmd");
720 ret_value
->_errno
= EIO
;
722 } else if (readlen
< sizeof(*ret_value
)) {
723 PERROR("Error reading response from run_as");
725 ret_value
->_errno
= errno
;
730 * Stage 5: Receive file descriptor if needed
732 ret
= recv_fd_from_worker(worker
, data
->cmd
, &ret_value
->fd
);
734 ERR("Error receiving fd");
736 ret_value
->_errno
= EIO
;
744 * This is for debugging ONLY and should not be considered secure.
747 int run_as_noworker(enum run_as_cmd cmd
,
748 struct run_as_data
*data
, struct run_as_ret
*ret_value
,
749 uid_t uid
, gid_t gid
)
751 int ret
, saved_errno
;
755 fct
= run_as_enum_to_fct(cmd
);
762 ret
= fct(data
, ret_value
);
763 saved_errno
= ret_value
->_errno
;
771 int run_as_restart_worker(struct run_as_worker
*worker
)
774 char *procname
= NULL
;
776 procname
= worker
->procname
;
778 /* Close socket to run_as worker process and clean up the zombie process */
779 run_as_destroy_worker();
781 /* Create a new run_as worker process*/
782 ret
= run_as_create_worker(procname
);
784 ERR("Restarting the worker process failed");
793 int run_as(enum run_as_cmd cmd
, struct run_as_data
*data
,
794 struct run_as_ret
*ret_value
, uid_t uid
, gid_t gid
)
796 int ret
, saved_errno
;
799 DBG("Using run_as worker");
800 pthread_mutex_lock(&worker_lock
);
801 assert(global_worker
);
803 ret
= run_as_cmd(global_worker
, cmd
, data
, ret_value
, uid
, gid
);
804 saved_errno
= ret_value
->_errno
;
806 pthread_mutex_unlock(&worker_lock
);
808 * If the worker thread crashed the errno is set to EIO. we log
809 * the error and start a new worker process.
811 if (ret
== -1 && saved_errno
== EIO
) {
812 DBG("Socket closed unexpectedly... "
813 "Restarting the worker process");
814 ret
= run_as_restart_worker(global_worker
);
817 ERR("Failed to restart worker process.");
822 DBG("Using run_as without worker");
823 ret
= run_as_noworker(cmd
, data
, ret_value
, uid
, gid
);
830 int run_as_mkdir_recursive(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
832 struct run_as_data data
;
833 struct run_as_ret ret
;
835 memset(&data
, 0, sizeof(data
));
836 memset(&ret
, 0, sizeof(ret
));
837 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
838 path
, (int) mode
, (int) uid
, (int) gid
);
839 strncpy(data
.u
.mkdir
.path
, path
, PATH_MAX
- 1);
840 data
.u
.mkdir
.path
[PATH_MAX
- 1] = '\0';
841 data
.u
.mkdir
.mode
= mode
;
843 run_as(RUN_AS_MKDIR_RECURSIVE
, &data
, &ret
, uid
, gid
);
845 return ret
.u
.mkdir
.ret
;
849 int run_as_mkdir(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
851 struct run_as_data data
;
852 struct run_as_ret ret
;
854 memset(&data
, 0, sizeof(data
));
855 memset(&ret
, 0, sizeof(ret
));
857 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
858 path
, (int) mode
, (int) uid
, (int) gid
);
859 strncpy(data
.u
.mkdir
.path
, path
, PATH_MAX
- 1);
860 data
.u
.mkdir
.path
[PATH_MAX
- 1] = '\0';
861 data
.u
.mkdir
.mode
= mode
;
862 run_as(RUN_AS_MKDIR
, &data
, &ret
, uid
, gid
);
864 return ret
.u
.mkdir
.ret
;
868 int run_as_open(const char *path
, int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
870 struct run_as_data data
;
871 struct run_as_ret ret
;
873 memset(&data
, 0, sizeof(data
));
874 memset(&ret
, 0, sizeof(ret
));
876 DBG3("open() %s with flags %X mode %d for uid %d and gid %d",
877 path
, flags
, (int) mode
, (int) uid
, (int) gid
);
878 strncpy(data
.u
.open
.path
, path
, PATH_MAX
- 1);
879 data
.u
.open
.path
[PATH_MAX
- 1] = '\0';
880 data
.u
.open
.flags
= flags
;
881 data
.u
.open
.mode
= mode
;
882 run_as(RUN_AS_OPEN
, &data
, &ret
, uid
, gid
);
884 ret
.u
.open
.ret
= ret
.fd
;
885 return ret
.u
.open
.ret
;
889 int run_as_unlink(const char *path
, uid_t uid
, gid_t gid
)
891 struct run_as_data data
;
892 struct run_as_ret ret
;
894 memset(&data
, 0, sizeof(data
));
895 memset(&ret
, 0, sizeof(ret
));
897 DBG3("unlink() %s with for uid %d and gid %d",
898 path
, (int) uid
, (int) gid
);
899 strncpy(data
.u
.unlink
.path
, path
, PATH_MAX
- 1);
900 data
.u
.unlink
.path
[PATH_MAX
- 1] = '\0';
901 run_as(RUN_AS_UNLINK
, &data
, &ret
, uid
, gid
);
903 return ret
.u
.unlink
.ret
;
907 int run_as_rmdir_recursive(const char *path
, uid_t uid
, gid_t gid
)
909 struct run_as_data data
;
910 struct run_as_ret ret
;
912 memset(&data
, 0, sizeof(data
));
913 memset(&ret
, 0, sizeof(ret
));
915 DBG3("rmdir_recursive() %s with for uid %d and gid %d",
916 path
, (int) uid
, (int) gid
);
917 strncpy(data
.u
.rmdir_recursive
.path
, path
, PATH_MAX
- 1);
918 data
.u
.rmdir_recursive
.path
[PATH_MAX
- 1] = '\0';
919 run_as(RUN_AS_RMDIR_RECURSIVE
, &data
, &ret
, uid
, gid
);
921 return ret
.u
.rmdir_recursive
.ret
;
925 int run_as_extract_elf_symbol_offset(int fd
, const char* function
,
926 uid_t uid
, gid_t gid
, uint64_t *offset
)
928 struct run_as_data data
;
929 struct run_as_ret ret
;
931 memset(&data
, 0, sizeof(data
));
932 memset(&ret
, 0, sizeof(ret
));
934 DBG3("extract_elf_symbol_offset() on fd=%d and function=%s "
935 "with for uid %d and gid %d", fd
, function
, (int) uid
, (int) gid
);
939 strncpy(data
.u
.extract_elf_symbol_offset
.function
, function
, LTTNG_SYMBOL_NAME_LEN
- 1);
941 data
.u
.extract_elf_symbol_offset
.function
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
943 run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET
, &data
, &ret
, uid
, gid
);
951 *offset
= ret
.u
.extract_elf_symbol_offset
.offset
;
956 int run_as_extract_sdt_probe_offsets(int fd
, const char* provider_name
,
957 const char* probe_name
, uid_t uid
, gid_t gid
,
958 uint64_t **offsets
, uint32_t *num_offset
)
960 struct run_as_data data
;
961 struct run_as_ret ret
;
963 memset(&data
, 0, sizeof(data
));
964 memset(&ret
, 0, sizeof(ret
));
966 DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and "
967 "provider_name=%s with for uid %d and gid %d", fd
, probe_name
,
968 provider_name
, (int) uid
, (int) gid
);
972 strncpy(data
.u
.extract_sdt_probe_offsets
.probe_name
, probe_name
, LTTNG_SYMBOL_NAME_LEN
- 1);
973 strncpy(data
.u
.extract_sdt_probe_offsets
.provider_name
, provider_name
, LTTNG_SYMBOL_NAME_LEN
- 1);
975 data
.u
.extract_sdt_probe_offsets
.probe_name
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
976 data
.u
.extract_sdt_probe_offsets
.provider_name
[LTTNG_SYMBOL_NAME_LEN
- 1] = '\0';
978 run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS
, &data
, &ret
, uid
, gid
);
986 *num_offset
= ret
.u
.extract_sdt_probe_offsets
.num_offset
;
988 *offsets
= zmalloc(*num_offset
* sizeof(uint64_t));
993 memcpy(*offsets
, ret
.u
.extract_sdt_probe_offsets
.offsets
, *num_offset
* sizeof(uint64_t));
998 int reset_sighandler(void)
1002 DBG("Resetting run_as worker signal handlers to default");
1003 for (sig
= 1; sig
<= 31; sig
++) {
1004 (void) signal(sig
, SIG_DFL
);
1010 void worker_sighandler(int sig
)
1012 const char *signame
;
1015 * The worker will inherit its parent's signals since they are part of
1016 * the same process group. However, in the case of SIGINT and SIGTERM,
1017 * we want to give the worker a chance to teardown gracefully when its
1018 * parent closes the command socket.
1025 signame
= "SIGTERM";
1032 DBG("run_as worker received signal %s", signame
);
1034 DBG("run_as_worker received signal %d", sig
);
1039 int set_worker_sighandlers(void)
1043 struct sigaction sa
;
1045 if ((ret
= sigemptyset(&sigset
)) < 0) {
1046 PERROR("sigemptyset");
1050 sa
.sa_handler
= worker_sighandler
;
1051 sa
.sa_mask
= sigset
;
1053 if ((ret
= sigaction(SIGINT
, &sa
, NULL
)) < 0) {
1054 PERROR("sigaction SIGINT");
1058 if ((ret
= sigaction(SIGTERM
, &sa
, NULL
)) < 0) {
1059 PERROR("sigaction SIGTERM");
1063 DBG("run_as signal handler set for SIGTERM and SIGINT");
1069 int run_as_create_worker(char *procname
)
1074 struct run_as_ret recvret
;
1075 struct run_as_worker
*worker
;
1077 pthread_mutex_lock(&worker_lock
);
1078 assert(!global_worker
);
1081 * Don't initialize a worker, all run_as tasks will be performed
1082 * in the current process.
1087 worker
= zmalloc(sizeof(*worker
));
1092 worker
->procname
= procname
;
1093 /* Create unix socket. */
1094 if (lttcomm_create_anon_unix_socketpair(worker
->sockpair
) < 0) {
1105 } else if (pid
== 0) {
1110 set_worker_sighandlers();
1112 /* The child has no use for this lock. */
1113 pthread_mutex_unlock(&worker_lock
);
1114 /* Just close, no shutdown. */
1115 if (close(worker
->sockpair
[0])) {
1121 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
1122 * Sockpair[1] is used as a control channel with the master
1124 for (i
= 3; i
< sysconf(_SC_OPEN_MAX
); i
++) {
1125 if (i
!= worker
->sockpair
[1]) {
1130 worker
->sockpair
[0] = -1;
1131 ret
= run_as_worker(worker
);
1132 if (lttcomm_close_unix_sock(worker
->sockpair
[1])) {
1136 worker
->sockpair
[1] = -1;
1137 LOG(ret
? PRINT_ERR
: PRINT_DBG
, "run_as worker exiting (ret = %d)", ret
);
1138 exit(ret
? EXIT_FAILURE
: EXIT_SUCCESS
);
1142 /* Just close, no shutdown. */
1143 if (close(worker
->sockpair
[1])) {
1148 worker
->sockpair
[1] = -1;
1150 /* Wait for worker to become ready. */
1151 readlen
= lttcomm_recv_unix_sock(worker
->sockpair
[0],
1152 &recvret
, sizeof(recvret
));
1153 if (readlen
< sizeof(recvret
)) {
1154 ERR("readlen: %zd", readlen
);
1155 PERROR("Error reading response from run_as at creation");
1159 global_worker
= worker
;
1162 pthread_mutex_unlock(&worker_lock
);
1165 /* Error handling. */
1167 for (i
= 0; i
< 2; i
++) {
1168 if (worker
->sockpair
[i
] < 0) {
1171 if (lttcomm_close_unix_sock(worker
->sockpair
[i
])) {
1174 worker
->sockpair
[i
] = -1;
1178 pthread_mutex_unlock(&worker_lock
);
1183 void run_as_destroy_worker(void)
1185 struct run_as_worker
*worker
= global_worker
;
1187 DBG("Destroying run_as worker");
1188 pthread_mutex_lock(&worker_lock
);
1192 /* Close unix socket */
1193 DBG("Closing run_as worker socket");
1194 if (lttcomm_close_unix_sock(worker
->sockpair
[0])) {
1197 worker
->sockpair
[0] = -1;
1198 /* Wait for worker. */
1203 wait_ret
= waitpid(worker
->pid
, &status
, 0);
1205 if (errno
== EINTR
) {
1212 if (WIFEXITED(status
)) {
1213 LOG(WEXITSTATUS(status
) == 0 ? PRINT_DBG
: PRINT_ERR
,
1214 DEFAULT_RUN_AS_WORKER_NAME
" terminated with status code %d",
1215 WEXITSTATUS(status
));
1217 } else if (WIFSIGNALED(status
)) {
1218 ERR(DEFAULT_RUN_AS_WORKER_NAME
" was killed by signal %d",
1224 global_worker
= NULL
;
1226 pthread_mutex_unlock(&worker_lock
);