summaryrefslogtreecommitdiff
path: root/Src/watch.c
diff options
context:
space:
mode:
authorOliver Kiddle <opk@zsh.org>2021-11-02 21:39:52 +0100
committerOliver Kiddle <opk@zsh.org>2021-11-02 21:41:53 +0100
commit271cfc685b17938e67a8212f2df78c32989411d7 (patch)
tree3f2c72a5d7df08dc17e54ae67f6c902a038b2b1d /Src/watch.c
parent2947130f91fe7edf7c79d73ccc0d096800709b3d (diff)
downloadzsh-271cfc685b17938e67a8212f2df78c32989411d7.tar.gz
zsh-271cfc685b17938e67a8212f2df78c32989411d7.zip
49534, 49539: separate watch/log functionality out into a module
Diffstat (limited to 'Src/watch.c')
-rw-r--r--Src/watch.c626
1 files changed, 0 insertions, 626 deletions
diff --git a/Src/watch.c b/Src/watch.c
deleted file mode 100644
index c41704315..000000000
--- a/Src/watch.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * watch.c - login/logout watching
- *
- * This file is part of zsh, the Z shell.
- *
- * Copyright (c) 1992-1997 Paul Falstad
- * All rights reserved.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and to distribute modified versions of this software for any
- * purpose, provided that the above copyright notice and the following
- * two paragraphs appear in all copies of this software.
- *
- * In no event shall Paul Falstad or the Zsh Development Group be liable
- * to any party for direct, indirect, special, incidental, or consequential
- * damages arising out of the use of this software and its documentation,
- * even if Paul Falstad and the Zsh Development Group have been advised of
- * the possibility of such damage.
- *
- * Paul Falstad and the Zsh Development Group specifically disclaim any
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose. The software
- * provided hereunder is on an "as is" basis, and Paul Falstad and the
- * Zsh Development Group have no obligation to provide maintenance,
- * support, updates, enhancements, or modifications.
- *
- */
-
-#include "zsh.mdh"
-
-/* Headers for utmp/utmpx structures */
-#ifdef HAVE_UTMP_H
-# include <utmp.h>
-#endif
-#ifdef HAVE_UTMPX_H
-# include <utmpx.h>
-#endif
-
-/* Find utmp file */
-#if !defined(REAL_UTMP_FILE) && defined(UTMP_FILE)
-# define REAL_UTMP_FILE UTMP_FILE
-#endif
-#if !defined(REAL_UTMP_FILE) && defined(_PATH_UTMP)
-# define REAL_UTMP_FILE _PATH_UTMP
-#endif
-#if !defined(REAL_UTMP_FILE) && defined(PATH_UTMP_FILE)
-# define REAL_UTMP_FILE PATH_UTMP_FILE
-#endif
-
-/* Find wtmp file */
-#if !defined(REAL_WTMP_FILE) && defined(WTMP_FILE)
-# define REAL_WTMP_FILE WTMP_FILE
-#endif
-#if !defined(REAL_WTMP_FILE) && defined(_PATH_WTMP)
-# define REAL_WTMP_FILE _PATH_WTMP
-#endif
-#if !defined(REAL_WTMP_FILE) && defined(PATH_WTMP_FILE)
-# define REAL_WTMP_FILE PATH_WTMP_FILE
-#endif
-
-/* Find utmpx file */
-#if !defined(REAL_UTMPX_FILE) && defined(UTMPX_FILE)
-# define REAL_UTMPX_FILE UTMPX_FILE
-#endif
-#if !defined(REAL_UTMPX_FILE) && defined(_PATH_UTMPX)
-# define REAL_UTMPX_FILE _PATH_UTMPX
-#endif
-#if !defined(REAL_UTMPX_FILE) && defined(PATH_UTMPX_FILE)
-# define REAL_UTMPX_FILE PATH_UTMPX_FILE
-#endif
-
-/* Find wtmpx file */
-#if !defined(REAL_WTMPX_FILE) && defined(WTMPX_FILE)
-# define REAL_WTMPX_FILE WTMPX_FILE
-#endif
-#if !defined(REAL_WTMPX_FILE) && defined(_PATH_WTMPX)
-# define REAL_WTMPX_FILE _PATH_WTMPX
-#endif
-#if !defined(REAL_WTMPX_FILE) && defined(PATH_WTMPX_FILE)
-# define REAL_WTMPX_FILE PATH_WTMPX_FILE
-#endif
-
-/* Decide which structure to use. We use a structure that exists in *
- * the headers, and require that its corresponding utmp file exist. *
- * (wtmp is less important.) */
-
-#if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMPX) && defined(REAL_UTMPX_FILE)
-# define WATCH_STRUCT_UTMP struct utmpx
-# if defined(HAVE_SETUTXENT) && defined(HAVE_GETUTXENT) && defined(HAVE_ENDUTXENT)
-# define setutent setutxent
-# define getutent getutxent
-# define endutent endutxent
-# ifndef HAVE_GETUTENT
-# define HAVE_GETUTENT 1
-# endif
-# endif
-
-/*
- * In utmpx, the ut_name field is replaced by ut_user.
- * However, on some systems ut_name may already be defined this
- * way for the purposes of utmp.
- */
-# ifndef ut_name
-# define ut_name ut_user
-# endif
-# ifdef HAVE_STRUCT_UTMPX_UT_XTIME
-# undef ut_time
-# define ut_time ut_xtime
-# else /* !HAVE_STRUCT_UTMPX_UT_XTIME */
-# ifdef HAVE_STRUCT_UTMPX_UT_TV
-# undef ut_time
-# define ut_time ut_tv.tv_sec
-# endif /* HAVE_STRUCT_UTMPX_UT_TV */
-# endif /* !HAVE_STRUCT_UTMPX_UT_XTIME */
-# define WATCH_UTMP_FILE REAL_UTMPX_FILE
-# ifdef REAL_WTMPX_FILE
-# define WATCH_WTMP_FILE REAL_WTMPX_FILE
-# endif
-# ifdef HAVE_STRUCT_UTMPX_UT_HOST
-# define WATCH_UTMP_UT_HOST 1
-# endif
-#endif
-
-#if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMP) && defined(REAL_UTMP_FILE)
-# define WATCH_STRUCT_UTMP struct utmp
-# define WATCH_UTMP_FILE REAL_UTMP_FILE
-# ifdef REAL_WTMP_FILE
-# define WATCH_WTMP_FILE REAL_WTMP_FILE
-# endif
-# ifdef HAVE_STRUCT_UTMP_UT_HOST
-# define WATCH_UTMP_UT_HOST 1
-# endif
-#endif
-
-#ifdef WATCH_UTMP_UT_HOST
-# define DEFAULT_WATCHFMT "%n has %a %l from %m."
-#else /* !WATCH_UTMP_UT_HOST */
-# define DEFAULT_WATCHFMT "%n has %a %l."
-#endif /* !WATCH_UTMP_UT_HOST */
-
-/**/
-char const * const default_watchfmt = DEFAULT_WATCHFMT;
-
-#ifdef WATCH_STRUCT_UTMP
-
-# include "watch.pro"
-
-# ifndef WATCH_WTMP_FILE
-# define WATCH_WTMP_FILE "/dev/null"
-# endif
-
-static int wtabsz = 0;
-static WATCH_STRUCT_UTMP *wtab = NULL;
-static time_t lastutmpcheck = 0;
-
-/* get the time of login/logout for WATCH */
-
-/**/
-static time_t
-getlogtime(WATCH_STRUCT_UTMP *u, int inout)
-{
- FILE *in;
- WATCH_STRUCT_UTMP uu;
- int first = 1;
- int srchlimit = 50; /* max number of wtmp records to search */
-
- if (inout)
- return u->ut_time;
- if (!(in = fopen(WATCH_WTMP_FILE, "r")))
- return time(NULL);
- fseek(in, 0, SEEK_END);
- do {
- if (fseek(in, ((first) ? -1 : -2) * sizeof(WATCH_STRUCT_UTMP), SEEK_CUR)) {
- fclose(in);
- return time(NULL);
- }
- first = 0;
- if (!fread(&uu, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
- fclose(in);
- return time(NULL);
- }
- if (uu.ut_time < lastwatch || !srchlimit--) {
- fclose(in);
- return time(NULL);
- }
- }
- while (memcmp(&uu, u, sizeof(uu)));
-
- do
- if (!fread(&uu, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
- fclose(in);
- return time(NULL);
- }
- while (strncmp(uu.ut_line, u->ut_line, sizeof(u->ut_line)));
- fclose(in);
- return uu.ut_time;
-}
-
-/* Mutually recursive call to handle ternaries in $WATCHFMT */
-
-# define BEGIN3 '('
-# define END3 ')'
-
-/**/
-static char *
-watch3ary(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt)
-{
- int truth = 1, sep;
-
- switch (*fmt++) {
- case 'n':
- truth = (u->ut_name[0] != 0);
- break;
- case 'a':
- truth = inout;
- break;
- case 'l':
- if (!strncmp(u->ut_line, "tty", 3))
- truth = (u->ut_line[3] != 0);
- else
- truth = (u->ut_line[0] != 0);
- break;
-# ifdef WATCH_UTMP_UT_HOST
- case 'm':
- case 'M':
- truth = (u->ut_host[0] != 0);
- break;
-# endif /* WATCH_UTMP_UT_HOST */
- default:
- prnt = 0; /* Skip unknown conditionals entirely */
- break;
- }
- sep = *fmt++;
- fmt = watchlog2(inout, u, fmt, (truth && prnt), sep);
- return watchlog2(inout, u, fmt, (!truth && prnt), END3);
-}
-
-/* print a login/logout event */
-
-/**/
-static char *
-watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
-{
- char buf[40], buf2[80];
- time_t timet;
- struct tm *tm;
- char *fm2;
- int len;
-# ifdef WATCH_UTMP_UT_HOST
- char *p;
- int i;
-# endif /* WATCH_UTMP_UT_HOST */
-
- while (*fmt)
- if (*fmt == '\\') {
- if (*++fmt) {
- if (prnt)
- putchar(*fmt);
- ++fmt;
- } else if (fini)
- return fmt;
- else
- break;
- }
- else if (*fmt == fini)
- return ++fmt;
- else if (*fmt != '%') {
- if (prnt)
- putchar(*fmt);
- ++fmt;
- } else {
- if (*++fmt == BEGIN3)
- fmt = watch3ary(inout, u, ++fmt, prnt);
- else if (!prnt)
- ++fmt;
- else
- switch (*(fm2 = fmt++)) {
- case 'n':
- printf("%.*s", (int)sizeof(u->ut_name), u->ut_name);
- break;
- case 'a':
- printf("%s", (!inout) ? "logged off" : "logged on");
- break;
- case 'l':
- if (!strncmp(u->ut_line, "tty", 3))
- printf("%.*s", (int)sizeof(u->ut_line) - 3, u->ut_line + 3);
- else
- printf("%.*s", (int)sizeof(u->ut_line), u->ut_line);
- break;
-# ifdef WATCH_UTMP_UT_HOST
- case 'm':
- for (p = u->ut_host, i = sizeof(u->ut_host); i && *p; i--, p++) {
- if (*p == '.' && !idigit(p[1]))
- break;
- putchar(*p);
- }
- break;
- case 'M':
- printf("%.*s", (int)sizeof(u->ut_host), u->ut_host);
- break;
-# endif /* WATCH_UTMP_UT_HOST */
- case 'T':
- case 't':
- case '@':
- case 'W':
- case 'w':
- case 'D':
- switch (*fm2) {
- case '@':
- case 't':
- fm2 = "%l:%M%p";
- break;
- case 'T':
- fm2 = "%K:%M";
- break;
- case 'w':
- fm2 = "%a %f";
- break;
- case 'W':
- fm2 = "%m/%d/%y";
- break;
- case 'D':
- if (fm2[1] == '{') {
- char *dd, *ss;
- int n = 79;
-
- for (ss = fm2 + 2, dd = buf2;
- n-- && *ss && *ss != '}'; ++ss, ++dd)
- *dd = *((*ss == '\\' && ss[1]) ? ++ss : ss);
- if (*ss == '}') {
- *dd = '\0';
- fmt = ss + 1;
- fm2 = buf2;
- }
- else fm2 = "%y-%m-%d";
- }
- else fm2 = "%y-%m-%d";
- break;
- }
- timet = getlogtime(u, inout);
- tm = localtime(&timet);
- len = ztrftime(buf, 40, fm2, tm, 0L);
- if (len > 0)
- metafy(buf, len, META_NOALLOC);
- printf("%s", (*buf == ' ') ? buf + 1 : buf);
- break;
- case '%':
- putchar('%');
- break;
- case 'S':
- txtset(TXTSTANDOUT);
- tsetcap(TCSTANDOUTBEG, TSC_RAW);
- break;
- case 's':
- txtunset(TXTSTANDOUT);
- tsetcap(TCSTANDOUTEND, TSC_RAW|TSC_DIRTY);
- break;
- case 'B':
- txtset(TXTBOLDFACE);
- tsetcap(TCBOLDFACEBEG, TSC_RAW|TSC_DIRTY);
- break;
- case 'b':
- txtunset(TXTBOLDFACE);
- tsetcap(TCALLATTRSOFF, TSC_RAW|TSC_DIRTY);
- break;
- case 'U':
- txtset(TXTUNDERLINE);
- tsetcap(TCUNDERLINEBEG, TSC_RAW);
- break;
- case 'u':
- txtunset(TXTUNDERLINE);
- tsetcap(TCUNDERLINEEND, TSC_RAW|TSC_DIRTY);
- break;
- default:
- putchar('%');
- putchar(*fm2);
- break;
- }
- }
- if (prnt)
- putchar('\n');
-
- return fmt;
-}
-
-/* See if the watch entry matches */
-
-static int
-watchlog_match(char *teststr, char *actual, int len)
-{
- int ret = 0;
- Patprog pprog;
- char *str = dupstring(teststr);
-
- tokenize(str);
-
- if ((pprog = patcompile(str, PAT_STATIC, 0))) {
- queue_signals();
- if (pattry(pprog, actual))
- ret = 1;
- unqueue_signals();
- } else if (!strncmp(actual, teststr, len))
- ret = 1;
- return ret;
-}
-
-/* check the List for login/logouts */
-
-/**/
-static void
-watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w, char *fmt)
-{
- char *v, *vv, sav;
- int bad;
-
- if (!*u->ut_name)
- return;
-
- if (*w && !strcmp(*w, "all")) {
- (void)watchlog2(inout, u, fmt, 1, 0);
- return;
- }
- if (*w && !strcmp(*w, "notme") &&
- strncmp(u->ut_name, get_username(), sizeof(u->ut_name))) {
- (void)watchlog2(inout, u, fmt, 1, 0);
- return;
- }
- for (; *w; w++) {
- bad = 0;
- v = *w;
- if (*v != '@' && *v != '%') {
- for (vv = v; *vv && *vv != '@' && *vv != '%'; vv++);
- sav = *vv;
- *vv = '\0';
- if (!watchlog_match(v, u->ut_name, sizeof(u->ut_name)))
- bad = 1;
- *vv = sav;
- v = vv;
- }
- for (;;)
- if (*v == '%') {
- for (vv = ++v; *vv && *vv != '@'; vv++);
- sav = *vv;
- *vv = '\0';
- if (!watchlog_match(v, u->ut_line, sizeof(u->ut_line)))
- bad = 1;
- *vv = sav;
- v = vv;
- }
-# ifdef WATCH_UTMP_UT_HOST
- else if (*v == '@') {
- for (vv = ++v; *vv && *vv != '%'; vv++);
- sav = *vv;
- *vv = '\0';
- if (!watchlog_match(v, u->ut_host, strlen(v)))
- bad = 1;
- *vv = sav;
- v = vv;
- }
-# endif /* WATCH_UTMP_UT_HOST */
- else
- break;
- if (!bad) {
- (void)watchlog2(inout, u, fmt, 1, 0);
- return;
- }
- }
-}
-
-/* compare 2 utmp entries */
-
-/**/
-static int
-ucmp(WATCH_STRUCT_UTMP *u, WATCH_STRUCT_UTMP *v)
-{
- if (u->ut_time == v->ut_time)
- return strncmp(u->ut_line, v->ut_line, sizeof(u->ut_line));
- return u->ut_time - v->ut_time;
-}
-
-/* initialize the user List */
-
-/**/
-static int
-readwtab(WATCH_STRUCT_UTMP **head, int initial_sz)
-{
- WATCH_STRUCT_UTMP *uptr;
- int wtabmax = initial_sz < 2 ? 32 : initial_sz;
- int sz = 0;
-# ifdef HAVE_GETUTENT
- WATCH_STRUCT_UTMP *tmp;
-# else
- FILE *in;
-# endif
-
- uptr = *head = (WATCH_STRUCT_UTMP *)
- zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP));
-# ifdef HAVE_GETUTENT
- setutent();
- while ((tmp = getutent()) != NULL) {
- memcpy(uptr, tmp, sizeof (WATCH_STRUCT_UTMP));
-# else
- if (!(in = fopen(WATCH_UTMP_FILE, "r")))
- return 0;
- while (fread(uptr, sizeof(WATCH_STRUCT_UTMP), 1, in)) {
-# endif
-# ifdef USER_PROCESS
- if (uptr->ut_type == USER_PROCESS)
-# else /* !USER_PROCESS */
- if (uptr->ut_name[0])
-# endif /* !USER_PROCESS */
- {
- uptr++;
- if (++sz == wtabmax) {
- uptr = (WATCH_STRUCT_UTMP *)
- realloc(*head, (wtabmax *= 2) * sizeof(WATCH_STRUCT_UTMP));
- if (uptr == NULL) {
- /* memory pressure - so stop consuming and use, what we have
- * Other option is to exit() here, as zmalloc does on error */
- sz--;
- break;
- }
- *head = uptr;
- uptr += sz;
- }
- }
- }
-# ifdef HAVE_GETUTENT
- endutent();
-# else
- fclose(in);
-# endif
-
- if (sz)
- qsort((void *) *head, sz, sizeof(WATCH_STRUCT_UTMP),
- (int (*) _((const void *, const void *)))ucmp);
- return sz;
-}
-
-/* Check for login/logout events; executed before *
- * each prompt if WATCH is set */
-
-/**/
-void
-dowatch(void)
-{
- WATCH_STRUCT_UTMP *utab, *uptr, *wptr;
- struct stat st;
- char **s;
- char *fmt;
- int utabsz, uct, wct;
-
- s = watch;
-
- holdintr();
- if (!wtab)
- wtabsz = readwtab(&wtab, 32);
- if ((stat(WATCH_UTMP_FILE, &st) == -1) || (st.st_mtime <= lastutmpcheck)) {
- noholdintr();
- return;
- }
- lastutmpcheck = st.st_mtime;
- utabsz = readwtab(&utab, wtabsz + 4);
- noholdintr();
- if (errflag) {
- free(utab);
- return;
- }
-
- wct = wtabsz;
- uct = utabsz;
- uptr = utab;
- wptr = wtab;
- if (errflag) {
- free(utab);
- return;
- }
- queue_signals();
- if (!(fmt = getsparam_u("WATCHFMT")))
- fmt = DEFAULT_WATCHFMT;
- while ((uct || wct) && !errflag) {
- if (!uct || (wct && ucmp(uptr, wptr) > 0))
- wct--, watchlog(0, wptr++, s, fmt);
- else if (!wct || (uct && ucmp(uptr, wptr) < 0))
- uct--, watchlog(1, uptr++, s, fmt);
- else
- uptr++, wptr++, wct--, uct--;
- }
- unqueue_signals();
- free(wtab);
- wtab = utab;
- wtabsz = utabsz;
- fflush(stdout);
-}
-
-/**/
-int
-bin_log(UNUSED(char *nam), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
-{
- if (!watch)
- return 1;
- if (wtab)
- free(wtab);
- wtab = (WATCH_STRUCT_UTMP *)zalloc(1);
- wtabsz = 0;
- lastutmpcheck = 0;
- dowatch();
- return 0;
-}
-
-#else /* !WATCH_STRUCT_UTMP */
-
-/**/
-void dowatch(void)
-{
-}
-
-/**/
-int
-bin_log(char *nam, char **argv, Options ops, int func)
-{
- return bin_notavail(nam, argv, ops, func);
-}
-
-#endif /* !WATCH_STRUCT_UTMP */