diff options
author | William Hubbs <w.d.hubbs@gmail.com> | 2022-04-06 10:51:55 -0500 |
---|---|---|
committer | William Hubbs <w.d.hubbs@gmail.com> | 2022-04-06 10:51:55 -0500 |
commit | 391d12db48754861b5cecac92ee3321597ee02c1 (patch) | |
tree | b42fad5a31ca342de7b7ecf1fb78784194c1400c /src/openrc-shutdown/broadcast.c | |
parent | 0efc1b133e4182bd53cde78153bd8b5cc2e99448 (diff) |
migrate fully to meson build system
- drop old build system
- move shared include and source files to common directory
- drop "rc-" prefix from shared include and source files
- move executable-specific code to individual directories under src
- adjust top-level .gitignore file for new build system
This closes #489.
Diffstat (limited to 'src/openrc-shutdown/broadcast.c')
-rw-r--r-- | src/openrc-shutdown/broadcast.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/openrc-shutdown/broadcast.c b/src/openrc-shutdown/broadcast.c new file mode 100644 index 00000000..402a9fb9 --- /dev/null +++ b/src/openrc-shutdown/broadcast.c @@ -0,0 +1,211 @@ +/* + * broadcast.c + * broadcast a message to every logged in user + */ + +/* + * Copyright 2018 Sony Interactive Entertainment Inc. + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/HEAD/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <stdio.h> +#include <utmp.h> +#include <utmpx.h> +#include <pwd.h> +#include <fcntl.h> +#include <signal.h> +#include <setjmp.h> +#include <paths.h> +#include <sys/utsname.h> + +#include "broadcast.h" +#include "helpers.h" + +#ifndef _PATH_DEV +# define _PATH_DEV "/dev/" +#endif + +static sigjmp_buf jbuf; + +/* + * Alarm handler + */ +/*ARGSUSED*/ +# ifdef __GNUC__ +static void handler(int arg __attribute__((unused))) +# else +static void handler(int arg) +# endif +{ + siglongjmp(jbuf, 1); +} + +static void getuidtty(char **userp, char **ttyp) +{ + struct passwd *pwd; + uid_t uid; + char *tty; + static char uidbuf[32]; + char *ttynm = NULL; + + uid = getuid(); + if ((pwd = getpwuid(uid)) != NULL) { + uidbuf[0] = 0; + strncat(uidbuf, pwd->pw_name, sizeof(uidbuf) - 1); + } else { + if (uid) + sprintf(uidbuf, "uid %d", (int) uid); + else + sprintf(uidbuf, "root"); + } + + if ((tty = ttyname(0)) != NULL) { + const size_t plen = strlen(_PATH_DEV); + if (strncmp(tty, _PATH_DEV, plen) == 0) { + tty += plen; + if (tty[0] == '/') + tty++; + } + xasprintf(&ttynm, "(%s) ", tty); + } + + *userp = uidbuf; + *ttyp = ttynm; +} + +/* + * Check whether the given filename looks like a tty device. + */ +static int file_isatty(const char *fname) +{ + struct stat st; + int major; + + if (stat(fname, &st) < 0) + return 0; + + if (st.st_nlink != 1 || !S_ISCHR(st.st_mode)) + return 0; + + /* + * It would be an impossible task to list all major/minors + * of tty devices here, so we just exclude the obvious + * majors of which just opening has side-effects: + * printers and tapes. + */ + major = major(st.st_dev); + if (major == 1 || major == 2 || major == 6 || major == 9 || + major == 12 || major == 16 || major == 21 || major == 27 || + major == 37 || major == 96 || major == 97 || major == 206 || + major == 230) + return 0; + return 1; +} + +/* + * broadcast function. + * + * NB: Not multithread safe. + */ +void broadcast(char *text) +{ + char *tty; + char *user; + struct utsname name; + time_t t; + char *date; + char *p; + char *line = NULL; + struct sigaction sa; + int flags; + char *term = NULL; + struct utmpx *utmp; + /* + * These are set across the sigsetjmp call, so they can't be stored on + * the stack, otherwise they might be clobbered. + */ + static int fd; + static FILE *tp; + + getuidtty(&user, &tty); + + /* + * Get and report current hostname, to make it easier to find out + * which machine is being shut down. + */ + uname(&name); + + /* Get the time */ + time(&t); + date = ctime(&t); + p = strchr(date, '\n'); + if (p) + *p = 0; + + xasprintf(&line, "\007\r\nBroadcast message from %s@%s %s(%s):\r\n\r\n", + user, name.nodename, tty, date); + free(tty); + + /* + * Fork to avoid hanging in a write() + */ + if (fork() != 0) + return; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sigaction(SIGALRM, &sa, NULL); + + setutxent(); + + while ((utmp = getutxent()) != NULL) { + if (utmp->ut_type != USER_PROCESS || utmp->ut_user[0] == 0) + continue; + if (strncmp(utmp->ut_line, _PATH_DEV, strlen(_PATH_DEV)) == 0) + xasprintf(&term, "%s", utmp->ut_line); + else + xasprintf(&term, "%s%s", _PATH_DEV, utmp->ut_line); + if (strstr(term, "/../")) { + free(term); + continue; + } + + /* + * Open it non-delay + */ + if (sigsetjmp(jbuf, 1) == 0) { + alarm(2); + flags = O_WRONLY|O_NDELAY|O_NOCTTY; + if (file_isatty(term) && (fd = open(term, flags)) >= 0) { + if (isatty(fd) && (tp = fdopen(fd, "w")) != NULL) { + fputs(line, tp); + fputs(text, tp); + fflush(tp); + } + } + } + alarm(0); + if (fd >= 0) + close(fd); + if (tp != NULL) + fclose(tp); + free(term); + } + endutxent(); + free(line); + exit(0); +} |