From 66ee4918a1540ae3baf8077c216a2b36ccba76f4 Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Thu, 9 Apr 2020 21:46:20 +0100
Subject: 45660: Fix crash setting vi or emacs mode on command line.
Delay setting the option until the module system is set up.
---
Src/init.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)
(limited to 'Src/init.c')
diff --git a/Src/init.c b/Src/init.c
index 04a5856ff..3d6c94d04 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -248,7 +248,8 @@ static int restricted;
/**/
static void
-parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr)
+parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr,
+ int *needkeymap)
{
char **x;
LinkList paramlist;
@@ -265,7 +266,7 @@ parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr)
* matched by code at the end of the present function.
*/
- if (parseopts(zsh_name, &argv, opts, cmdptr, NULL, flags))
+ if (parseopts(zsh_name, &argv, opts, cmdptr, NULL, flags, needkeymap))
exit(1);
/*
@@ -376,7 +377,7 @@ static void parseopts_setemulate(char *nam, int flags)
/**/
mod_export int
parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
- LinkList optlist, int flags)
+ LinkList optlist, int flags, int *needkeymap)
{
int optionbreak = 0;
int action, optno;
@@ -482,8 +483,14 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
return 1;
} else if (optno == RESTRICTED && toplevel) {
restricted = action;
- } else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) {
- WARN_OPTION("can't change option: %s", *argv);
+ } else if ((optno == EMACSMODE || optno == VIMODE)
+ && (!toplevel || needkeymap)){
+ if (!toplevel) {
+ WARN_OPTION("can't change option: %s", *argv);
+ } else {
+ /* Need to wait for modules to be loadable */
+ *needkeymap = optno;
+ }
} else {
if (dosetopt(optno, action, toplevel, new_opts) &&
!toplevel) {
@@ -1707,7 +1714,7 @@ zsh_main(UNUSED(int argc), char **argv)
{
char **t, *runscript = NULL, *zsh_name;
char *cmd; /* argument to -c */
- int t0;
+ int t0, needkeymap = 0;
#ifdef USE_LOCALE
setlocale(LC_ALL, "");
#endif
@@ -1753,7 +1760,7 @@ zsh_main(UNUSED(int argc), char **argv)
createoptiontable();
/* sets emulation, LOGINSHELL, PRIVILEGED, ZLE, INTERACTIVE,
* SHINSTDIN and SINGLECOMMAND */
- parseargs(zsh_name, argv, &runscript, &cmd);
+ parseargs(zsh_name, argv, &runscript, &cmd, &needkeymap);
SHTTY = -1;
init_io(cmd);
@@ -1762,6 +1769,15 @@ zsh_main(UNUSED(int argc), char **argv)
init_signals();
init_bltinmods();
init_builtins();
+
+ if (needkeymap)
+ {
+ /* Saved for after module system initialisation */
+ zleentry(ZLE_CMD_SET_KEYMAP, needkeymap);
+ opts[needkeymap] = 1;
+ opts[needkeymap == EMACSMODE ? VIMODE : EMACSMODE] = 0;
+ }
+
run_init_scripts();
setupshin(runscript);
init_misc(cmd, zsh_name);
--
cgit v1.2.3
From e5cd2dd980302f328d232d933f646c3dc02828bf Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Fri, 27 Aug 2021 09:36:06 +0100
Subject: 49290: Replace stdio for buffered shell input.
The previous method allowed memory management to interact with signal
handlers, causing occasional crashes on some system.
Instead, use a simple pre-allocated buffer and raw system calls.
---
ChangeLog | 6 +++
Src/init.c | 14 +++----
Src/input.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 123 insertions(+), 19 deletions(-)
(limited to 'Src/init.c')
diff --git a/ChangeLog b/ChangeLog
index 458446401..dd7b630d0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2021-08-27 Peter Stephenson
+
+ * 49290: Src/init.c, Src/input.c: Replace stdio for buffered
+ shell input to avoid memory management interacting with signal
+ handlers.
+
2021-08-27 Oliver Kiddle
* Marlon: 49272: Completion/Base/Utility/_call_program:
diff --git a/Src/init.c b/Src/init.c
index 3d6c94d04..878a53a37 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1229,7 +1229,7 @@ setupshin(char *runscript)
/*
* Finish setting up SHIN and its relatives.
*/
- bshin = SHIN ? fdopen(SHIN, "r") : stdin;
+ shinbufalloc();
if (isset(SHINSTDIN) && !SHIN && unset(INTERACTIVE)) {
#ifdef _IONBF
setvbuf(stdin, NULL, _IONBF, 0);
@@ -1384,9 +1384,9 @@ init_misc(char *cmd, char *zsh_name)
dosetopt(RESTRICTED, 1, 0, opts);
if (cmd) {
if (SHIN >= 10)
- fclose(bshin);
+ close(SHIN);
SHIN = movefd(open("/dev/null", O_RDONLY | O_NOCTTY));
- bshin = fdopen(SHIN, "r");
+ shinbufreset();
execstring(cmd, 0, 1, "cmdarg");
stopmsg = 1;
zexit((exit_pending || shell_exiting) ? exit_val : lastval, ZEXIT_NORMAL);
@@ -1409,7 +1409,6 @@ source(char *s)
int tempfd = -1, fd, cj;
zlong oldlineno;
int oldshst, osubsh, oloops;
- FILE *obshin;
char *old_scriptname = scriptname, *us;
char *old_scriptfilename = scriptfilename;
unsigned char *ocs;
@@ -1426,7 +1425,6 @@ source(char *s)
/* save the current shell state */
fd = SHIN; /* store the shell input fd */
- obshin = bshin; /* store file handle for buffered shell input */
osubsh = subsh; /* store whether we are in a subshell */
cj = thisjob; /* store our current job number */
oldlineno = lineno; /* store our current lineno */
@@ -1439,7 +1437,7 @@ source(char *s)
if (!prog) {
SHIN = tempfd;
- bshin = fdopen(SHIN, "r");
+ shinbufsave();
}
subsh = 0;
lineno = 1;
@@ -1507,10 +1505,10 @@ source(char *s)
if (prog)
freeeprog(prog);
else {
- fclose(bshin);
+ close(SHIN);
fdtable[SHIN] = FDT_UNUSED;
SHIN = fd; /* the shell input fd */
- bshin = obshin; /* file handle for buffered shell input */
+ shinbufrestore();
}
subsh = osubsh; /* whether we are in a subshell */
thisjob = cj; /* current job number */
diff --git a/Src/input.c b/Src/input.c
index f568cc135..3c6ad7002 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -80,11 +80,6 @@
/**/
int SHIN;
-/* buffered shell input for non-interactive shells */
-
-/**/
-FILE *bshin;
-
/* != 0 means we are reading input from a string */
/**/
@@ -129,7 +124,116 @@ static struct instacks *instack, *instacktop;
static int instacksz = INSTACK_INITIAL;
-/* Read a line from bshin. Convert tokens and *
+/* Size of buffer for non-interactive command input */
+
+#define SHINBUFSIZE 8192
+
+/* Input buffer for non-interactive command input */
+static char *shinbuffer;
+
+/* Pointer into shinbuffer */
+static char *shinbufptr;
+
+/* End of contents read into shinbuffer */
+static char *shinbufendptr;
+
+/* Entry on SHIN buffer save stack */
+struct shinsaveentry {
+ /* Next entry on stack */
+ struct shinsaveentry *next;
+ /* Saved shinbuffer */
+ char *buffer;
+ /* Saved shinbufptr */
+ char *ptr;
+ /* Saved shinbufendptr */
+ char *endptr;
+};
+
+/* SHIN buffer save stack */
+struct shinsaveentry *shinsavestack;
+
+/* Reset the input buffer for SHIN, discarding any pending input */
+
+/**/
+void
+shinbufreset(void)
+{
+ shinbufendptr = shinbufptr = shinbuffer;
+}
+
+/* Allocate a new shinbuffer
+ *
+ * Only called at shell initialisation and when saving on the stack.
+ */
+
+/**/
+void
+shinbufalloc(void)
+{
+ shinbuffer = zalloc(SHINBUFSIZE);
+ shinbufreset();
+}
+
+/* Save entry on SHIN buffer save stack */
+
+/**/
+void
+shinbufsave(void)
+{
+ struct shinsaveentry *entry =
+ (struct shinsaveentry *)zalloc(sizeof(struct shinsaveentry));
+
+ entry->next = shinsavestack;
+ entry->buffer = shinbuffer;
+ entry->ptr = shinbufptr;
+ entry->endptr = shinbufendptr;
+
+ shinsavestack = entry;
+
+ shinbufalloc();
+}
+
+/* Restore entry from SHIN buffer save stack */
+
+/**/
+void
+shinbufrestore(void)
+{
+ struct shinsaveentry *entry = shinsavestack;
+
+ zfree(shinbuffer, SHINBUFSIZE);
+
+ shinbuffer = entry->buffer;
+ shinbufptr = entry->ptr;
+ shinbufendptr = entry->endptr;
+
+ shinsavestack = entry->next;
+ zfree(entry, sizeof(struct shinsaveentry));
+}
+
+/* Get a character from SHIN, -1 if none available */
+
+/**/
+static int
+shingetchar(void)
+{
+ int nread;
+
+ if (shinbufptr < shinbufendptr)
+ return STOUC(*shinbufptr++);
+
+ shinbufreset();
+ do {
+ errno = 0;
+ nread = read(SHIN, shinbuffer, SHINBUFSIZE);
+ } while (nread < 0 && errno == EINTR);
+ if (nread <= 0)
+ return -1;
+ shinbufendptr = shinbuffer + nread;
+ return STOUC(*shinbufptr++);
+}
+
+/* Read a line from SHIN. Convert tokens and *
* null characters to Meta c^32 character pairs. */
/**/
@@ -147,11 +251,7 @@ shingetline(void)
winch_unblock();
dont_queue_signals();
for (;;) {
- /* Can't fgets() here because we need to accept '\0' bytes */
- do {
- errno = 0;
- c = fgetc(bshin);
- } while (c < 0 && errno == EINTR);
+ c = shingetchar();
if (c < 0 || c == '\n') {
winch_block();
restore_queue_signals(q);
--
cgit v1.2.3
From 271cfc685b17938e67a8212f2df78c32989411d7 Mon Sep 17 00:00:00 2001
From: Oliver Kiddle
Date: Tue, 2 Nov 2021 21:39:52 +0100
Subject: 49534, 49539: separate watch/log functionality out into a module
---
ChangeLog | 6 +
Doc/Makefile.in | 1 +
Doc/Zsh/builtins.yo | 8 -
Doc/Zsh/compat.yo | 3 +-
Doc/Zsh/mod_watch.yo | 140 ++++++++++
Doc/Zsh/params.yo | 118 ---------
Src/Modules/watch.c | 716 ++++++++++++++++++++++++++++++++++++++++++++++++++
Src/Modules/watch.mdd | 7 +
Src/builtin.c | 1 -
Src/init.c | 1 -
Src/params.c | 16 +-
Src/utils.c | 16 --
Src/watch.c | 626 -------------------------------------------
Src/zsh.mdd | 2 +-
14 files changed, 878 insertions(+), 783 deletions(-)
create mode 100644 Doc/Zsh/mod_watch.yo
create mode 100644 Src/Modules/watch.c
create mode 100644 Src/Modules/watch.mdd
delete mode 100644 Src/watch.c
(limited to 'Src/init.c')
diff --git a/ChangeLog b/ChangeLog
index 5179555ca..00c0d5be6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2021-11-02 Oliver Kiddle
+ * 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
diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index 5a6a705ff..23e5fc7e2 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -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
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index ddbcd4363..733d8f185 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -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.
diff --git a/Doc/Zsh/compat.yo b/Doc/Zsh/compat.yo
index 6e4dbcfa4..4d3567d45 100644
--- a/Doc/Zsh/compat.yo
+++ b/Doc/Zsh/compat.yo
@@ -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
diff --git a/Doc/Zsh/mod_watch.yo b/Doc/Zsh/mod_watch.yo
new file mode 100644
index 000000000..4eea89e23
--- /dev/null
+++ b/Doc/Zsh/mod_watch.yo
@@ -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) (tt(WATCH) ))(
+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()
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index a88e44d4f..1f2f01f55 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -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) (tt(WATCH) ))(
-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) )(
A list of non-alphanumeric characters considered part of a word
diff --git a/Src/Modules/watch.c b/Src/Modules/watch.c
new file mode 100644
index 000000000..02f0562fc
--- /dev/null
+++ b/Src/Modules/watch.c
@@ -0,0 +1,716 @@
+/*
+ * 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 "watch.mdh"
+
+/* Headers for utmp/utmpx structures */
+#ifdef HAVE_UTMP_H
+# include
+#endif
+#ifdef HAVE_UTMPX_H
+# include
+#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 */
+
+#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;
+
+/* 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)
+{
+ 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);
+ 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();
+}
+
+/**/
+static 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 */
+
+static void
+checksched(void)
+{
+}
+
+/**/
+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;
+}
diff --git a/Src/Modules/watch.mdd b/Src/Modules/watch.mdd
new file mode 100644
index 000000000..7e8454ede
--- /dev/null
+++ b/Src/Modules/watch.mdd
@@ -0,0 +1,7 @@
+name=zsh/watch
+link=dynamic
+load=yes
+
+autofeatures="b:log p:WATCH p:watch"
+
+objects="watch.o"
diff --git a/Src/builtin.c b/Src/builtin.c
index 89bcd98db..8ef678b22 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -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)
diff --git a/Src/init.c b/Src/init.c
index 878a53a37..871d46b12 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -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");
diff --git a/Src/params.c b/Src/params.c
index b703a97ce..dadf83129 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -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;
diff --git a/Src/utils.c b/Src/utils.c
index ed3690172..8adab2bd7 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -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 &&
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
-#endif
-#ifdef HAVE_UTMPX_H
-# include
-#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 */
diff --git a/Src/zsh.mdd b/Src/zsh.mdd
index 9bcaccae5..da8d58322 100644
--- a/Src/zsh.mdd
+++ b/Src/zsh.mdd
@@ -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 \
--
cgit v1.2.3