123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- /* $OpenBSD$ */
- /*
- * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
- * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <sys/types.h>
- #include <sys/file.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/un.h>
- #include <sys/wait.h>
- #include <errno.h>
- #include <event.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include "tmux.h"
- struct tmuxproc *client_proc;
- struct tmuxpeer *client_peer;
- int client_flags;
- struct event client_stdin;
- enum {
- CLIENT_EXIT_NONE,
- CLIENT_EXIT_DETACHED,
- CLIENT_EXIT_DETACHED_HUP,
- CLIENT_EXIT_LOST_TTY,
- CLIENT_EXIT_TERMINATED,
- CLIENT_EXIT_LOST_SERVER,
- CLIENT_EXIT_EXITED,
- CLIENT_EXIT_SERVER_EXITED,
- } client_exitreason = CLIENT_EXIT_NONE;
- int client_exitval;
- enum msgtype client_exittype;
- const char *client_exitsession;
- int client_attached;
- __dead void client_exec(const char *,const char *);
- int client_get_lock(char *);
- int client_connect(struct event_base *, const char *, int);
- void client_send_identify(const char *, const char *);
- void client_stdin_callback(int, short, void *);
- void client_write(int, const char *, size_t);
- void client_signal(int);
- void client_dispatch(struct imsg *, void *);
- void client_dispatch_attached(struct imsg *);
- void client_dispatch_wait(struct imsg *, const char *);
- const char *client_exit_message(void);
- /*
- * Get server create lock. If already held then server start is happening in
- * another client, so block until the lock is released and return -2 to
- * retry. Return -1 on failure to continue and start the server anyway.
- */
- int
- client_get_lock(char *lockfile)
- {
- int lockfd;
- log_debug("lock file is %s", lockfile);
- if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1) {
- log_debug("open failed: %s", strerror(errno));
- return (-1);
- }
- if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
- log_debug("flock failed: %s", strerror(errno));
- if (errno != EAGAIN)
- return (lockfd);
- while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
- /* nothing */;
- close(lockfd);
- return (-2);
- }
- log_debug("flock succeeded");
- return (lockfd);
- }
- /* Connect client to server. */
- int
- client_connect(struct event_base *base, const char *path, int start_server)
- {
- struct sockaddr_un sa;
- size_t size;
- int fd, lockfd = -1, locked = 0;
- char *lockfile = NULL;
- memset(&sa, 0, sizeof sa);
- sa.sun_family = AF_UNIX;
- size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
- if (size >= sizeof sa.sun_path) {
- errno = ENAMETOOLONG;
- return (-1);
- }
- log_debug("socket is %s", path);
- retry:
- if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
- return (-1);
- log_debug("trying connect");
- if (connect(fd, (struct sockaddr *)&sa, sizeof sa) == -1) {
- log_debug("connect failed: %s", strerror(errno));
- if (errno != ECONNREFUSED && errno != ENOENT)
- goto failed;
- if (!start_server)
- goto failed;
- close(fd);
- if (!locked) {
- xasprintf(&lockfile, "%s.lock", path);
- if ((lockfd = client_get_lock(lockfile)) < 0) {
- log_debug("didn't get lock (%d)", lockfd);
- free(lockfile);
- lockfile = NULL;
- if (lockfd == -2)
- goto retry;
- }
- log_debug("got lock (%d)", lockfd);
- /*
- * Always retry at least once, even if we got the lock,
- * because another client could have taken the lock,
- * started the server and released the lock between our
- * connect() and flock().
- */
- locked = 1;
- goto retry;
- }
- if (lockfd >= 0 && unlink(path) != 0 && errno != ENOENT) {
- free(lockfile);
- close(lockfd);
- return (-1);
- }
- fd = server_start(base, lockfd, lockfile);
- }
- if (locked && lockfd >= 0) {
- free(lockfile);
- close(lockfd);
- }
- setblocking(fd, 0);
- return (fd);
- failed:
- if (locked) {
- free(lockfile);
- close(lockfd);
- }
- close(fd);
- return (-1);
- }
- /* Get exit string from reason number. */
- const char *
- client_exit_message(void)
- {
- static char msg[256];
- switch (client_exitreason) {
- case CLIENT_EXIT_NONE:
- break;
- case CLIENT_EXIT_DETACHED:
- if (client_exitsession != NULL) {
- xsnprintf(msg, sizeof msg, "detached "
- "(from session %s)", client_exitsession);
- return (msg);
- }
- return ("detached");
- case CLIENT_EXIT_DETACHED_HUP:
- if (client_exitsession != NULL) {
- xsnprintf(msg, sizeof msg, "detached and SIGHUP "
- "(from session %s)", client_exitsession);
- return (msg);
- }
- return ("detached and SIGHUP");
- case CLIENT_EXIT_LOST_TTY:
- return ("lost tty");
- case CLIENT_EXIT_TERMINATED:
- return ("terminated");
- case CLIENT_EXIT_LOST_SERVER:
- return ("lost server");
- case CLIENT_EXIT_EXITED:
- return ("exited");
- case CLIENT_EXIT_SERVER_EXITED:
- return ("server exited");
- }
- return ("unknown reason");
- }
- #ifdef TMATE
- extern const struct cmd_entry cmd_attach_session_entry;
- extern const struct cmd_entry cmd_new_session_entry;
- #endif
- /* Client main loop. */
- int
- client_main(struct event_base *base, int argc, char **argv, int flags,
- const char *shellcmd)
- {
- struct cmd *cmd;
- struct cmd_list *cmdlist;
- struct msg_command_data *data;
- int cmdflags, fd, i;
- const char *ttynam, *cwd;
- pid_t ppid;
- enum msgtype msg;
- char *cause, path[PATH_MAX];
- struct termios tio, saved_tio;
- size_t size;
- #ifdef TMATE
- int cant_nest = 0;
- #endif
- /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
- signal(SIGCHLD, SIG_IGN);
- /* Save the flags. */
- client_flags = flags;
- /* Set up the initial command. */
- cmdflags = 0;
- if (shellcmd != NULL) {
- msg = MSG_SHELL;
- cmdflags = CMD_STARTSERVER;
- } else if (argc == 0) {
- msg = MSG_COMMAND;
- cmdflags = CMD_STARTSERVER;
- #ifdef TMATE
- cant_nest = 1;
- #endif
- } else {
- msg = MSG_COMMAND;
- /*
- * It sucks parsing the command string twice (in client and
- * later in server) but it is necessary to get the start server
- * flag.
- */
- cmdlist = cmd_list_parse(argc, argv, NULL, 0, &cause);
- if (cmdlist == NULL) {
- fprintf(stderr, "%s\n", cause);
- return (1);
- }
- cmdflags &= ~CMD_STARTSERVER;
- TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
- if (cmd->entry->flags & CMD_STARTSERVER)
- cmdflags |= CMD_STARTSERVER;
- #ifdef TMATE
- if (cmd->entry == &cmd_attach_session_entry ||
- cmd->entry == &cmd_new_session_entry)
- cant_nest = 1;
- #endif
- }
- cmd_list_free(cmdlist);
- }
- #ifdef TMATE
- if (cant_nest && getenv("TMUX")) {
- fprintf(stderr, "sessions should be nested with care, "
- "unset $TMUX to force\n");
- return (1);
- }
- #endif
- /* Create client process structure (starts logging). */
- client_proc = proc_start("client", base, 0, client_signal);
- /* Initialize the client socket and start the server. */
- fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
- if (fd == -1) {
- if (errno == ECONNREFUSED) {
- fprintf(stderr, "no server running on %s\n",
- socket_path);
- } else {
- #ifdef TMATE
- if (errno == ENOENT)
- fprintf(stderr, "You must specify a socket name with -S. For example: \n"
- " tmate -S /tmp/tmate.sock new-session -d\n"
- " tmate -S /tmp/tmate.sock wait tmate-ready\n");
- else
- #endif
- fprintf(stderr, "error connecting to %s (%s)\n",
- socket_path, strerror(errno));
- }
- return (1);
- }
- client_peer = proc_add_peer(client_proc, fd, client_dispatch,
- (void *)shellcmd);
- /* Save these before pledge(). */
- if ((cwd = getcwd(path, sizeof path)) == NULL) {
- if ((cwd = find_home()) == NULL)
- cwd = "/";
- }
- if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
- ttynam = "";
- #ifdef __OpenBSD__
- /*
- * Drop privileges for client. "proc exec" is needed for -c and for
- * locking (which uses system(3)).
- *
- * "tty" is needed to restore termios(4) and also for some reason -CC
- * does not work properly without it (input is not recognised).
- *
- * "sendfd" is dropped later in client_dispatch_wait().
- */
- if (pledge("stdio unix sendfd proc exec tty", NULL) != 0)
- fatal("pledge failed");
- #endif
- /* Free stuff that is not used in the client. */
- options_free(global_options);
- options_free(global_s_options);
- options_free(global_w_options);
- environ_free(global_environ);
- /* Create stdin handler. */
- setblocking(STDIN_FILENO, 0);
- event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
- client_stdin_callback, NULL);
- if (client_flags & CLIENT_CONTROLCONTROL) {
- if (tcgetattr(STDIN_FILENO, &saved_tio) != 0)
- fatal("tcgetattr failed");
- cfmakeraw(&tio);
- tio.c_iflag = ICRNL|IXANY;
- tio.c_oflag = OPOST|ONLCR;
- #ifdef NOKERNINFO
- tio.c_lflag = NOKERNINFO;
- #endif
- tio.c_cflag = CREAD|CS8|HUPCL;
- tio.c_cc[VMIN] = 1;
- tio.c_cc[VTIME] = 0;
- cfsetispeed(&tio, cfgetispeed(&saved_tio));
- cfsetospeed(&tio, cfgetospeed(&saved_tio));
- tcsetattr(STDIN_FILENO, TCSANOW, &tio);
- }
- /* Send identify messages. */
- client_send_identify(ttynam, cwd);
- /* Send first command. */
- if (msg == MSG_COMMAND) {
- /* How big is the command? */
- size = 0;
- for (i = 0; i < argc; i++)
- size += strlen(argv[i]) + 1;
- data = xmalloc((sizeof *data) + size);
- /* Prepare command for server. */
- data->argc = argc;
- if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) {
- fprintf(stderr, "command too long\n");
- free(data);
- return (1);
- }
- size += sizeof *data;
- /* Send the command. */
- if (proc_send(client_peer, msg, -1, data, size) != 0) {
- fprintf(stderr, "failed to send command\n");
- free(data);
- return (1);
- }
- free(data);
- } else if (msg == MSG_SHELL)
- proc_send(client_peer, msg, -1, NULL, 0);
- /* Start main loop. */
- proc_loop(client_proc, NULL);
- /* Print the exit message, if any, and exit. */
- if (client_attached) {
- if (client_exitreason != CLIENT_EXIT_NONE)
- printf("[%s]\n", client_exit_message());
- ppid = getppid();
- if (client_exittype == MSG_DETACHKILL && ppid > 1)
- kill(ppid, SIGHUP);
- } else if (client_flags & CLIENT_CONTROLCONTROL) {
- if (client_exitreason != CLIENT_EXIT_NONE)
- printf("%%exit %s\n", client_exit_message());
- else
- printf("%%exit\n");
- printf("\033\\");
- tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
- } else if (client_exitreason != CLIENT_EXIT_NONE)
- fprintf(stderr, "%s\n", client_exit_message());
- setblocking(STDIN_FILENO, 1);
- return (client_exitval);
- }
- /* Send identify messages to server. */
- void
- client_send_identify(const char *ttynam, const char *cwd)
- {
- const char *s;
- char **ss;
- size_t sslen;
- int fd, flags = client_flags;
- pid_t pid;
- proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
- if ((s = getenv("TERM")) == NULL)
- s = "";
- proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
- proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
- strlen(ttynam) + 1);
- proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
- if ((fd = dup(STDIN_FILENO)) == -1)
- fatal("dup failed");
- proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
- pid = getpid();
- proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
- for (ss = environ; *ss != NULL; ss++) {
- sslen = strlen(*ss) + 1;
- if (sslen > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
- continue;
- proc_send(client_peer, MSG_IDENTIFY_ENVIRON, -1, *ss, sslen);
- }
- proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
- }
- /* Callback for client stdin read events. */
- void
- client_stdin_callback(__unused int fd, __unused short events,
- __unused void *arg)
- {
- struct msg_stdin_data data;
- data.size = read(STDIN_FILENO, data.data, sizeof data.data);
- if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
- return;
- proc_send(client_peer, MSG_STDIN, -1, &data, sizeof data);
- if (data.size <= 0)
- event_del(&client_stdin);
- }
- /* Force write to file descriptor. */
- void
- client_write(int fd, const char *data, size_t size)
- {
- ssize_t used;
- while (size != 0) {
- used = write(fd, data, size);
- if (used == -1) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- break;
- }
- data += used;
- size -= used;
- }
- }
- /* Run command in shell; used for -c. */
- __dead void
- client_exec(const char *shell, const char *shellcmd)
- {
- const char *name, *ptr;
- char *argv0;
- log_debug("shell %s, command %s", shell, shellcmd);
- ptr = strrchr(shell, '/');
- if (ptr != NULL && *(ptr + 1) != '\0')
- name = ptr + 1;
- else
- name = shell;
- if (client_flags & CLIENT_LOGIN)
- xasprintf(&argv0, "-%s", name);
- else
- xasprintf(&argv0, "%s", name);
- setenv("SHELL", shell, 1);
- setblocking(STDIN_FILENO, 1);
- setblocking(STDOUT_FILENO, 1);
- setblocking(STDERR_FILENO, 1);
- closefrom(STDERR_FILENO + 1);
- execl(shell, argv0, "-c", shellcmd, (char *) NULL);
- fatal("execl failed");
- }
- /* Callback to handle signals in the client. */
- void
- client_signal(int sig)
- {
- struct sigaction sigact;
- int status;
- if (sig == SIGCHLD)
- waitpid(WAIT_ANY, &status, WNOHANG);
- else if (!client_attached) {
- if (sig == SIGTERM)
- proc_exit(client_proc);
- } else {
- switch (sig) {
- case SIGHUP:
- client_exitreason = CLIENT_EXIT_LOST_TTY;
- client_exitval = 1;
- proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
- break;
- case SIGTERM:
- client_exitreason = CLIENT_EXIT_TERMINATED;
- client_exitval = 1;
- proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
- break;
- case SIGWINCH:
- proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
- break;
- case SIGCONT:
- memset(&sigact, 0, sizeof sigact);
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = SA_RESTART;
- sigact.sa_handler = SIG_IGN;
- if (sigaction(SIGTSTP, &sigact, NULL) != 0)
- fatal("sigaction failed");
- proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
- break;
- }
- }
- }
- /* Callback for client read events. */
- void
- client_dispatch(struct imsg *imsg, void *arg)
- {
- if (imsg == NULL) {
- client_exitreason = CLIENT_EXIT_LOST_SERVER;
- client_exitval = 1;
- proc_exit(client_proc);
- return;
- }
- if (client_attached)
- client_dispatch_attached(imsg);
- else
- client_dispatch_wait(imsg, arg);
- }
- /* Dispatch imsgs when in wait state (before MSG_READY). */
- void
- client_dispatch_wait(struct imsg *imsg, const char *shellcmd)
- {
- char *data;
- ssize_t datalen;
- struct msg_stdout_data stdoutdata;
- struct msg_stderr_data stderrdata;
- int retval;
- #ifdef __OpenBSD__
- static int pledge_applied;
- /*
- * "sendfd" is no longer required once all of the identify messages
- * have been sent. We know the server won't send us anything until that
- * point (because we don't ask it to), so we can drop "sendfd" once we
- * get the first message from the server.
- */
- if (!pledge_applied) {
- if (pledge("stdio unix proc exec tty", NULL) != 0)
- fatal("pledge failed");
- pledge_applied = 1;
- };
- #endif
- data = imsg->data;
- datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
- switch (imsg->hdr.type) {
- case MSG_EXIT:
- case MSG_SHUTDOWN:
- if (datalen != sizeof retval && datalen != 0)
- fatalx("bad MSG_EXIT size");
- if (datalen == sizeof retval) {
- memcpy(&retval, data, sizeof retval);
- client_exitval = retval;
- }
- proc_exit(client_proc);
- break;
- case MSG_READY:
- if (datalen != 0)
- fatalx("bad MSG_READY size");
- event_del(&client_stdin);
- client_attached = 1;
- proc_send(client_peer, MSG_RESIZE, -1, NULL, 0);
- break;
- case MSG_STDIN:
- if (datalen != 0)
- fatalx("bad MSG_STDIN size");
- event_add(&client_stdin, NULL);
- break;
- case MSG_STDOUT:
- if (datalen != sizeof stdoutdata)
- fatalx("bad MSG_STDOUT size");
- memcpy(&stdoutdata, data, sizeof stdoutdata);
- client_write(STDOUT_FILENO, stdoutdata.data,
- stdoutdata.size);
- break;
- case MSG_STDERR:
- if (datalen != sizeof stderrdata)
- fatalx("bad MSG_STDERR size");
- memcpy(&stderrdata, data, sizeof stderrdata);
- client_write(STDERR_FILENO, stderrdata.data,
- stderrdata.size);
- break;
- case MSG_VERSION:
- if (datalen != 0)
- fatalx("bad MSG_VERSION size");
- fprintf(stderr, "protocol version mismatch "
- "(client %d, server %u)\n", PROTOCOL_VERSION,
- imsg->hdr.peerid & 0xff);
- client_exitval = 1;
- proc_exit(client_proc);
- break;
- case MSG_SHELL:
- if (datalen == 0 || data[datalen - 1] != '\0')
- fatalx("bad MSG_SHELL string");
- clear_signals(0);
- client_exec(data, shellcmd);
- /* NOTREACHED */
- case MSG_DETACH:
- case MSG_DETACHKILL:
- proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
- break;
- case MSG_EXITED:
- proc_exit(client_proc);
- break;
- }
- }
- /* Dispatch imsgs in attached state (after MSG_READY). */
- void
- client_dispatch_attached(struct imsg *imsg)
- {
- struct sigaction sigact;
- char *data;
- ssize_t datalen;
- data = imsg->data;
- datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
- switch (imsg->hdr.type) {
- case MSG_DETACH:
- case MSG_DETACHKILL:
- if (datalen == 0 || data[datalen - 1] != '\0')
- fatalx("bad MSG_DETACH string");
- client_exitsession = xstrdup(data);
- client_exittype = imsg->hdr.type;
- if (imsg->hdr.type == MSG_DETACHKILL)
- client_exitreason = CLIENT_EXIT_DETACHED_HUP;
- else
- client_exitreason = CLIENT_EXIT_DETACHED;
- proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
- break;
- case MSG_EXIT:
- if (datalen != 0 && datalen != sizeof (int))
- fatalx("bad MSG_EXIT size");
- proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
- client_exitreason = CLIENT_EXIT_EXITED;
- break;
- case MSG_EXITED:
- if (datalen != 0)
- fatalx("bad MSG_EXITED size");
- proc_exit(client_proc);
- break;
- case MSG_SHUTDOWN:
- if (datalen != 0)
- fatalx("bad MSG_SHUTDOWN size");
- proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
- client_exitreason = CLIENT_EXIT_SERVER_EXITED;
- client_exitval = 1;
- break;
- case MSG_SUSPEND:
- if (datalen != 0)
- fatalx("bad MSG_SUSPEND size");
- memset(&sigact, 0, sizeof sigact);
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = SA_RESTART;
- sigact.sa_handler = SIG_DFL;
- if (sigaction(SIGTSTP, &sigact, NULL) != 0)
- fatal("sigaction failed");
- kill(getpid(), SIGTSTP);
- break;
- case MSG_LOCK:
- if (datalen == 0 || data[datalen - 1] != '\0')
- fatalx("bad MSG_LOCK string");
- system(data);
- proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
- break;
- }
- }
|