diff options
Diffstat (limited to 'Src/Modules')
-rw-r--r-- | Src/Modules/curses.c | 48 | ||||
-rw-r--r-- | Src/Modules/datetime.c | 2 | ||||
-rw-r--r-- | Src/Modules/files.c | 16 | ||||
-rw-r--r-- | Src/Modules/parameter.c | 139 | ||||
-rw-r--r-- | Src/Modules/termcap.c | 23 | ||||
-rw-r--r-- | Src/Modules/zftp.c | 1 | ||||
-rw-r--r-- | Src/Modules/zpty.c | 4 | ||||
-rw-r--r-- | Src/Modules/zutil.c | 71 |
8 files changed, 262 insertions, 42 deletions
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c index 29e088c70..41ad2c6e4 100644 --- a/Src/Modules/curses.c +++ b/Src/Modules/curses.c @@ -1069,8 +1069,47 @@ zccmd_input(const char *nam, char **args) } #endif + /* + * Some documentation for wgetch() says: + + The behavior of getch and friends in the presence of handled signals + is unspecified in the SVr4 and XSI Curses documentation. Under his- + torical curses implementations, it varied depending on whether the + operating system's implementation of handled signal receipt interrupts + a read(2) call in progress or not, and also (in some implementations) + depending on whether an input timeout or non-blocking mode has been + set. + + Programmers concerned about portability should be prepared for either + of two cases: (a) signal receipt does not interrupt getch; (b) signal + receipt interrupts getch and causes it to return ERR with errno set to + EINTR. Under the ncurses implementation, handled signals never inter- + rupt getch. + + * The observed behavior, however, is different: wgetch() consistently + * returns ERR with EINTR when a signal is handled by the shell "trap" + * command mechanism. Further, it consistently returns ERR twice, the + * second time without even attempting to repeat the interrupted read, + * which has the side-effect of NOT updating errno. A third call will + * then begin reading again. + * + * Therefore, to properly implement signal trapping, we must (1) call + * wgetch() in a loop as long as errno remains EINTR, and (2) clear + * errno only before beginning the loop, not on every pass. + * + * There remains a potential bug here in that, if the caller has set + * a timeout for the read [see zccmd_timeout()] the countdown is very + * likely restarted on every call to wgetch(), so an interrupted call + * might wait much longer than desired. + */ + errno = 0; + #ifdef HAVE_WGET_WCH - switch (wget_wch(w->win, &wi)) { + while ((ret = wget_wch(w->win, &wi)) == ERR) { + if (errno != EINTR || errflag || retflag || breaks || exit_pending) + break; + } + switch (ret) { case OK: ret = wctomb(instr, (wchar_t)wi); if (ret == 0) { @@ -1092,9 +1131,10 @@ zccmd_input(const char *nam, char **args) return 1; } #else - ci = wgetch(w->win); - if (ci == ERR) - return 1; + while ((ci = wgetch(w->win)) == ERR) { + if (errno != EINTR || errflag || retflag || breaks || exit_pending) + return 1; + } if (ci >= 256) { keypadnum = ci; *instr = '\0'; diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index 0dc42fda8..45818b968 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -146,7 +146,7 @@ bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) } static zlong -getcurrentsecs() +getcurrentsecs(UNUSED(Param pm)) { return (zlong) time(NULL); } diff --git a/Src/Modules/files.c b/Src/Modules/files.c index 3fbccf576..f86b9c1e9 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -195,7 +195,7 @@ bin_rmdir(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) static int bin_ln(char *nam, char **args, Options ops, int func) { - MoveFunc move; + MoveFunc movefn; int flags, have_dir, err = 0; char **a, *ptr, *rp, *buf; struct stat st; @@ -203,7 +203,7 @@ bin_ln(char *nam, char **args, Options ops, int func) if(func == BIN_MV) { - move = (MoveFunc) rename; + movefn = (MoveFunc) rename; flags = OPT_ISSET(ops,'f') ? 0 : MV_ASKNW; flags |= MV_ATOMIC; } else { @@ -212,11 +212,11 @@ bin_ln(char *nam, char **args, Options ops, int func) if(OPT_ISSET(ops,'h') || OPT_ISSET(ops,'n')) flags |= MV_NOCHASETARGET; if(OPT_ISSET(ops,'s')) - move = (MoveFunc) symlink; + movefn = (MoveFunc) symlink; else #endif { - move = (MoveFunc) link; + movefn = (MoveFunc) link; if(!OPT_ISSET(ops,'d')) flags |= MV_NODIRS; } @@ -267,7 +267,7 @@ bin_ln(char *nam, char **args, Options ops, int func) else args[1] = args[0]; } - return domove(nam, move, args[0], args[1], flags); + return domove(nam, movefn, args[0], args[1], flags); havedir: buf = ztrdup(*a); *a = NULL; @@ -283,7 +283,7 @@ bin_ln(char *nam, char **args, Options ops, int func) buf[blen] = 0; buf = appstr(buf, ptr); - err |= domove(nam, move, *args, buf, flags); + err |= domove(nam, movefn, *args, buf, flags); } zsfree(buf); return err; @@ -291,7 +291,7 @@ bin_ln(char *nam, char **args, Options ops, int func) /**/ static int -domove(char *nam, MoveFunc move, char *p, char *q, int flags) +domove(char *nam, MoveFunc movefn, char *p, char *q, int flags) { struct stat st; char *pbuf, *qbuf; @@ -341,7 +341,7 @@ domove(char *nam, MoveFunc move, char *p, char *q, int flags) if(doit && !(flags & MV_ATOMIC)) unlink(qbuf); } - if(move(pbuf, qbuf)) { + if(movefn(pbuf, qbuf)) { zwarnnam(nam, "%s: %e", p, errno); zsfree(pbuf); return 1; diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 793249f32..092efa0c3 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -1820,6 +1820,141 @@ scanpmdissaliases(HashTable ht, ScanFunc func, int flags) scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED); } + +/* Functions for the usergroups special parameter */ + +/* + * Get GID and names for groups of which the current user is a member. + */ + +/**/ +static Groupset get_all_groups(void) +{ + Groupset gs = zhalloc(sizeof(*gs)); + Groupmap gaptr; + gid_t *list, *lptr, egid; + int add_egid; + struct group *grptr; + + egid = getegid(); + add_egid = 1; + gs->num = getgroups(0, NULL); + if (gs->num > 0) { + list = zhalloc(gs->num * sizeof(*list)); + if (getgroups(gs->num, list) < 0) { + return NULL; + } + + /* + * It's unspecified whether $EGID is included in the + * group set, so check. + */ + for (lptr = list; lptr < list + gs->num; lptr++) { + if (*lptr == egid) { + add_egid = 0; + break; + } + } + gs->array = zhalloc((gs->num + add_egid) * sizeof(*gs->array)); + /* Put EGID if needed first */ + gaptr = gs->array + add_egid; + for (lptr = list; lptr < list + gs->num; lptr++) { + gaptr->gid = *lptr; + gaptr++; + } + gs->num += add_egid; + } else { + /* Just use effective GID */ + gs->num = 1; + gs->array = zhalloc(sizeof(*gs->array)); + } + if (add_egid) { + gs->array->gid = egid; + } + + /* Get group names */ + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + grptr = getgrgid(gaptr->gid); + if (!grptr) { + return NULL; + } + gaptr->name = dupstring(grptr->gr_name); + } + + return gs; +} + +/* Standard hash element lookup. */ + +/**/ +static HashNode +getpmusergroups(UNUSED(HashTable ht), const char *name) +{ + Param pm = NULL; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + pm = (Param)hcalloc(sizeof(struct param)); + pm->node.nam = dupstring(name); + pm->node.flags = PM_SCALAR | PM_READONLY; + pm->gsu.s = &nullsetscalar_gsu; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; + } + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + if (!strcmp(name, gaptr->name)) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm->u.str = dupstring(buf); + return &pm->node; + } + } + + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; +} + +/* Standard hash scan. */ + +/**/ +static void +scanpmusergroups(UNUSED(HashTable ht), ScanFunc func, int flags) +{ + struct param pm; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + return; + } + + memset((void *)&pm, 0, sizeof(pm)); + pm.node.flags = PM_SCALAR | PM_READONLY; + pm.gsu.s = &nullsetscalar_gsu; + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + pm.node.nam = gaptr->name; + if (func != scancountparams && + ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) || + !(flags & SCANPM_WANTKEYS))) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm.u.str = dupstring(buf); + } + func(&pm.node, flags); + } +} + + /* Table for defined parameters. */ struct pardef { @@ -1926,7 +2061,9 @@ static struct paramdef partab[] = { SPECIALPMDEF("saliases", 0, &pmsaliases_gsu, getpmsalias, scanpmsaliases), SPECIALPMDEF("userdirs", PM_READONLY, - NULL, getpmuserdir, scanpmuserdirs) + NULL, getpmuserdir, scanpmuserdirs), + SPECIALPMDEF("usergroups", PM_READONLY, + NULL, getpmusergroups, scanpmusergroups) }; static struct features module_features = { diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c index 7367dade7..cd0e85885 100644 --- a/Src/Modules/termcap.c +++ b/Src/Modules/termcap.c @@ -35,34 +35,11 @@ */ #include "../../config.h" -#ifdef HAVE_TGETENT -# if defined(ZSH_HAVE_CURSES_H) && defined(ZSH_HAVE_TERM_H) -# define USES_TERM_H 1 -# else -# ifdef HAVE_TERMCAP_H -# define USES_TERMCAP_H 1 -# endif -# endif -#endif - #include "termcap.mdh" #include "termcap.pro" /**/ #ifdef HAVE_TGETENT -# ifdef USES_TERM_H -# ifdef HAVE_TERMIO_H -# include <termio.h> -# endif -# ifdef ZSH_HAVE_CURSES_H -# include "../zshcurses.h" -# endif -# include "../zshterm.h" -# else -# ifdef USES_TERMCAP_H -# include <termcap.h> -# endif -# endif #ifndef HAVE_BOOLCODES static char *boolcodes[] = { diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 1558d354f..8d688abd4 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -50,6 +50,7 @@ struct zftp_session; typedef struct zftp_session *Zftp_session; #include "tcp.h" +#include "tcp.mdh" #include "zftp.mdh" #include "zftp.pro" diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 2a81e68cb..25ec7dfea 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -351,8 +351,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) struct ttyinfo info; if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) { - info.winsize.ws_row = lines; - info.winsize.ws_col = columns; + info.winsize.ws_row = zterm_lines; + info.winsize.ws_col = zterm_columns; ioctl(slave, TIOCSWINSZ, (char *) &info.winsize); } } diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 3c71edfa7..399c45f46 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1405,6 +1405,8 @@ struct zoptdesc { #define ZOF_OPT 2 #define ZOF_MULT 4 #define ZOF_SAME 8 +#define ZOF_MAP 16 +#define ZOF_CYC 32 struct zoptarr { Zoptarr next; @@ -1459,6 +1461,34 @@ get_opt_arr(char *name) return NULL; } +static Zoptdesc +map_opt_desc(Zoptdesc start) +{ + Zoptdesc map = NULL; + + if (!start || !(start->flags & ZOF_MAP)) + return start; + + map = get_opt_desc(start->arr->name); + + if (!map) + return start; + + if (map == start) { + start->flags &= ~ZOF_MAP; /* optimize */ + return start; + } + + if (map->flags & ZOF_CYC) + return NULL; + + start->flags |= ZOF_CYC; + map = map_opt_desc(map); + start->flags &= ~ZOF_CYC; + + return map; +} + static void add_opt_val(Zoptdesc d, char *arg) { @@ -1466,6 +1496,10 @@ add_opt_val(Zoptdesc d, char *arg) char *n = dyncat("-", d->name); int new = 0; + Zoptdesc map = map_opt_desc(d); + if (map) + d = map; + if (!(d->flags & ZOF_MULT)) v = d->vals; if (!v) { @@ -1513,7 +1547,7 @@ static int bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; - int del = 0, f, extract = 0, keep = 0; + int del = 0, flags = 0, extract = 0, keep = 0; Zoptdesc sopts[256], d; Zoptarr a, defarr = NULL; Zoptval v; @@ -1531,6 +1565,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) case '-': if (o[2]) args--; + /* else unreachable, default parsing removes "--" */ o = NULL; break; case 'D': @@ -1557,6 +1592,14 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } keep = 1; break; + case 'M': + if (o[2]) { + args--; + o = NULL; + break; + } + flags |= ZOF_MAP; + break; case 'a': if (defarr) { zwarnnam(nam, "default array given more than once"); @@ -1578,6 +1621,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) opt_arrs = defarr; break; case 'A': + if (assoc) { + zwarnnam(nam, "associative array given more than once"); + return 1; + } if (o[2]) assoc = o + 2; else if (*args) @@ -1587,6 +1634,11 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } break; + default: + /* Anything else is an option description */ + args--; + o = NULL; + break; } if (!o) { o = ""; @@ -1602,11 +1654,11 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } while ((o = dupstring(*args++))) { + int f = 0; if (!*o) { zwarnnam(nam, "invalid option description: %s", o); return 1; } - f = 0; for (p = o; *p; p++) { if (*p == '\\' && p[1]) p++; @@ -1633,6 +1685,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) a = NULL; if (*p == '=') { *p++ = '\0'; + f |= flags; if (!(a = get_opt_arr(p))) { a = (Zoptarr) zhalloc(sizeof(*a)); a->name = p; @@ -1666,6 +1719,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) opt_descs = d; if (!o[1]) sopts[STOUC(*o)] = d; + if ((flags & ZOF_MAP) && !map_opt_desc(d)) { + zwarnnam(nam, "cyclic option mapping: %s", args[-1]); + return 1; + } } np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams); for (; (o = *pp); pp++) { @@ -1732,12 +1789,20 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) add_opt_val(d, NULL); } } + + if (flags & ZOF_MAP) { + for (d = opt_descs; d; d = d->next) + if (d->arr && !d->vals && (d->flags & ZOF_MAP)) { + if (d->arr->num == 0 && get_opt_desc(d->arr->name)) + d->arr->num = -1; /* this is not a real array */ + } + } if (extract && del) while (*pp) *cp++ = *pp++; for (a = opt_arrs; a; a = a->next) { - if (!keep || a->num) { + if (a->num >= 0 && (!keep || a->num)) { aval = (char **) zalloc((a->num + 1) * sizeof(char *)); for (ap = aval, v = a->vals; v; ap++, v = v->next) { if (v->str) |