49534, 49539: separate watch/log functionality out into a module

This commit is contained in:
Oliver Kiddle 2021-11-02 21:39:52 +01:00
parent 2947130f91
commit 271cfc685b
13 changed files with 265 additions and 170 deletions

View file

@ -1,5 +1,11 @@
2021-11-02 Oliver Kiddle <opk@zsh.org>
* 49534, 49539: Doc/Makefile.in, Doc/Zsh/builtins.yo,
Doc/Zsh/compat.yo, Doc/Zsh/mod_watch.yo, Doc/Zsh/params.yo,
Src/Modules/watch.mdd, Src/builtin.c, Src/init.c, Src/params.c,
Src/utils.c, Src/Modules/watch.c, Src/zsh.mdd: separate watch/log
functionality out into a module
* 49537: aczsh.m4, configure.ac: fix finding utmpx file on FreeBSD
2021-11-01 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>

View file

@ -69,6 +69,7 @@ Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_private.yo \
Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
Zsh/mod_stat.yo Zsh/mod_system.yo Zsh/mod_tcp.yo \
Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
Zsh/mod_watch.yo \
Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
Zsh/mod_zprof.yo Zsh/mod_zpty.yo Zsh/mod_zselect.yo \
Zsh/mod_zutil.yo

View file

@ -1235,14 +1235,6 @@ Same as tt(typeset), except that the options tt(-g), and
tt(-f) are not permitted. In this case the tt(-x) option does not force
the use of tt(-g), i.e. exported variables will be local to functions.
)
findex(log)
vindex(watch, use of)
cindex(watching users)
cindex(users, watching)
item(tt(log))(
List all users currently logged in who are affected by
the current setting of the tt(watch) parameter.
)
findex(logout)
item(tt(logout) [ var(n) ])(
Same as tt(exit), except that it only works in a login shell.

View file

@ -30,8 +30,7 @@ tt(PROMPT2),
tt(PROMPT3),
tt(PROMPT4),
tt(psvar),
tt(status),
tt(watch).
tt(status).
vindex(ENV, use of)
The usual zsh startup/shutdown scripts are not executed. Login shells

140
Doc/Zsh/mod_watch.yo Normal file
View file

@ -0,0 +1,140 @@
COMMENT(!MOD!zsh/watch
Reporting of login and logout events.
!MOD!)
The tt(zsh/watch) module can be used to report when specific users log in or
out. This is controlled via the following parameters.
startitem()
vindex(LOGCHECK)
item(tt(LOGCHECK))(
The interval in seconds between checks for login/logout activity
using the tt(watch) parameter.
)
vindex(watch)
vindex(WATCH)
item(tt(watch) <S> <Z> (tt(WATCH) <S>))(
An array (colon-separated list) of login/logout events to report.
If it contains the single word `tt(all)', then all login/logout events
are reported. If it contains the single word `tt(notme)', then all
events are reported as with `tt(all)' except tt($USERNAME).
An entry in this list may consist of a username,
an `tt(@)' followed by a remote hostname,
and a `tt(%)' followed by a line (tty). Any of these may
be a pattern (be sure to quote this during the assignment to
tt(watch) so that it does not immediately perform file generation);
the setting of the tt(EXTENDED_GLOB) option is respected.
Any or all of these components may be present in an entry;
if a login/logout event matches all of them,
it is reported.
For example, with the tt(EXTENDED_GLOB) option set, the following:
example(watch=('^(pws|barts)'))
causes reports for activity associated with any user other than tt(pws)
or tt(barts).
)
vindex(WATCHFMT)
item(tt(WATCHFMT))(
The format of login/logout reports if the tt(watch) parameter is set.
Default is `tt(%n has %a %l from %m)'.
Recognizes the following escape sequences:
startitem()
item(tt(%n))(
The name of the user that logged in/out.
)
item(tt(%a))(
The observed action, i.e. "logged on" or "logged off".
)
item(tt(%l))(
The line (tty) the user is logged in on.
)
item(tt(%M))(
The full hostname of the remote host.
)
item(tt(%m))(
The hostname up to the first `tt(.)'. If only the
IP address is available or the utmp field contains
the name of an X-windows display, the whole name is printed.
em(NOTE:)
The `tt(%m)' and `tt(%M)' escapes will work only if there is a host name
field in the utmp on your machine. Otherwise they are
treated as ordinary strings.
)
item(tt(%S) LPAR()tt(%s)RPAR())(
Start (stop) standout mode.
)
item(tt(%U) LPAR()tt(%u)RPAR())(
Start (stop) underline mode.
)
item(tt(%B) LPAR()tt(%b)RPAR())(
Start (stop) boldface mode.
)
xitem(tt(%t))
item(tt(%@))(
The time, in 12-hour, am/pm format.
)
item(tt(%T))(
The time, in 24-hour format.
)
item(tt(%w))(
The date in `var(day)tt(-)var(dd)' format.
)
item(tt(%W))(
The date in `var(mm)tt(/)var(dd)tt(/)var(yy)' format.
)
item(tt(%D))(
The date in `var(yy)tt(-)var(mm)tt(-)var(dd)' format.
)
item(tt(%D{)var(string)tt(}))(
The date formatted as var(string) using the tt(strftime) function, with
zsh extensions as described by
ifzman(EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
ifnzman(noderef(Prompt Expansion)).
)
item(tt(%LPAR())var(x)tt(:)var(true-text)tt(:)var(false-text)tt(RPAR()))(
Specifies a ternary expression.
The character following the var(x) is
arbitrary; the same character is used to separate the text
for the "true" result from that for the "false" result.
Both the separator and the right parenthesis may be escaped
with a backslash.
Ternary expressions may be nested.
The test character var(x) may be any one of `tt(l)', `tt(n)', `tt(m)'
or `tt(M)', which indicate a `true' result if the corresponding
escape sequence would return a non-empty value; or it may be `tt(a)',
which indicates a `true' result if the watched user has logged in,
or `false' if he has logged out.
Other characters evaluate to neither true nor false; the entire
expression is omitted in this case.
If the result is `true', then the var(true-text)
is formatted according to the rules above and printed,
and the var(false-text) is skipped.
If `false', the var(true-text) is skipped and the var(false-text)
is formatted and printed.
Either or both of the branches may be empty, but
both separators must be present in any case.
)
enditem()
)
enditem()
Furthermore, the tt(zsh/watch) module makes available one builtin
command:
startitem()
findex(log)
vindex(watch, use of)
cindex(watching users)
cindex(users, watching)
item(tt(log))(
List all users currently logged in who are affected by
the current setting of the tt(watch) parameter.
)
enditem()

View file

@ -1332,11 +1332,6 @@ most as many lines as given by the absolute value.
If set to zero, the shell asks only if the top of the listing would scroll
off the screen.
)
vindex(LOGCHECK)
item(tt(LOGCHECK))(
The interval in seconds between checks for login/logout activity
using the tt(watch) parameter.
)
vindex(MAIL)
item(tt(MAIL))(
If this parameter is set and tt(mailpath) is not set,
@ -1670,119 +1665,6 @@ to be interpreted as a file extension. The default is not to append
any suffix, thus this parameter should be assigned only when needed
and then unset again.
)
vindex(watch)
vindex(WATCH)
item(tt(watch) <S> <Z> (tt(WATCH) <S>))(
An array (colon-separated list) of login/logout events to report.
If it contains the single word `tt(all)', then all login/logout events
are reported. If it contains the single word `tt(notme)', then all
events are reported as with `tt(all)' except tt($USERNAME).
An entry in this list may consist of a username,
an `tt(@)' followed by a remote hostname,
and a `tt(%)' followed by a line (tty). Any of these may
be a pattern (be sure to quote this during the assignment to
tt(watch) so that it does not immediately perform file generation);
the setting of the tt(EXTENDED_GLOB) option is respected.
Any or all of these components may be present in an entry;
if a login/logout event matches all of them,
it is reported.
For example, with the tt(EXTENDED_GLOB) option set, the following:
example(watch=('^(pws|barts)'))
causes reports for activity associated with any user other than tt(pws)
or tt(barts).
)
vindex(WATCHFMT)
item(tt(WATCHFMT))(
The format of login/logout reports if the tt(watch) parameter is set.
Default is `tt(%n has %a %l from %m)'.
Recognizes the following escape sequences:
startitem()
item(tt(%n))(
The name of the user that logged in/out.
)
item(tt(%a))(
The observed action, i.e. "logged on" or "logged off".
)
item(tt(%l))(
The line (tty) the user is logged in on.
)
item(tt(%M))(
The full hostname of the remote host.
)
item(tt(%m))(
The hostname up to the first `tt(.)'. If only the
IP address is available or the utmp field contains
the name of an X-windows display, the whole name is printed.
em(NOTE:)
The `tt(%m)' and `tt(%M)' escapes will work only if there is a host name
field in the utmp on your machine. Otherwise they are
treated as ordinary strings.
)
item(tt(%S) LPAR()tt(%s)RPAR())(
Start (stop) standout mode.
)
item(tt(%U) LPAR()tt(%u)RPAR())(
Start (stop) underline mode.
)
item(tt(%B) LPAR()tt(%b)RPAR())(
Start (stop) boldface mode.
)
xitem(tt(%t))
item(tt(%@))(
The time, in 12-hour, am/pm format.
)
item(tt(%T))(
The time, in 24-hour format.
)
item(tt(%w))(
The date in `var(day)tt(-)var(dd)' format.
)
item(tt(%W))(
The date in `var(mm)tt(/)var(dd)tt(/)var(yy)' format.
)
item(tt(%D))(
The date in `var(yy)tt(-)var(mm)tt(-)var(dd)' format.
)
item(tt(%D{)var(string)tt(}))(
The date formatted as var(string) using the tt(strftime) function, with
zsh extensions as described by
ifzman(EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
ifnzman(noderef(Prompt Expansion)).
)
item(tt(%LPAR())var(x)tt(:)var(true-text)tt(:)var(false-text)tt(RPAR()))(
Specifies a ternary expression.
The character following the var(x) is
arbitrary; the same character is used to separate the text
for the "true" result from that for the "false" result.
Both the separator and the right parenthesis may be escaped
with a backslash.
Ternary expressions may be nested.
The test character var(x) may be any one of `tt(l)', `tt(n)', `tt(m)'
or `tt(M)', which indicate a `true' result if the corresponding
escape sequence would return a non-empty value; or it may be `tt(a)',
which indicates a `true' result if the watched user has logged in,
or `false' if he has logged out.
Other characters evaluate to neither true nor false; the entire
expression is omitted in this case.
If the result is `true', then the var(true-text)
is formatted according to the rules above and printed,
and the var(false-text) is skipped.
If `false', the var(true-text) is skipped and the var(false-text)
is formatted and printed.
Either or both of the branches may be empty, but
both separators must be present in any case.
)
enditem()
)
vindex(WORDCHARS)
item(tt(WORDCHARS) <S>)(
A list of non-alphanumeric characters considered part of a word

View file

@ -27,7 +27,7 @@
*
*/
#include "zsh.mdh"
#include "watch.mdh"
/* Headers for utmp/utmpx structures */
#ifdef HAVE_UTMP_H
@ -139,9 +139,6 @@
# 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"
@ -152,11 +149,14 @@ char const * const default_watchfmt = DEFAULT_WATCHFMT;
static int wtabsz = 0;
static WATCH_STRUCT_UTMP *wtab = NULL;
/* the last time we checked the people in the WATCH variable */
static time_t lastwatch;
static time_t lastutmpcheck = 0;
/* get the time of login/logout for WATCH */
/**/
static time_t
getlogtime(WATCH_STRUCT_UTMP *u, int inout)
{
@ -202,7 +202,6 @@ getlogtime(WATCH_STRUCT_UTMP *u, int inout)
# define BEGIN3 '('
# define END3 ')'
/**/
static char *
watch3ary(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt)
{
@ -407,7 +406,6 @@ watchlog_match(char *teststr, char *actual, int len)
/* check the List for login/logouts */
/**/
static void
watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w, char *fmt)
{
@ -470,7 +468,6 @@ watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w, char *fmt)
/* compare 2 utmp entries */
/**/
static int
ucmp(WATCH_STRUCT_UTMP *u, WATCH_STRUCT_UTMP *v)
{
@ -481,7 +478,6 @@ ucmp(WATCH_STRUCT_UTMP *u, WATCH_STRUCT_UTMP *v)
/* initialize the user List */
/**/
static int
readwtab(WATCH_STRUCT_UTMP **head, int initial_sz)
{
@ -592,10 +588,19 @@ dowatch(void)
wtab = utab;
wtabsz = utabsz;
fflush(stdout);
lastwatch = time(NULL);
}
static void
checksched(void)
{
/* Do nothing if WATCH is not set, or LOGCHECK has not elapsed */
if (watch && (int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK"))
dowatch();
}
/**/
int
static int
bin_log(UNUSED(char *nam), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int func))
{
if (!watch)
@ -611,16 +616,101 @@ bin_log(UNUSED(char *nam), UNUSED(char **argv), UNUSED(Options ops), UNUSED(int
#else /* !WATCH_STRUCT_UTMP */
/**/
void dowatch(void)
static void
checksched(void)
{
}
/**/
int
static int
bin_log(char *nam, char **argv, Options ops, int func)
{
return bin_notavail(nam, argv, ops, func);
}
#endif /* !WATCH_STRUCT_UTMP */
/**/
static char **watch; /* $watch */
/* module setup */
static struct builtin bintab[] = {
BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
};
static struct paramdef partab[] = {
PARAMDEF("WATCH", PM_TIED|PM_SCALAR|PM_SPECIAL, &watch, &colonarr_gsu),
PARAMDEF("watch", PM_TIED|PM_ARRAY|PM_SPECIAL, &watch, &vararray_gsu),
};
static struct features module_features = {
bintab, sizeof(bintab)/sizeof(*bintab),
NULL, 0,
NULL, 0,
partab, sizeof(partab)/sizeof(*partab),
0
};
/**/
int
setup_(UNUSED(Module m))
{
return 0;
}
/**/
int
features_(Module m, char ***features)
{
*features = featuresarray(m, &module_features);
return 0;
}
/**/
int
enables_(Module m, int **enables)
{
return handlefeatures(m, &module_features, enables);
}
/**/
int
boot_(UNUSED(Module m))
{
static char const * const default_watchfmt = DEFAULT_WATCHFMT;
Param pm;
if ((pm = (Param) paramtab->getnode(paramtab, "watch")))
pm->ename = "WATCH";
if ((pm = (Param) paramtab->getnode(paramtab, "WATCH")))
pm->ename = "watch";
watch = mkarray(NULL);
/* These two parameters are only set to defaults if not set.
* So setting them in .zshrc will not be enough to load the
* module. It's useless until the watch array is set anyway. */
if (!paramtab->getnode(paramtab, "WATCHFMT"))
setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt));
if (!paramtab->getnode(paramtab, "LOGCHECK"))
setiparam("LOGCHECK", 60);
addprepromptfn(&checksched);
return 0;
}
/**/
int
cleanup_(Module m)
{
delprepromptfn(&checksched);
return setfeatureenables(m, &module_features, NULL);
}
/**/
int
finish_(UNUSED(Module m))
{
return 0;
}

7
Src/Modules/watch.mdd Normal file
View file

@ -0,0 +1,7 @@
name=zsh/watch
link=dynamic
load=yes
autofeatures="b:log p:WATCH p:watch"
objects="watch.o"

View file

@ -89,7 +89,6 @@ static struct builtin builtins[] =
BUILTIN("kill", BINF_HANDLES_OPTS, bin_kill, 0, -1, 0, NULL, NULL),
BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lp:%rtux", NULL),
BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
#if defined(ZSH_MEM) & defined(ZSH_MEM_DEBUG)

View file

@ -1042,7 +1042,6 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
#endif /* FPATH_NEEDS_INIT */
mailpath = mkarray(NULL);
watch = mkarray(NULL);
psvar = mkarray(NULL);
module_path = mkarray(ztrdup(MODULE_DIR));
modulestab = newmoduletable(17, "modules");

View file

@ -63,7 +63,6 @@ char **pparams, /* $argv */
**mailpath, /* $mailpath */
**manpath, /* $manpath */
**psvar, /* $psvar */
**watch, /* $watch */
**zsh_eval_context; /* $zsh_eval_context */
/**/
mod_export
@ -194,6 +193,10 @@ mod_export const struct gsu_hash stdhash_gsu =
mod_export const struct gsu_hash nullsethash_gsu =
{ hashgetfn, nullsethashfn, nullunsetfn };
/**/
mod_export const struct gsu_scalar colonarr_gsu =
{ colonarrgetfn, colonarrsetfn, stdunsetfn };
/* Non standard methods (not exported) */
static const struct gsu_integer pound_gsu =
@ -259,9 +262,6 @@ static const struct gsu_integer varint_readonly_gsu =
static const struct gsu_integer zlevar_gsu =
{ intvargetfn, zlevarsetfn, stdunsetfn };
static const struct gsu_scalar colonarr_gsu =
{ colonarrgetfn, colonarrsetfn, stdunsetfn };
static const struct gsu_integer argc_gsu =
{ poundgetfn, nullintsetfn, stdunsetfn };
static const struct gsu_array pipestatus_gsu =
@ -398,7 +398,6 @@ IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED),
IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED),
IPDEF8("FPATH", &fpath, "fpath", PM_TIED),
IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED),
IPDEF8("WATCH", &watch, "watch", PM_TIED),
IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED),
IPDEF8("PSVAR", &psvar, "psvar", PM_TIED),
IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED),
@ -430,7 +429,6 @@ IPDEF9("fpath", &fpath, "FPATH", PM_TIED),
IPDEF9("mailpath", &mailpath, "MAILPATH", PM_TIED),
IPDEF9("manpath", &manpath, "MANPATH", PM_TIED),
IPDEF9("psvar", &psvar, "PSVAR", PM_TIED),
IPDEF9("watch", &watch, "WATCH", PM_TIED),
IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL),
@ -453,7 +451,6 @@ IPDEF8("CDPATH", &cdpath, NULL, 0),
IPDEF8("FIGNORE", &fignore, NULL, 0),
IPDEF8("FPATH", &fpath, NULL, 0),
IPDEF8("MAILPATH", &mailpath, NULL, 0),
IPDEF8("WATCH", &watch, NULL, 0),
IPDEF8("PATH", &path, NULL, PM_RESTRICTED),
IPDEF8("PSVAR", &psvar, NULL, 0),
IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL),
@ -836,7 +833,6 @@ createparamtable(void)
*/
setsparam("TMPPREFIX", ztrdup_metafy(DEFAULT_TMPPREFIX));
setsparam("TIMEFMT", ztrdup_metafy(DEFAULT_TIMEFMT));
setsparam("WATCHFMT", ztrdup_metafy(default_watchfmt));
hostnam = (char *)zalloc(256);
gethostname(hostnam, 256);
@ -4093,7 +4089,7 @@ arrvarsetfn(Param pm, char **x)
}
/**/
char *
mod_export char *
colonarrgetfn(Param pm)
{
char ***dptr = (char ***)pm->u.data;
@ -4101,7 +4097,7 @@ colonarrgetfn(Param pm)
}
/**/
void
mod_export void
colonarrsetfn(Param pm, char *x)
{
char ***dptr = (char ***)pm->u.data;

View file

@ -1494,11 +1494,6 @@ deltimedfn(voidvoidfnptr_t func)
/**/
time_t lastmailcheck;
/* the last time we checked the people in the WATCH variable */
/**/
time_t lastwatch;
/*
* Call a function given by "name" with optional arguments
* "lnklst". If these are present the first argument is the function name.
@ -1637,17 +1632,6 @@ preprompt(void)
if (errflag)
return;
/* If WATCH is set, then check for the *
* specified login/logout events. */
if (watch) {
if ((int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK")) {
dowatch();
lastwatch = time(NULL);
}
}
if (errflag)
return;
/* Check mail */
currentmailcheck = time(NULL);
if (mailcheck &&

View file

@ -13,7 +13,7 @@ objects="builtin.o compat.o cond.o context.o \
exec.o glob.o hashtable.o hashnameddir.o \
hist.o init.o input.o jobs.o lex.o linklist.o loop.o math.o \
mem.o module.o options.o params.o parse.o pattern.o prompt.o signals.o \
signames.o sort.o string.o subst.o text.o utils.o watch.o \
signames.o sort.o string.o subst.o text.o utils.o \
openssh_bsd_setres_id.o"
headers="../config.h zsh_system.h zsh.h sigcount.h signals.h \