int bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) { int action, optno, match = 0; /* With no arguments or options, display options. */ if (!*args) { scanhashtable(optiontab, 1, 0, OPT_ALIAS, optiontab->printnode, !isun); return 0; } /* loop through command line options (begins with "-" or "+") */ while (*args && (**args == '-' || **args == '+')) { action = (**args == '-') ^ isun; if(!args[0][1]) *args = "--"; while (*++*args) { if(**args == Meta) *++*args ^= 32; /* The pseudo-option `--' signifies the end of options. */ if (**args == '-') { args++; goto doneoptions; } else if (**args == 'o') { if (!*++*args) args++; if (!*args) { zwarnnam(nam, "string expected after -o"); inittyptab(); return 1; } if(!(optno = optlookup(*args))) zwarnnam(nam, "no such option: %s", *args); else if(dosetopt(optno, action, 0, opts)) zwarnnam(nam, "can't change option: %s", *args); break; } else if(**args == 'm') { match = 1; } else { if (!(optno = optlookupc(**args))) zwarnnam(nam, "bad option: -%c", **args); else if(dosetopt(optno, action, 0, opts)) zwarnnam(nam, "can't change option: -%c", **args); } } args++; } doneoptions: if (!match) { /* Not globbing the arguments -- arguments are simply option names. */ while (*args) { if(!(optno = optlookup(*args++))) zwarnnam(nam, "no such option: %s", args[-1]); else if(dosetopt(optno, !isun, 0, opts)) zwarnnam(nam, "can't change option: %s", args[-1]); } } else { /* Globbing option (-m) set. */ while (*args) { Patprog pprog; char *s, *t; t = s = dupstring(*args); while (*t) if (*t == '_') chuck(t); else { /* See comment in optlookup() */ if (*t >= 'A' && *t <= 'Z') *t = (*t - 'A') + 'a'; t++; } /* Expand the current arg. */ tokenize(s); if (!(pprog = patcompile(s, PAT_STATIC, NULL))) { zwarnnam(nam, "bad pattern: %s", *args); continue; } /* Loop over expansions. */ scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS, setoption, !isun); args++; } } inittyptab(); return 0; }
static int recursivecmd_dorec(struct recursivecmd const *reccmd, char *arg, char *rp, struct stat const *sp, struct dirsav *ds, int first) { char *fn; DIR *d; int err, err1; struct dirsav dsav; char *files = NULL; int fileslen = 0; err1 = reccmd->dirpre_func(arg, rp, sp, reccmd->magic); if(err1 & 2) return 2; err = -lchdir(rp, ds, !first); if (err) { if(!reccmd->opt_noerr) zwarnnam(reccmd->nam, "%s: %e", arg, errno); return err; } err = err1; init_dirsav(&dsav); d = opendir("."); if(!d) { if(!reccmd->opt_noerr) zwarnnam(reccmd->nam, "%s: %e", arg, errno); err = 1; } else { int arglen = strlen(arg) + 1; while (!errflag && (fn = zreaddir(d, 1))) { int l = strlen(fn) + 1; files = hrealloc(files, fileslen, fileslen + l); strcpy(files + fileslen, fn); fileslen += l; } closedir(d); for (fn = files; !errflag && !(err & 2) && fn < files + fileslen;) { int l = strlen(fn) + 1; VARARR(char, narg, arglen + l); strcpy(narg,arg); narg[arglen-1] = '/'; strcpy(narg + arglen, fn); unmetafy(fn, NULL); err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0); fn += l; } hrealloc(files, fileslen, 0); } zsfree(dsav.dirname); if (err & 2) return 2; if (restoredir(ds)) { if(!reccmd->opt_noerr) zwarnnam(reccmd->nam, "failed to return to previous directory: %e", errno); return 2; } return err | reccmd->dirpost_func(arg, rp, sp, reccmd->magic); }
static int bin_chown(char *nam, char **args, Options ops, int func) { struct chownmagic chm; char *uspec = ztrdup(*args), *p = uspec; char *end; chm.nam = nam; if(func == BIN_CHGRP) { chm.uid = -1; goto dogroup; } end = strchr(uspec, ':'); if(!end) end = strchr(uspec, '.'); if(end == uspec) { chm.uid = -1; p++; goto dogroup; } else { struct passwd *pwd; if(end) *end = 0; pwd = getpwnam(p); if(pwd) chm.uid = pwd->pw_uid; else { int err; chm.uid = getnumeric(p, &err); if(err) { zwarnnam(nam, "%s: no such user", p); free(uspec); return 1; } } if(end) { p = end+1; if(!*p) { if(!pwd && !(pwd = getpwuid(chm.uid))) { zwarnnam(nam, "%s: no such user", uspec); free(uspec); return 1; } chm.gid = pwd->pw_gid; } else if(p[0] == ':' && !p[1]) { chm.gid = -1; } else { struct group *grp; dogroup: grp = getgrnam(p); if(grp) chm.gid = grp->gr_gid; else { int err; chm.gid = getnumeric(p, &err); if(err) { zwarnnam(nam, "%s: no such group", p); free(uspec); return 1; } } } } else chm.gid = -1; } free(uspec); return recursivecmd(nam, 0, OPT_ISSET(ops,'R'), OPT_ISSET(ops,'s'), args + 1, OPT_ISSET(ops, 'h') ? chown_dolchown : chown_dochown, recurse_donothing, OPT_ISSET(ops, 'h') ? chown_dolchown : chown_dochown, &chm); }
static int newptycmd(char *nam, char *pname, char **args, int echo, int nblock) { Ptycmd p; int master, slave, pid, oineval = ineval, ret; char *oscriptname = scriptname, syncch; Eprog prog; /* code borrowed from bin_eval() */ ineval = !isset(EVALLINENO); if (!ineval) scriptname = "(zpty)"; prog = parse_string(zjoin(args, ' ', 1), 0); if (!prog) { errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; return 1; } if (get_pty(1, &master)) { zwarnnam(nam, "can't open pseudo terminal: %e", errno); scriptname = oscriptname; ineval = oineval; return 1; } if ((pid = fork()) == -1) { zwarnnam(nam, "can't create pty command %s: %e", pname, errno); close(master); scriptname = oscriptname; ineval = oineval; return 1; } else if (!pid) { /* This code copied from the clone module, except for getting * * the descriptor from get_pty() and duplicating it to 0/1/2. */ deletehookfunc("exit", ptyhook); clearjobtab(0); ppid = getppid(); mypid = getpid(); #ifdef HAVE_SETSID if (setsid() != mypid) { zwarnnam(nam, "failed to create new session: %e", errno); #endif #ifdef TIOCNOTTY if (ioctl(SHTTY, TIOCNOTTY, 0)) zwarnnam(nam, "%e", errno); setpgrp(0L, mypid); #endif #ifdef HAVE_SETSID } #endif if (get_pty(0, &slave)) exit(1); SHTTY = slave; attachtty(mypid); #ifdef TIOCGWINSZ /* Set the window size before associating with the terminal * * so that we don't get hit with a SIGWINCH. I'm paranoid. */ if (interact) { struct ttyinfo info; if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) { info.winsize.ws_row = zterm_lines; info.winsize.ws_col = zterm_columns; ioctl(slave, TIOCSWINSZ, (char *) &info.winsize); } } #endif /* TIOCGWINSZ */ if (!echo) { struct ttyinfo info; if (!ptygettyinfo(slave, &info)) { #ifdef HAVE_TERMIOS_H info.tio.c_lflag &= ~ECHO; #else #ifdef HAVE_TERMIO_H info.tio.c_lflag &= ~ECHO; #else info.tio.lmodes &= ~ECHO; /**** dunno if this is right */ #endif #endif ptysettyinfo(slave, &info); } } #ifdef TIOCSCTTY ioctl(slave, TIOCSCTTY, 0); #endif close(0); close(1); close(2); dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); closem(FDT_UNUSED, 0); close(slave); close(master); close(coprocin); close(coprocout); init_io(NULL); setsparam("TTY", ztrdup(ttystrname)); opts[INTERACTIVE] = 0; syncch = 0; do { ret = write(1, &syncch, 1); } while (ret != 1 && ( #ifdef EWOULDBLOCK errno == EWOULDBLOCK || #else #ifdef EAGAIN errno == EAGAIN || #endif #endif errno == EINTR)); execode(prog, 1, 0, "zpty"); stopmsg = 2; mypid = 0; /* trick to ensure we _exit() */ zexit(lastval, 0); } master = movefd(master); if (master == -1) { zerrnam(nam, "cannot duplicate fd %d: %e", master, errno); scriptname = oscriptname; ineval = oineval; return 1; } p = (Ptycmd) zalloc(sizeof(*p)); p->name = ztrdup(pname); p->args = zarrdup(args); p->fd = master; p->pid = pid; p->echo = echo; p->nblock = nblock; p->fin = 0; p->read = -1; p->old = NULL; p->olen = 0; p->next = ptycmds; ptycmds = p; if (nblock) ptynonblock(master); scriptname = oscriptname; ineval = oineval; do { ret = read(master, &syncch, 1); } while (ret != 1 && ( #ifdef EWOULDBLOCK errno == EWOULDBLOCK || #else #ifdef EAGAIN errno == EAGAIN || #endif #endif errno == EINTR)); setiparam_no_convert("REPLY", (zlong)master); return 0; }
static int recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe, char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func, RecurseFunc leaf_func, void *magic) { int err = 0, len; char *rp, *s; struct dirsav ds; struct recursivecmd reccmd; reccmd.nam = nam; reccmd.opt_noerr = opt_noerr; reccmd.opt_recurse = opt_recurse; reccmd.opt_safe = opt_safe; reccmd.dirpre_func = dirpre_func; reccmd.dirpost_func = dirpost_func; reccmd.leaf_func = leaf_func; reccmd.magic = magic; init_dirsav(&ds); if (opt_recurse || opt_safe) { if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 && zgetdir(&ds) && *ds.dirname != '/') ds.dirfd = open("..", O_RDONLY|O_NOCTTY); } for(; !errflag && !(err & 2) && *args; args++) { rp = ztrdup(*args); unmetafy(rp, &len); if (opt_safe) { s = strrchr(rp, '/'); if (s && !s[1]) { while (*s == '/' && s > rp) *s-- = '\0'; while (*s != '/' && s > rp) s--; } if (s && s[1]) { int e; *s = '\0'; e = lchdir(s > rp ? rp : "/", &ds, 1); err |= -e; if (!e) { struct dirsav d; d.ino = d.dev = 0; d.dirname = NULL; d.dirfd = d.level = -1; err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0); zsfree(d.dirname); if (restoredir(&ds)) err |= 2; } else if(!opt_noerr) zwarnnam(nam, "%s: %e", *args, errno); } else err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0); } else err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1); zfree(rp, len + 1); } if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) { zsfree(pwd); pwd = ztrdup("/"); if (chdir(pwd) < 0) zwarn("failed to chdir(%s): %e", pwd, errno); } if (ds.dirfd >= 0) close(ds.dirfd); zsfree(ds.dirname); return !!err; }
static int bin_vared(char *name, char **args, Options ops, UNUSED(int func)) { char *s, *t, *ova = varedarg; struct value vbuf; Value v; Param pm = 0; int ifl; int type = PM_SCALAR, obreaks = breaks, haso = 0, oSHTTY = 0; char *p1, *p2, *main_keymapname, *vicmd_keymapname, *init, *finish; Keymap main_keymapsave = NULL, vicmd_keymapsave = NULL; FILE *oshout = NULL; if ((interact && unset(USEZLE)) || !strcmp(term, "emacs")) { zwarnnam(name, "ZLE not enabled"); return 1; } if (zleactive) { zwarnnam(name, "ZLE cannot be used recursively (yet)"); return 1; } if (OPT_ISSET(ops,'A')) { if (OPT_ISSET(ops, 'a')) { zwarnnam(name, "specify only one of -a and -A"); return 1; } type = PM_HASHED; } else if (OPT_ISSET(ops,'a')) type = PM_ARRAY; p1 = OPT_ARG_SAFE(ops,'p'); p2 = OPT_ARG_SAFE(ops,'r'); main_keymapname = OPT_ARG_SAFE(ops,'M'); vicmd_keymapname = OPT_ARG_SAFE(ops,'m'); init = OPT_ARG_SAFE(ops,'i'); finish = OPT_ARG_SAFE(ops,'f'); if (type != PM_SCALAR && !OPT_ISSET(ops,'c')) { zwarnnam(name, "-%s ignored", type == PM_ARRAY ? "a" : "A"); } /* handle non-existent parameter */ s = args[0]; queue_signals(); v = fetchvalue(&vbuf, &s, (!OPT_ISSET(ops,'c') || type == PM_SCALAR), SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY); if (!v && !OPT_ISSET(ops,'c')) { unqueue_signals(); zwarnnam(name, "no such variable: %s", args[0]); return 1; } else if (v) { if (*s) { zwarnnam(name, "not an identifier: `%s'", args[0]); return 1; } if (v->isarr) { /* Array: check for separators and quote them. */ char **arr = getarrvalue(v), **aptr, **tmparr, **tptr; tptr = tmparr = (char **)zhalloc(sizeof(char *)*(arrlen(arr)+1)); for (aptr = arr; *aptr; aptr++) { int sepcount = 0, clen; convchar_t c; /* * See if this word contains a separator character * or backslash */ MB_METACHARINIT(); for (t = *aptr; *t; ) { if (*t == '\\') { t++; sepcount++; } else { t += MB_METACHARLENCONV(t, &c); if (WC_ZISTYPE(c, ISEP)) sepcount++; } } if (sepcount) { /* Yes, so allocate enough space to quote it. */ char *newstr, *nptr; newstr = zhalloc(strlen(*aptr)+sepcount+1); /* Go through string quoting separators */ MB_METACHARINIT(); for (t = *aptr, nptr = newstr; *t; ) { if (*t == '\\') { *nptr++ = '\\'; *nptr++ = *t++; } else { clen = MB_METACHARLENCONV(t, &c); if (WC_ZISTYPE(c, ISEP)) *nptr++ = '\\'; while (clen--) *nptr++ = *t++; } } *nptr = '\0'; /* Stick this into the array of words to join up */ *tptr++ = newstr; } else *tptr++ = *aptr; /* No, keep original array element */ } *tptr = NULL; s = sepjoin(tmparr, NULL, 0); } else { s = ztrdup(getstrvalue(v)); } unqueue_signals(); } else if (*s) { unqueue_signals(); zwarnnam(name, "invalid parameter name: %s", args[0]); return 1; } else { unqueue_signals(); s = ztrdup(s); } if (SHTTY == -1 || OPT_ISSET(ops,'t')) { /* need to open /dev/tty specially */ oSHTTY = SHTTY; if ((SHTTY = open(OPT_ISSET(ops,'t') ? OPT_ARG(ops,'t') : "/dev/tty", O_RDWR|O_NOCTTY)) == -1) { zwarnnam(name, "can't access terminal"); zsfree(s); return 1; } if (!isatty(SHTTY)) { zwarnnam(name, "%s: not a terminal", OPT_ARG(ops,'t')); close(SHTTY); SHTTY = oSHTTY; zsfree(s); return 1; } oshout = shout; init_shout(); haso = 1; } /* edit the parameter value */ zpushnode(bufstack, s); if (main_keymapname && savekeymap(name, "main", main_keymapname, &main_keymapsave)) main_keymapname = NULL; if (vicmd_keymapname && savekeymap(name, "vicmd", vicmd_keymapname, &vicmd_keymapsave)) vicmd_keymapname = NULL; varedarg = *args; ifl = isfirstln; if (OPT_ISSET(ops,'h')) hbegin(2); isfirstln = OPT_ISSET(ops,'e'); t = zleread(&p1, &p2, OPT_ISSET(ops,'h') ? ZLRF_HISTORY : 0, ZLCON_VARED, init ? init : "zle-line-init", finish ? finish : "zle-line-finish"); if (OPT_ISSET(ops,'h')) hend(NULL); isfirstln = ifl; varedarg = ova; restorekeymap(name, "main", main_keymapname, main_keymapsave); restorekeymap(name, "vicmd", vicmd_keymapname, vicmd_keymapsave); if (haso) { fclose(shout); /* close(SHTTY) */ shout = oshout; SHTTY = oSHTTY; } if (!t || errflag) { /* error in editing */ errflag &= ~ERRFLAG_ERROR; breaks = obreaks; if (t) zsfree(t); return 1; } /* strip off trailing newline, if any */ if (t[strlen(t) - 1] == '\n') t[strlen(t) - 1] = '\0'; /* final assignment of parameter value */ if (OPT_ISSET(ops,'c')) { unsetparam(args[0]); createparam(args[0], type); } queue_signals(); pm = (Param) paramtab->getnode(paramtab, args[0]); if (pm && (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) { char **a; /* * Use spacesplit with fourth argument 1: identify quoted separators, * and unquote. This duplicates the string, so we still need to free. */ a = spacesplit(t, 1, 0, 1); zsfree(t); if (PM_TYPE(pm->node.flags) == PM_ARRAY) setaparam(args[0], a); else sethparam(args[0], a); } else setsparam(args[0], t); unqueue_signals(); return 0; }
static int bin_compset(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) { int test = 0, na = 0, nb = 0; char *sa = NULL, *sb = NULL; if (incompfunc != 1) { zwarnnam(name, "can only be called from completion function"); return 1; } if (argv[0][0] != '-') { zwarnnam(name, "missing option"); return 1; } switch (argv[0][1]) { case 'n': test = CVT_RANGENUM; break; case 'N': test = CVT_RANGEPAT; break; case 'p': test = CVT_PRENUM; break; case 'P': test = CVT_PREPAT; break; case 's': test = CVT_SUFNUM; break; case 'S': test = CVT_SUFPAT; break; case 'q': return set_comp_sep(); default: zwarnnam(name, "bad option -%c", argv[0][1]); return 1; } if (argv[0][2]) { sa = argv[0] + 2; sb = argv[1]; na = 2; } else { if (!(sa = argv[1])) { zwarnnam(name, "missing string for option -%c", argv[0][1]); return 1; } sb = argv[2]; na = 3; } if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb : (sb && argv[na]))) { zwarnnam(name, "too many arguments"); return 1; } switch (test) { case CVT_RANGENUM: na = atoi(sa); nb = (sb ? atoi(sb) : -1); break; case CVT_RANGEPAT: tokenize(sa); remnulargs(sa); if (sb) { tokenize(sb); remnulargs(sb); } break; case CVT_PRENUM: case CVT_SUFNUM: na = atoi(sa); break; case CVT_PREPAT: case CVT_SUFPAT: if (sb) { na = atoi(sa); sa = sb; } else na = -1; tokenize(sa); remnulargs(sa); break; } return !do_comp_vars(test, na, sa, nb, sb, 1); }
static int bin_sched(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func)) { char *s, **argptr; time_t t; long h, m, sec; struct tm *tm; struct schedcmd *sch, *sch2, *schl; int sn, flags = 0; /* If the argument begins with a -, remove the specified item from the schedule. */ for (argptr = argv; *argptr && **argptr == '-'; argptr++) { char *arg = *argptr + 1; if (idigit(*arg)) { sn = atoi(arg); if (!sn) { zwarnnam("sched", "usage for delete: sched -<item#>."); return 1; } for (schl = NULL, sch = schedcmds, sn--; sch && sn; sch = (schl = sch)->next, sn--); if (!sch) { zwarnnam("sched", "not that many entries"); return 1; } if (schl) schl->next = sch->next; else { scheddeltimed(); schedcmds = sch->next; if (schedcmds) { DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (2)"); schedaddtimed(schedcmds->time); } } zsfree(sch->cmd); zfree(sch, sizeof(struct schedcmd)); return 0; } else if (*arg == '-') { /* end of options */ argptr++; break; } else if (!strcmp(arg, "o")) { flags |= SCHEDFLAG_TRASH_ZLE; } else { if (*arg) zwarnnam(nam, "bad option: -%c", *arg); else zwarnnam(nam, "option expected"); return 1; } } /* given no arguments, display the schedule list */ if (!*argptr) { for (sn = 1, sch = schedcmds; sch; sch = sch->next, sn++) { char tbuf[60], *flagstr, *endstr; time_t t; struct tm *tmp; t = sch->time; tmp = localtime(&t); ztrftime(tbuf, 40, "%a %b %e %k:%M:%S", tmp, 0L); if (sch->flags & SCHEDFLAG_TRASH_ZLE) flagstr = "-o "; else flagstr = ""; if (*sch->cmd == '-') endstr = "-- "; else endstr = ""; printf("%3d %s %s%s%s\n", sn, tbuf, flagstr, endstr, sch->cmd); } return 0; } else if (!argptr[1]) { /* other than the two cases above, sched * *requires at least two arguments */ zwarnnam("sched", "not enough arguments"); return 1; } /* The first argument specifies the time to schedule the command for. The remaining arguments form the command. */ s = *argptr++; if (*s == '+') { /* * + introduces a relative time. The rest of the argument may be an * hour:minute offset from the current time. Once the hour and minute * numbers have been extracted, and the format verified, the resulting * offset is simply added to the current time. */ zlong zl = zstrtol(s + 1, &s, 10); if (*s == ':') { m = (long)zstrtol(s + 1, &s, 10); if (*s == ':') sec = (long)zstrtol(s + 1, &s, 10); else sec = 0; if (*s) { zwarnnam("sched", "bad time specifier"); return 1; } t = time(NULL) + (long)zl * 3600 + m * 60 + sec; } else if (!*s) { /* * Alternatively, it may simply be a number of seconds. * This is here for consistency with absolute times. */ t = time(NULL) + (time_t)zl; } else { zwarnnam("sched", "bad time specifier"); return 1; } } else { /* * If there is no +, an absolute time must have been given. * This may be in hour:minute format, optionally followed by a string * starting with `a' or `p' (for a.m. or p.m.). Characters after the * `a' or `p' are ignored. */ zlong zl = zstrtol(s, &s, 10); if (*s == ':') { h = (long)zl; m = (long)zstrtol(s + 1, &s, 10); if (*s == ':') sec = (long)zstrtol(s + 1, &s, 10); else sec = 0; if (*s && *s != 'a' && *s != 'A' && *s != 'p' && *s != 'P') { zwarnnam("sched", "bad time specifier"); return 1; } t = time(NULL); tm = localtime(&t); t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600; if (*s == 'p' || *s == 'P') h += 12; t += h * 3600 + m * 60 + sec; /* * If the specified time is before the current time, it must refer * to tomorrow. */ if (t < time(NULL)) t += 3600 * 24; } else if (!*s) { /* * Otherwise, it must be a raw time specifier. */ t = (long)zl; } else { zwarnnam("sched", "bad time specifier"); return 1; } } /* The time has been calculated; now add the new entry to the linked list of scheduled commands. */ sch = (struct schedcmd *) zalloc(sizeof *sch); sch->time = t; sch->cmd = zjoin(argptr, ' ', 0); sch->flags = flags; /* Insert into list in time order */ if (schedcmds) { if (sch->time < schedcmds->time) { scheddeltimed(); sch->next = schedcmds; schedcmds = sch; DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (3)"); schedaddtimed(t); } else { for (sch2 = schedcmds; sch2->next && sch2->next->time < sch->time; sch2 = sch2->next) ; sch->next = sch2->next; sch2->next = sch; } } else { sch->next = NULL; schedcmds = sch; DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (4)"); schedaddtimed(t); } return 0; }
static int bin_ztcp(char *nam, char **args, Options ops, UNUSED(int func)) { int herrno, err=1, destport, force=0, verbose=0, test=0, targetfd=0; ZSOCKLEN_T len; char **addrp, *desthost; const char *localname, *remotename; struct hostent *zthost = NULL, *ztpeer = NULL; struct servent *srv; Tcp_session sess = NULL; if (OPT_ISSET(ops,'f')) force = 1; if (OPT_ISSET(ops,'v')) verbose = 1; if (OPT_ISSET(ops,'t')) test = 1; if (OPT_ISSET(ops,'d')) { targetfd = atoi(OPT_ARG(ops,'d')); if (!targetfd) { zwarnnam(nam, "%s is an invalid argument to -d", OPT_ARG(ops,'d')); return 1; } } if (OPT_ISSET(ops,'c')) { if (!args[0]) { tcp_cleanup(); } else { targetfd = atoi(args[0]); sess = zts_byfd(targetfd); if(!targetfd) { zwarnnam(nam, "%s is an invalid argument to -c", args[0]); return 1; } if (sess) { if ((sess->flags & ZTCP_ZFTP) && !force) { zwarnnam(nam, "use -f to force closure of a zftp control connection"); return 1; } tcp_close(sess); return 0; } else { zwarnnam(nam, "fd %s not found in tcp table", args[0]); return 1; } } } else if (OPT_ISSET(ops,'l')) { int lport = 0; if (!args[0]) { zwarnnam(nam, "-l requires an argument"); return 1; } srv = getservbyname(args[0], "tcp"); if (srv) lport = srv->s_port; else lport = htons(atoi(args[0])); if (!lport) { zwarnnam(nam, "bad service name or port number"); return 1; } sess = tcp_socket(PF_INET, SOCK_STREAM, 0, ZTCP_LISTEN); if (!sess) { zwarnnam(nam, "unable to allocate a TCP session slot"); return 1; } #ifdef SO_OOBINLINE len = 1; setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len)); #endif if (!zsh_inet_aton("0.0.0.0", &(sess->sock.in.sin_addr))) { zwarnnam(nam, "bad address: %s", "0.0.0.0"); return 1; } sess->sock.in.sin_family = AF_INET; sess->sock.in.sin_port = lport; if (bind(sess->fd, (struct sockaddr *)&sess->sock.in, sizeof(struct sockaddr_in))) { char buf[DIGBUFSIZE]; convbase(buf, (zlong)ntohs(lport), 10); zwarnnam(nam, "could not bind to port %s: %e", buf, errno); tcp_close(sess); return 1; } if (listen(sess->fd, 1)) { zwarnnam(nam, "could not listen on socket: %e", errno); tcp_close(sess); return 1; } if (targetfd) { sess->fd = redup(sess->fd, targetfd); } else { /* move the fd since no one will want to read from it */ sess->fd = movefd(sess->fd); } if (sess->fd == -1) { zwarnnam(nam, "cannot duplicate fd %d: %e", sess->fd, errno); tcp_close(sess); return 1; } setiparam_no_convert("REPLY", (zlong)sess->fd); if (verbose) printf("%d listener is on fd %d\n", ntohs(sess->sock.in.sin_port), sess->fd); return 0; } else if (OPT_ISSET(ops,'a')) { int lfd, rfd; if (!args[0]) { zwarnnam(nam, "-a requires an argument"); return 1; } lfd = atoi(args[0]); if (!lfd) { zwarnnam(nam, "invalid numerical argument"); return 1; } sess = zts_byfd(lfd); if (!sess) { zwarnnam(nam, "fd %s is not registered as a tcp connection", args[0]); return 1; } if (!(sess->flags & ZTCP_LISTEN)) { zwarnnam(nam, "tcp connection not a listener"); return 1; } if (test) { #if defined(HAVE_POLL) || defined(HAVE_SELECT) # ifdef HAVE_POLL struct pollfd pfd; int ret; pfd.fd = lfd; pfd.events = POLLIN; if ((ret = poll(&pfd, 1, 0)) == 0) return 1; else if (ret == -1) { zwarnnam(nam, "poll error: %e", errno); return 1; } # else fd_set rfds; struct timeval tv; int ret; FD_ZERO(&rfds); FD_SET(lfd, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; if ((ret = select(lfd+1, &rfds, NULL, NULL, &tv)) == 0) return 1; else if (ret == -1) { zwarnnam(nam, "select error: %e", errno); return 1; } # endif #else zwarnnam(nam, "not currently supported"); return 1; #endif } sess = zts_alloc(ZTCP_INBOUND); len = sizeof(sess->peer.in); do { rfd = accept(lfd, (struct sockaddr *)&sess->peer.in, &len); } while (rfd < 0 && errno == EINTR && !errflag); if (rfd == -1) { zwarnnam(nam, "could not accept connection: %e", errno); tcp_close(sess); return 1; } /* redup expects fd is already registered */ addmodulefd(rfd, FDT_MODULE); if (targetfd) { sess->fd = redup(rfd, targetfd); if (sess->fd < 0) { zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); return 1; } } else { sess->fd = rfd; } setiparam_no_convert("REPLY", (zlong)sess->fd); if (verbose) printf("%d is on fd %d\n", ntohs(sess->peer.in.sin_port), sess->fd); } else { if (!args[0]) { LinkNode node; for(node = firstnode(ztcp_sessions); node; incnode(node)) { sess = (Tcp_session)getdata(node); if (sess->fd != -1) { zthost = gethostbyaddr((const void *)&(sess->sock.in.sin_addr), sizeof(sess->sock.in.sin_addr), AF_INET); if (zthost) localname = zthost->h_name; else localname = inet_ntoa(sess->sock.in.sin_addr); ztpeer = gethostbyaddr((const void *)&(sess->peer.in.sin_addr), sizeof(sess->peer.in.sin_addr), AF_INET); if (ztpeer) remotename = ztpeer->h_name; else remotename = inet_ntoa(sess->peer.in.sin_addr); if (OPT_ISSET(ops,'L')) { int schar; if (sess->flags & ZTCP_ZFTP) schar = 'Z'; else if (sess->flags & ZTCP_LISTEN) schar = 'L'; else if (sess->flags & ZTCP_INBOUND) schar = 'I'; else schar = 'O'; printf("%d %c %s %d %s %d\n", sess->fd, schar, localname, ntohs(sess->sock.in.sin_port), remotename, ntohs(sess->peer.in.sin_port)); } else { printf("%s:%d %s %s:%d is on fd %d%s\n", localname, ntohs(sess->sock.in.sin_port), ((sess->flags & ZTCP_LISTEN) ? "-<" : ((sess->flags & ZTCP_INBOUND) ? "<-" : "->")), remotename, ntohs(sess->peer.in.sin_port), sess->fd, (sess->flags & ZTCP_ZFTP) ? " ZFTP" : ""); } } } return 0; } else if (!args[1]) { destport = htons(23); } else { srv = getservbyname(args[1],"tcp"); if (srv) destport = srv->s_port; else destport = htons(atoi(args[1])); } desthost = ztrdup(args[0]); zthost = zsh_getipnodebyname(desthost, AF_INET, 0, &herrno); if (!zthost || errflag) { zwarnnam(nam, "host resolution failure: %s", desthost); zsfree(desthost); return 1; } sess = tcp_socket(PF_INET, SOCK_STREAM, 0, 0); if (!sess) { zwarnnam(nam, "unable to allocate a TCP session slot"); zsfree(desthost); return 1; } #ifdef SO_OOBINLINE len = 1; setsockopt(sess->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&len, sizeof(len)); #endif if (sess->fd < 0) { zwarnnam(nam, "socket creation failed: %e", errno); zsfree(desthost); zts_delete(sess); return 1; } for (addrp = zthost->h_addr_list; err && *addrp; addrp++) { if (zthost->h_length != 4) zwarnnam(nam, "address length mismatch"); do { err = tcp_connect(sess, *addrp, zthost, destport); } while (err && errno == EINTR && !errflag); } if (err) { zwarnnam(nam, "connection failed: %e", errno); tcp_close(sess); zsfree(desthost); return 1; } else { if (targetfd) { sess->fd = redup(sess->fd, targetfd); if (sess->fd < 0) { zerrnam(nam, "could not duplicate socket fd to %d: %e", targetfd, errno); zsfree(desthost); tcp_close(sess); return 1; } } setiparam_no_convert("REPLY", (zlong)sess->fd); if (verbose) printf("%s:%d is now on fd %d\n", desthost, destport, sess->fd); } zsfree(desthost); } return 0; }
static int bin_stat(char *name, char **args, Options ops, UNUSED(int func)) { char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL; char *hashnam = NULL, **hash = NULL, **hashptr = NULL; int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0; struct stat statbuf; int found = 0, nargs; timefmt = "%a %b %e %k:%M:%S %Z %Y"; for (; *args && (**args == '+' || **args == '-'); args++) { char *arg = *args+1; if (!*arg || *arg == '-' || *arg == '+') { args++; break; } if (**args == '+') { if (found) break; len = strlen(arg); for (aptr = statelts; *aptr; aptr++) if (!strncmp(*aptr, arg, len)) { found++; iwhich = aptr - statelts; } if (found > 1) { zwarnnam(name, "%s: ambiguous stat element", arg); return 1; } else if (found == 0) { zwarnnam(name, "%s: no such stat element", arg); return 1; } /* if name of link requested, turn on lstat */ if (iwhich == ST_READLINK) ops->ind['L'] = 1; flags |= STF_PICK; } else { for (; *arg; arg++) { if (strchr("glLnNorstT", *arg)) ops->ind[STOUC(*arg)] = 1; else if (*arg == 'A') { if (arg[1]) { arrnam = arg+1; } else if (!(arrnam = *++args)) { zwarnnam(name, "missing parameter name"); return 1; } flags |= STF_ARRAY; break; } else if (*arg == 'H') { if (arg[1]) { hashnam = arg+1; } else if (!(hashnam = *++args)) { zwarnnam(name, "missing parameter name"); return 1; } flags |= STF_HASH; break; } else if (*arg == 'f') { char *sfd; ops->ind['f'] = 1; if (arg[1]) { sfd = arg+1; } else if (!(sfd = *++args)) { zwarnnam(name, "missing file descriptor"); return 1; } fd = zstrtol(sfd, &sfd, 10); if (*sfd) { zwarnnam(name, "bad file descriptor"); return 1; } break; } else if (*arg == 'F') { if (arg[1]) { timefmt = arg+1; } else if (!(timefmt = *++args)) { zwarnnam(name, "missing time format"); return 1; } /* force string format in order to use time format */ ops->ind['s'] = 1; break; } else { zwarnnam(name, "bad option: -%c", *arg); return 1; } } } } if ((flags & STF_ARRAY) && (flags & STF_HASH)) { /* We don't implement setting multiple variables at once */ zwarnnam(name, "both array and hash requested"); return 1; /* Alternate method would be to make -H blank arrnam etc etc * * and so get 'silent loss' of earlier choice, which would * * be similar to stat -A foo -A bar filename */ } if (OPT_ISSET(ops,'l')) { /* list types and return: can also list to array */ if (arrnam) { arrptr = array = (char **)zalloc((ST_COUNT+1)*sizeof(char *)); array[ST_COUNT] = NULL; } for (aptr = statelts; *aptr; aptr++) { if (arrnam) { *arrptr++ = ztrdup(*aptr); } else { printf("%s", *aptr); if (aptr[1]) putchar(' '); } } if (arrnam) { setaparam(arrnam, array); if (errflag) return 1; } else putchar('\n'); return 0; } if (!*args && !OPT_ISSET(ops,'f')) { zwarnnam(name, "no files given"); return 1; } else if (*args && OPT_ISSET(ops,'f')) { zwarnnam(name, "no files allowed with -f"); return 1; } nargs = 0; if (OPT_ISSET(ops,'f')) nargs = 1; else for (aptr = args; *aptr; aptr++) nargs++; if (OPT_ISSET(ops,'g')) { flags |= STF_GMT; ops->ind['s'] = 1; } if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'r')) flags |= STF_STRING; if (OPT_ISSET(ops,'r') || !OPT_ISSET(ops,'s')) flags |= STF_RAW; if (OPT_ISSET(ops,'n')) flags |= STF_FILE; if (OPT_ISSET(ops,'o')) flags |= STF_OCTAL; if (OPT_ISSET(ops,'t')) flags |= STF_NAME; if (!(arrnam || hashnam)) { if (nargs > 1) flags |= STF_FILE; if (!(flags & STF_PICK)) flags |= STF_NAME; } if (OPT_ISSET(ops,'N') || OPT_ISSET(ops,'f')) flags &= ~STF_FILE; if (OPT_ISSET(ops,'T') || OPT_ISSET(ops,'H')) flags &= ~STF_NAME; if (hashnam) { if (nargs > 1) { zwarnnam(name, "only one file allowed with -H"); return 1; } arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; if (flags & STF_FILE) arrsize++; hashptr = hash = (char **)zshcalloc((arrsize+1)*2*sizeof(char *)); } if (arrnam) { arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; if (flags & STF_FILE) arrsize++; arrsize *= nargs; arrptr = array = (char **)zshcalloc((arrsize+1)*sizeof(char *)); } for (; OPT_ISSET(ops,'f') || *args; args++) { char outbuf[PATH_MAX + 9]; /* "link " + link name + NULL */ int rval = OPT_ISSET(ops,'f') ? fstat(fd, &statbuf) : OPT_ISSET(ops,'L') ? lstat(unmeta(*args), &statbuf) : stat(unmeta(*args), &statbuf); if (rval) { if (OPT_ISSET(ops,'f')) sprintf(outbuf, "%d", fd); zwarnnam(name, "%s: %e", OPT_ISSET(ops,'f') ? outbuf : *args, errno); ret = 1; if (OPT_ISSET(ops,'f') || arrnam) break; else continue; } if (flags & STF_FILE) { if (arrnam) *arrptr++ = ztrdup(*args); else if (hashnam) { *hashptr++ = ztrdup(HNAMEKEY); *hashptr++ = ztrdup(*args); } else printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n"); } if (iwhich > -1) { statprint(&statbuf, outbuf, *args, iwhich, flags); if (arrnam) *arrptr++ = metafy(outbuf, -1, META_DUP); else if (hashnam) { /* STF_NAME explicitly turned off for ops.ind['H'] above */ *hashptr++ = ztrdup(statelts[iwhich]); *hashptr++ = metafy(outbuf, -1, META_DUP); } else printf("%s\n", outbuf); } else { int i; for (i = 0; i < ST_COUNT; i++) { statprint(&statbuf, outbuf, *args, i, flags); if (arrnam) *arrptr++= metafy(outbuf, -1, META_DUP); else if (hashnam) { /* STF_NAME explicitly turned off for ops.ind['H'] above */ *hashptr++ = ztrdup(statelts[i]); *hashptr++ = metafy(outbuf, -1, META_DUP); } else printf("%s\n", outbuf); } } if (OPT_ISSET(ops,'f')) break; if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK)) putchar('\n'); } if (arrnam) { if (ret) freearray(array); else { setaparam(arrnam, array); if (errflag) return 1; } } if (hashnam) { if (ret) freearray(hash); else { sethparam(hashnam, hash); if (errflag) return 1; } } return ret; }
static int bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) { struct cadata dat; char *mstr = NULL; /* argument of -M options, accumulated */ int added; /* return value */ Cmatcher match = NULL; if (incompfunc != 1) { zwarnnam(name, "can only be called from completion function"); return 1; } dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg = dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp = dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL; dat.match = NULL; dat.flags = 0; dat.aflags = CAF_MATCH; dat.dummies = -1; for (; *argv && **argv == '-'; argv++) { char *p; /* loop variable, points into argv */ if (!(*argv)[1]) { argv++; break; } for (p = *argv + 1; *p; p++) { char *m = NULL; /* argument of -M option (this one only) */ char **sp = NULL; /* the argument to an option should be copied to *sp. */ const char *e; /* error message */ switch (*p) { case 'q': dat.flags |= CMF_REMOVE; break; case 'Q': dat.aflags |= CAF_QUOTE; break; case 'C': dat.aflags |= CAF_ALL; break; case 'f': dat.flags |= CMF_FILE; break; case 'e': dat.flags |= CMF_ISPAR; break; case 'a': dat.aflags |= CAF_ARRAYS; break; case 'k': dat.aflags |= CAF_ARRAYS|CAF_KEYS; break; case 'F': sp = &(dat.ign); e = "string expected after -%c"; break; case 'n': dat.flags |= CMF_NOLIST; break; case 'U': dat.aflags &= ~CAF_MATCH; break; case 'P': sp = &(dat.pre); e = "string expected after -%c"; break; case 'S': sp = &(dat.suf); e = "string expected after -%c"; break; case 'J': sp = &(dat.group); e = "group name expected after -%c"; break; case 'V': if (!dat.group) dat.aflags |= CAF_NOSORT; sp = &(dat.group); e = "group name expected after -%c"; break; case '1': if (!(dat.aflags & CAF_UNIQCON)) dat.aflags |= CAF_UNIQALL; break; case '2': if (!(dat.aflags & CAF_UNIQALL)) dat.aflags |= CAF_UNIQCON; break; case 'i': sp = &(dat.ipre); e = "string expected after -%c"; break; case 'I': sp = &(dat.isuf); e = "string expected after -%c"; break; case 'p': sp = &(dat.ppre); e = "string expected after -%c"; break; case 's': sp = &(dat.psuf); e = "string expected after -%c"; break; case 'W': sp = &(dat.prpre); e = "string expected after -%c"; break; case 'M': sp = &m; e = "matching specification expected after -%c"; break; case 'X': sp = &(dat.exp); e = "string expected after -%c"; break; case 'x': sp = &(dat.mesg); e = "string expected after -%c"; break; case 'r': dat.flags |= CMF_REMOVE; sp = &(dat.rems); e = "string expected after -%c"; break; case 'R': dat.flags |= CMF_REMOVE; sp = &(dat.remf); e = "function name expected after -%c"; break; case 'A': sp = &(dat.apar); e = "parameter name expected after -%c"; break; case 'O': sp = &(dat.opar); e = "parameter name expected after -%c"; break; case 'D': sp = &(dat.dpar); e = "parameter name expected after -%c"; break; case 'd': sp = &(dat.disp); e = "parameter name expected after -%c"; break; case 'l': dat.flags |= CMF_DISPLINE; break; case 'o': dat.flags |= CMF_MORDER; break; case 'E': if (p[1]) { dat.dummies = atoi(p + 1); p = "" - 1; } else if (argv[1]) { argv++; dat.dummies = atoi(*argv); p = "" - 1; } else { zwarnnam(name, "number expected after -%c", *p); zsfree(mstr); return 1; } if (dat.dummies < 0) { zwarnnam(name, "invalid number: %d", dat.dummies); zsfree(mstr); return 1; } break; case '-': argv++; goto ca_args; default: zwarnnam(name, "bad option: -%c", *p); zsfree(mstr); return 1; } if (sp) { if (p[1]) { /* Pasted argument: -Xfoo. */ if (!*sp) *sp = p + 1; p = "" - 1; } else if (argv[1]) { /* Argument in a separate word: -X foo. */ argv++; if (!*sp) *sp = *argv; p = "" - 1; } else { /* Missing argument: argv[N] == "-X", argv[N+1] == NULL. */ zwarnnam(name, e, *p); zsfree(mstr); return 1; } if (m) { if (mstr) { char *tmp = tricat(mstr, " ", m); zsfree(mstr); mstr = tmp; } else mstr = ztrdup(m); } } } } ca_args: if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) { zsfree(mstr); return 1; } zsfree(mstr); if (!*argv && !dat.group && !dat.mesg && !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL))) return 1; dat.match = match = cpcmatcher(match); added = addmatches(&dat, argv); freecmatcher(match); return added; }
static int bin_echoti(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) { char *s, *t, **u; int arg, num, strarg = 0; long pars[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; char *strcap[] = { "pfkey", "pfloc", "pfx", "pln", "pfxl", NULL }; s = *argv++; /* This depends on the termcap stuff in init.c */ if (termflags & TERM_BAD) return 1; if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term())) return 1; /* if the specified capability has a numeric value, display it */ if (((num = tigetnum(s)) != -1) && (num != -2)) { printf("%d\n", num); return 0; } switch (tigetflag(s)) { case -1: break; case 0: puts("no"); return 0; default: puts("yes"); return 0; } /* get a string-type capability */ t = (char *)tigetstr(s); if (!t || t == (char *)-1 || !*t) { /* capability doesn't exist, or (if boolean) is off */ zwarnnam(name, "no such terminfo capability: %s", s); return 1; } /* check that the number of arguments provided is not too high */ if (arrlen_gt(argv, 9)) { zwarnnam(name, "too many arguments"); return 1; } /* check if we have a capability taking non-integers for parameters */ for (u = strcap; *u && !strarg; u++) strarg = !strcmp(s, *u); /* get the arguments */ for (arg=0; argv[arg]; arg++) { if (strarg && arg > 0) pars[arg] = (long) argv[arg]; else pars[arg] = atoi(argv[arg]); } /* output string, through the proper termcap functions */ if (!arg) putp(t); else { putp(tparm(t, pars[0], pars[1], pars[2], pars[3], pars[4], pars[5], pars[6], pars[7], pars[8])); } return 0; }
static int bin_zpty(char *nam, char **args, Options ops, UNUSED(int func)) { if ((OPT_ISSET(ops,'r') && OPT_ISSET(ops,'w')) || ((OPT_ISSET(ops,'r') || OPT_ISSET(ops,'w')) && (OPT_ISSET(ops,'d') || OPT_ISSET(ops,'e') || OPT_ISSET(ops,'b') || OPT_ISSET(ops,'L'))) || (OPT_ISSET(ops,'w') && (OPT_ISSET(ops,'t') || OPT_ISSET(ops,'m'))) || (OPT_ISSET(ops,'n') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') || OPT_ISSET(ops,'r') || OPT_ISSET(ops,'t') || OPT_ISSET(ops,'d') || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'m'))) || (OPT_ISSET(ops,'d') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'t') || OPT_ISSET(ops,'m'))) || (OPT_ISSET(ops,'L') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') || OPT_ISSET(ops,'m')))) { zwarnnam(nam, "illegal option combination"); return 1; } if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'w')) { Ptycmd p; if (!*args) { zwarnnam(nam, "missing pty command name"); return 1; } else if (!(p = getptycmd(*args))) { zwarnnam(nam, "no such pty command: %s", *args); return 1; } if (p->fin) return 2; return (OPT_ISSET(ops,'r') ? ptyread(nam, p, args + 1, OPT_ISSET(ops,'t'), OPT_ISSET(ops, 'm')) : ptywrite(p, args + 1, OPT_ISSET(ops,'n'))); } else if (OPT_ISSET(ops,'d')) { Ptycmd p; int ret = 0; if (*args) { while (*args) if ((p = getptycmd(*args++))) deleteptycmd(p); else { zwarnnam(nam, "no such pty command: %s", args[-1]); ret = 1; } } else deleteallptycmds(); return ret; } else if (OPT_ISSET(ops,'t')) { Ptycmd p; if (!*args) { zwarnnam(nam, "missing pty command name"); return 1; } else if (!(p = getptycmd(*args))) { zwarnnam(nam, "no such pty command: %s", *args); return 1; } checkptycmd(p); return p->fin; } else if (*args) { if (!args[1]) { zwarnnam(nam, "missing command"); return 1; } if (getptycmd(*args)) { zwarnnam(nam, "pty command name already used: %s", *args); return 1; } return newptycmd(nam, *args, args + 1, OPT_ISSET(ops,'e'), OPT_ISSET(ops,'b')); } else { Ptycmd p; char **a; for (p = ptycmds; p; p = p->next) { checkptycmd(p); if (OPT_ISSET(ops,'L')) printf("%s %s%s%s ", nam, (p->echo ? "-e " : ""), (p->nblock ? "-b " : ""), p->name); else if (p->fin) printf("(finished) %s: ", p->name); else printf("(%d) %s: ", p->pid, p->name); for (a = p->args; *a; ) { quotedzputs(*a++, stdout); if (*a) putchar(' '); } putchar('\n'); } return 0; } }
static int ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch) { int blen, used, seen = 0, ret = 0, matchok = 0; char *buf; Patprog prog = NULL; if (*args && args[1]) { char *p; if (args[2]) { zwarnnam(nam, "too many arguments"); return 1; } p = dupstring(args[1]); tokenize(p); remnulargs(p); /* Signals handlers might stomp PAT_STATIC */ if (!(prog = patcompile(p, PAT_ZDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", args[1]); return 1; } } else fflush(stdout); if (cmd->old) { used = cmd->olen; buf = (char *) zhalloc((blen = 256 + used) + 1); memcpy(buf, cmd->old, cmd->olen); zfree(cmd->old, cmd->olen); cmd->old = NULL; cmd->olen = 0; } else { used = 0; buf = (char *) zhalloc((blen = 256) + 1); } if (cmd->read != -1) { buf[used] = (char) cmd->read; buf[used + 1] = '\0'; seen = used = 1; cmd->read = -1; } do { if (noblock && cmd->read == -1) { int pollret; /* * Check there is data available. Borrowed from * poll_read() in utils.c and simplified. */ #ifdef HAVE_SELECT fd_set foofd; struct timeval expire_tv; expire_tv.tv_sec = 0; expire_tv.tv_usec = 0; FD_ZERO(&foofd); FD_SET(cmd->fd, &foofd); pollret = select(cmd->fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); #else #ifdef FIONREAD if (ioctl(cmd->fd, FIONREAD, (char *) &val) == 0) pollret = (val > 0); #endif #endif if (pollret < 0) { /* * See read_poll() for this. * Last despairing effort to poll: attempt to * set nonblocking I/O and actually read the * character. cmd->read stores the character read. */ long mode; if (setblock_fd(0, cmd->fd, &mode)) pollret = read(cmd->fd, &cmd->read, 1); if (mode != -1) fcntl(cmd->fd, F_SETFL, mode); } if (pollret == 0) break; } if (!ret) { checkptycmd(cmd); if (cmd->fin) break; } if (cmd->read != -1 || (ret = read(cmd->fd, buf + used, 1)) == 1) { int readchar; if (cmd->read != -1) { ret = 1; readchar = cmd->read; cmd->read = -1; } else readchar = STOUC(buf[used]); if (imeta(readchar)) { buf[used++] = Meta; buf[used++] = (char) (readchar ^ 32); } else buf[used++] = (char) readchar; seen = 1; if (used >= blen-1) { if (!*args) { buf[used] = '\0'; unmetafy(buf, &used); write_loop(1, buf, used); used = 0; } else { buf = hrealloc(buf, blen, blen << 1); blen <<= 1; } } } buf[used] = '\0'; if (!prog) { if (ret <= 0 || (*args && buf[used - 1] == '\n' && (used < 2 || buf[used-2] != Meta))) break; } else { if (ret < 0 #ifdef EWOULDBLOCK && errno != EWOULDBLOCK #else #ifdef EAGAIN && errno != EAGAIN #endif #endif ) break; } } while (!(errflag || breaks || retflag || contflag) && used < READ_MAX && !(prog && ret && (matchok = pattry(prog, buf)))); if (prog && ret < 0 && #ifdef EWOULDBLOCK errno == EWOULDBLOCK #else #ifdef EAGAIN errno == EAGAIN #endif #endif ) { cmd->old = (char *) zalloc(cmd->olen = used); memcpy(cmd->old, buf, cmd->olen); return 1; } if (*args) setsparam(*args, ztrdup(buf)); else if (used) { unmetafy(buf, &used); write_loop(1, buf, used); } { int ret = cmd->fin + 1; if (seen && (!prog || matchok || !mustmatch)) ret = 0; if (prog) freepatprog(prog); return ret; } }
static int bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { int cloexec = 1, unlock = 0, readlock = 0; time_t timeout = 0; char *fdvar = NULL; #ifdef HAVE_FCNTL_H struct flock lck; int flock_fd, flags; #endif while (*args && **args == '-') { int opt; char *optptr = *args + 1, *optarg; args++; if (!*optptr || !strcmp(optptr, "-")) break; while ((opt = *optptr)) { switch (opt) { case 'e': /* keep lock on "exec" */ cloexec = 0; break; case 'f': /* variable for fd */ if (optptr[1]) { fdvar = optptr + 1; optptr += strlen(fdvar) - 1; } else if (*args) { fdvar = *args++; } if (fdvar == NULL || !isident(fdvar)) { zwarnnam(nam, "flock: option %c requires a variable name", opt); return 1; } break; case 'r': /* read lock rather than read-write lock */ readlock = 1; break; case 't': /* timeout in seconds */ if (optptr[1]) { optarg = optptr + 1; optptr += strlen(optarg) - 1; } else if (!*args) { zwarnnam(nam, "flock: option %c requires a numeric timeout", opt); return 1; } else { optarg = *args++; } timeout = (time_t)mathevali(optarg); break; case 'u': /* unlock: argument is fd */ unlock = 1; break; default: zwarnnam(nam, "flock: unknown option: %c", *optptr); return 1; } optptr++; } } if (!args[0]) { zwarnnam(nam, "flock: not enough arguments"); return 1; } if (args[1]) { zwarnnam(nam, "flock: too many arguments"); return 1; } #ifdef HAVE_FCNTL_H if (unlock) { flock_fd = (int)mathevali(args[0]); if (zcloselockfd(flock_fd) < 0) { zwarnnam(nam, "flock: file descriptor %d not in use for locking", flock_fd); return 1; } return 0; } if (readlock) flags = O_RDONLY | O_NOCTTY; else flags = O_RDWR | O_NOCTTY; if ((flock_fd = open(unmeta(args[0]), flags)) < 0) { zwarnnam(nam, "failed to open %s for writing: %e", args[0], errno); return 1; } flock_fd = movefd(flock_fd); if (flock_fd == -1) return 1; #ifdef FD_CLOEXEC if (cloexec) { long fdflags = fcntl(flock_fd, F_GETFD, 0); if (fdflags != (long)-1) fcntl(flock_fd, F_SETFD, fdflags | FD_CLOEXEC); } #endif addlockfd(flock_fd, cloexec); lck.l_type = readlock ? F_RDLCK : F_WRLCK; lck.l_whence = SEEK_SET; lck.l_start = 0; lck.l_len = 0; /* lock the whole file */ if (timeout > 0) { time_t end = time(NULL) + (time_t)timeout; while (fcntl(flock_fd, F_SETLK, &lck) < 0) { if (errflag) return 1; if (errno != EINTR && errno != EACCES && errno != EAGAIN) { zwarnnam(nam, "failed to lock file %s: %e", args[0], errno); return 1; } if (time(NULL) >= end) return 2; sleep(1); } } else { while (fcntl(flock_fd, F_SETLKW, &lck) < 0) { if (errflag) return 1; if (errno == EINTR) continue; zwarnnam(nam, "failed to lock file %s: %e", args[0], errno); return 1; } } if (fdvar) setiparam(fdvar, flock_fd); return 0; #else /* HAVE_FCNTL_H */ zwarnnam(nam, "flock: not implemented on this system"); return 255; #endif /* HAVE_FCNTL_H */ }
static int bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { int ttyfd, pid, cttyfd; unmetafy(*args, NULL); ttyfd = open(*args, O_RDWR|O_NOCTTY); if (ttyfd < 0) { zwarnnam(nam, "%s: %e", *args, errno); return 1; } pid = fork(); if (!pid) { clearjobtab(0); ppid = getppid(); mypid = getpid(); #ifdef HAVE_SETSID if (setsid() != mypid) zwarnnam(nam, "failed to create new session: %e", NULL, errno); #elif defined(TIOCNOTTY) if (ioctl(SHTTY, TIOCNOTTY, 0)) zwarnnam(*args, "%e", NULL, errno); setpgrp(0L, mypid); #endif dup2(ttyfd,0); dup2(ttyfd,1); dup2(ttyfd,2); if (ttyfd > 2) close(ttyfd); closem(0); close(coprocin); close(coprocout); /* Acquire a controlling terminal */ cttyfd = open(*args, O_RDWR); if (cttyfd == -1) zwarnnam(nam, "%e", NULL, errno); else { #ifdef TIOCSCTTY ioctl(cttyfd, TIOCSCTTY, 0); #endif close(cttyfd); } /* check if we acquired the tty successfully */ cttyfd = open("/dev/tty", O_RDWR); if (cttyfd == -1) zwarnnam(nam, "could not make %s my controlling tty, job control " "disabled", *args, 0); else close(cttyfd); /* Clear mygrp so that acquire_pgrp() gets the new process group. * (acquire_pgrp() is called from init_io()) */ mypgrp = 0; init_io(); setsparam("TTY", ztrdup(ttystrname)); } close(ttyfd); if (pid < 0) { zerrnam(nam, "fork failed: %e", NULL, errno); return 1; } lastpid = pid; return 0; }
static int bin_sysread(char *nam, char **args, Options ops, UNUSED(int func)) { int infd = 0, outfd = -1, bufsize = SYSREAD_BUFSIZE, count; char *outvar = NULL, *countvar = NULL, *inbuf; /* -i: input file descriptor if not stdin */ if (OPT_ISSET(ops, 'i')) { infd = getposint(OPT_ARG(ops, 'i'), nam); if (infd < 0) return 1; } /* -o: output file descriptor, else store in REPLY */ if (OPT_ISSET(ops, 'o')) { if (*args) { zwarnnam(nam, "no argument allowed with -o"); return 1; } outfd = getposint(OPT_ARG(ops, 'o'), nam); if (outfd < 0) return 1; } /* -s: buffer size if not default SYSREAD_BUFSIZE */ if (OPT_ISSET(ops, 's')) { bufsize = getposint(OPT_ARG(ops, 's'), nam); if (bufsize < 0) return 1; } /* -c: name of variable to store count of transferred bytes */ if (OPT_ISSET(ops, 'c')) { countvar = OPT_ARG(ops, 'c'); if (!isident(countvar)) { zwarnnam(nam, "not an identifier: %s", countvar); return 1; } } if (*args) { /* * Variable in which to store result if doing a plain read. * Default variable if not specified is REPLY. * If writing, only stuff we couldn't write is stored here, * no default in that case (we just discard it if no variable). */ outvar = *args; if (!isident(outvar)) { zwarnnam(nam, "not an identifier: %s", outvar); return 1; } } inbuf = zhalloc(bufsize); #if defined(HAVE_POLL) || defined(HAVE_SELECT) /* -t: timeout */ if (OPT_ISSET(ops, 't')) { # ifdef HAVE_POLL struct pollfd poll_fd; mnumber to_mn; int to_int, ret; poll_fd.fd = infd; poll_fd.events = POLLIN; to_mn = matheval(OPT_ARG(ops, 't')); if (errflag) return 1; if (to_mn.type == MN_FLOAT) to_int = (int) (1000 * to_mn.u.d); else to_int = 1000 * (int)to_mn.u.l; while ((ret = poll(&poll_fd, 1, to_int)) < 0) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } if (ret <= 0) { /* treat non-timeout error as error on read */ return ret ? 2 : 4; } # else /* using select */ struct timeval select_tv; fd_set fds; mnumber to_mn; int ret; FD_ZERO(&fds); FD_SET(infd, &fds); to_mn = matheval(OPT_ARG(ops, 't')); if (errflag) return 1; if (to_mn.type == MN_FLOAT) { select_tv.tv_sec = (int) to_mn.u.d; select_tv.tv_usec = (int) ((to_mn.u.d - select_tv.tv_sec) * 1e6); } else { select_tv.tv_sec = (int) to_mn.u.l; select_tv.tv_usec = 0; } while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds, NULL, NULL,&select_tv)) < 1) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } if (ret <= 0) { /* treat non-timeout error as error on read */ return ret ? 2 : 4; } # endif } #endif while ((count = read(infd, inbuf, bufsize)) < 0) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } if (countvar) setiparam(countvar, count); if (count < 0) return 2; if (outfd >= 0) { if (!count) return 5; while (count > 0) { int ret; ret = write(outfd, inbuf, count); if (ret < 0) { if (errno == EINTR && !errflag && !retflag && !breaks && !contflag) continue; if (outvar) setsparam(outvar, metafy(inbuf, count, META_DUP)); if (countvar) setiparam(countvar, count); return 3; } inbuf += ret; count -= ret; } return 0; } if (!outvar) outvar = "REPLY"; /* do this even if we read zero bytes */ setsparam(outvar, metafy(inbuf, count, META_DUP)); return count ? 0 : 5; }
static int bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) { int ret, capcount, *ovec, ovecsize, c; char *matched_portion = NULL; char *receptacle = NULL; int return_value = 1; /* The subject length and offset start are both int values in pcre_exec */ int subject_len; int offset_start = 0; int want_offset_pair = 0; if (pcre_pattern == NULL) { zwarnnam(nam, "no pattern has been compiled"); return 1; } if(OPT_HASARG(ops,c='a')) { receptacle = OPT_ARG(ops,c); } if(OPT_HASARG(ops,c='v')) { matched_portion = OPT_ARG(ops,c); } if(OPT_HASARG(ops,c='n')) { /* The offset position to start the search, in bytes. */ offset_start = getposint(OPT_ARG(ops,c), nam); } /* For the entire match, 'Return' the offset byte positions instead of the matched string */ if(OPT_ISSET(ops,'b')) want_offset_pair = 1; if(!*args) { zwarnnam(nam, "not enough arguments"); } if ((ret = pcre_fullinfo(pcre_pattern, pcre_hints, PCRE_INFO_CAPTURECOUNT, &capcount))) { zwarnnam(nam, "error %d in fullinfo", ret); return 1; } ovecsize = (capcount+1)*3; ovec = zalloc(ovecsize*sizeof(int)); subject_len = (int)strlen(*args); if (offset_start < 0 || offset_start >= subject_len) ret = PCRE_ERROR_NOMATCH; else ret = pcre_exec(pcre_pattern, pcre_hints, *args, subject_len, offset_start, 0, ovec, ovecsize); if (ret==0) return_value = 0; else if (ret==PCRE_ERROR_NOMATCH) /* no match */; else if (ret>0) { zpcre_get_substrings(*args, ovec, ret, matched_portion, receptacle, want_offset_pair, 0, 0); return_value = 0; } else { zwarnnam(nam, "error in pcre_exec"); } if (ovec) zfree(ovec, ovecsize*sizeof(int)); return return_value; }
int evalcond(Estate state, char *fromtest) { struct stat *st; char *left, *right, *overridename, overridebuf[13]; Wordcode pcode; wordcode code; int ctype, htok = 0, ret; rec: left = right = overridename = NULL; pcode = state->pc++; code = *pcode; ctype = WC_COND_TYPE(code); switch (ctype) { case COND_NOT: if (tracingcond) fprintf(xtrerr, " %s", condstr[ctype]); ret = evalcond(state, fromtest); if (ret == 2) return ret; else return !ret; case COND_AND: if (!(ret = evalcond(state, fromtest))) { if (tracingcond) fprintf(xtrerr, " %s", condstr[ctype]); goto rec; } else { state->pc = pcode + (WC_COND_SKIP(code) + 1); return ret; } case COND_OR: if ((ret = evalcond(state, fromtest)) == 1) { if (tracingcond) fprintf(xtrerr, " %s", condstr[ctype]); goto rec; } else { state->pc = pcode + (WC_COND_SKIP(code) + 1); return ret; } case COND_REGEX: { char *modname = isset(REMATCHPCRE) ? "zsh/pcre" : "zsh/regex"; sprintf(overridename = overridebuf, "-%s-match", modname+4); (void)ensurefeature(modname, "C:", overridename+1); ctype = COND_MODI; } /*FALLTHROUGH*/ case COND_MOD: case COND_MODI: { Conddef cd; char *name = overridename, *errname; char **strs; int l = WC_COND_SKIP(code); if (name == NULL) name = ecgetstr(state, EC_NODUP, NULL); if (ctype == COND_MOD) strs = ecgetarr(state, l, EC_DUP, NULL); else { char *sbuf[3]; sbuf[0] = ecgetstr(state, EC_NODUP, NULL); sbuf[1] = ecgetstr(state, EC_NODUP, NULL); sbuf[2] = NULL; strs = arrdup(sbuf); l = 2; } if (name && name[0] == '-') errname = name; else if (strs[0] && *strs[0] == '-') errname = strs[0]; else errname = "<null>"; if (name && name[0] == '-' && (cd = getconddef((ctype == COND_MODI), name + 1, 1))) { if (ctype == COND_MOD && (l < cd->min || (cd->max >= 0 && l > cd->max))) { zwarnnam(fromtest, "unknown condition: %s", name); return 2; } if (tracingcond) tracemodcond(name, strs, ctype == COND_MODI); return !cd->handler(strs, cd->condid); } else { char *s = strs[0]; if (overridename) { /* * Standard regex function not available: this * is a hard error. */ zerrnam(fromtest, "%s not available for regex", overridename); return 2; } strs[0] = dupstring(name); name = s; if (name && name[0] == '-' && (cd = getconddef(0, name + 1, 1))) { if (l < cd->min || (cd->max >= 0 && l > cd->max)) { zwarnnam(fromtest, "unknown condition: %s", errname); return 2; } if (tracingcond) tracemodcond(name, strs, ctype == COND_MODI); return !cd->handler(strs, cd->condid); } else { zwarnnam(fromtest, "unknown condition: %s", errname); } } /* module not found, error */ return 2; } } left = ecgetstr(state, EC_DUPTOK, &htok); if (htok) { cond_subst(&left, !fromtest); untokenize(left); } if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) { right = ecgetstr(state, EC_DUPTOK, &htok); if (htok) { cond_subst(&right, !fromtest); untokenize(right); } } if (tracingcond) { if (ctype < COND_MOD) { fputc(' ',xtrerr); quotedzputs(left, xtrerr); fprintf(xtrerr, " %s ", condstr[ctype]); if (ctype == COND_STREQ || ctype == COND_STRNEQ) { char *rt = dupstring(ecrawstr(state->prog, state->pc, NULL)); cond_subst(&rt, !fromtest); quote_tokenized_output(rt, xtrerr); } else quotedzputs((char *)right, xtrerr); } else { fprintf(xtrerr, " -%c ", ctype); quotedzputs(left, xtrerr); } } if (ctype >= COND_EQ && ctype <= COND_GE) { mnumber mn1, mn2; if (fromtest) { /* * For test and [, the expressions must be base 10 integers, * not integer expressions. */ char *eptr, *err; mn1.u.l = zstrtol(left, &eptr, 10); if (!*eptr) { mn2.u.l = zstrtol(right, &eptr, 10); err = right; } else err = left; if (*eptr) { zwarnnam(fromtest, "integer expression expected: %s", err); return 2; } mn1.type = mn2.type = MN_INTEGER; } else { mn1 = matheval(left); mn2 = matheval(right); } if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) == (MN_INTEGER|MN_FLOAT)) { /* promote to float */ if (mn1.type & MN_INTEGER) { mn1.type = MN_FLOAT; mn1.u.d = (double)mn1.u.l; } if (mn2.type & MN_INTEGER) { mn2.type = MN_FLOAT; mn2.u.d = (double)mn2.u.l; } } switch(ctype) { case COND_EQ: return !((mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) : (mn1.u.l == mn2.u.l)); case COND_NE: return !((mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) : (mn1.u.l != mn2.u.l)); case COND_LT: return !((mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) : (mn1.u.l < mn2.u.l)); case COND_GT: return !((mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) : (mn1.u.l > mn2.u.l)); case COND_LE: return !((mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) : (mn1.u.l <= mn2.u.l)); case COND_GE: return !((mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) : (mn1.u.l >= mn2.u.l)); } } switch (ctype) { case COND_STREQ: case COND_STRNEQ: { int test, npat = state->pc[1]; Patprog pprog = state->prog->pats[npat]; if (pprog == dummy_patprog1 || pprog == dummy_patprog2) { char *opat; int save; right = dupstring(opat = ecrawstr(state->prog, state->pc, &htok)); singsub(&right); save = (!(state->prog->flags & EF_HEAP) && !strcmp(opat, right) && pprog != dummy_patprog2); if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC), NULL))) { zwarnnam(fromtest, "bad pattern: %s", right); return 2; } else if (save) state->prog->pats[npat] = pprog; } state->pc += 2; test = (pprog && pattry(pprog, left)); return !(ctype == COND_STREQ ? test : !test); } case COND_STRLT: return !(strcmp(left, right) < 0); case COND_STRGTR: return !(strcmp(left, right) > 0); case 'e': case 'a': return (!doaccess(left, F_OK)); case 'b': return (!S_ISBLK(dostat(left))); case 'c': return (!S_ISCHR(dostat(left))); case 'd': return (!S_ISDIR(dostat(left))); case 'f': return (!S_ISREG(dostat(left))); case 'g': return (!(dostat(left) & S_ISGID)); case 'k': return (!(dostat(left) & S_ISVTX)); case 'n': return (!strlen(left)); case 'o': return (optison(fromtest, left)); case 'p': return (!S_ISFIFO(dostat(left))); case 'r': return (!doaccess(left, R_OK)); case 's': return !((st = getstat(left)) && !!(st->st_size)); case 'S': return (!S_ISSOCK(dostat(left))); case 'u': return (!(dostat(left) & S_ISUID)); case 'w': return (!doaccess(left, W_OK)); case 'x': if (privasserted()) { mode_t mode = dostat(left); return !((mode & S_IXUGO) || S_ISDIR(mode)); } return !doaccess(left, X_OK); case 'z': return !!(strlen(left)); case 'h': case 'L': return (!S_ISLNK(dolstat(left))); case 'O': return !((st = getstat(left)) && st->st_uid == geteuid()); case 'G': return !((st = getstat(left)) && st->st_gid == getegid()); case 'N': #if defined(GET_ST_MTIME_NSEC) && defined(GET_ST_ATIME_NSEC) if (!(st = getstat(left))) return 1; return (st->st_atime == st->st_mtime) ? GET_ST_ATIME_NSEC(*st) > GET_ST_MTIME_NSEC(*st) : st->st_atime > st->st_mtime; #else return !((st = getstat(left)) && st->st_atime <= st->st_mtime); #endif case 't': return !isatty(mathevali(left)); case COND_NT: case COND_OT: { time_t a; #ifdef GET_ST_MTIME_NSEC long nsecs; #endif if (!(st = getstat(left))) return 1; a = st->st_mtime; #ifdef GET_ST_MTIME_NSEC nsecs = GET_ST_MTIME_NSEC(*st); #endif if (!(st = getstat(right))) return 1; #ifdef GET_ST_MTIME_NSEC if (a == st->st_mtime) { return !((ctype == COND_NT) ? nsecs > GET_ST_MTIME_NSEC(*st) : nsecs < GET_ST_MTIME_NSEC(*st)); } #endif return !((ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime); } case COND_EF: { dev_t d; ino_t i; if (!(st = getstat(left))) return 1; d = st->st_dev; i = st->st_ino; if (!(st = getstat(right))) return 1; return !(d == st->st_dev && i == st->st_ino); } default: zwarnnam(fromtest, "bad cond code"); return 2; } }
static int bin_ln(char *nam, char **args, Options ops, int func) { MoveFunc movefn; int flags, have_dir, err = 0; char **a, *ptr, *rp, *buf; struct stat st; size_t blen; if(func == BIN_MV) { movefn = (MoveFunc) rename; flags = OPT_ISSET(ops,'f') ? 0 : MV_ASKNW; flags |= MV_ATOMIC; } else { flags = OPT_ISSET(ops,'f') ? MV_FORCE : 0; #ifdef HAVE_LSTAT if(OPT_ISSET(ops,'h') || OPT_ISSET(ops,'n')) flags |= MV_NOCHASETARGET; if(OPT_ISSET(ops,'s')) movefn = (MoveFunc) symlink; else #endif { movefn = (MoveFunc) link; if(!OPT_ISSET(ops,'d')) flags |= MV_NODIRS; } } if(OPT_ISSET(ops,'i') && !OPT_ISSET(ops,'f')) flags |= MV_INTERACTIVE; for(a = args; a[1]; a++) ; if(a != args) { rp = unmeta(*a); if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode)) { have_dir = 1; if((flags & MV_NOCHASETARGET) && !lstat(rp, &st) && S_ISLNK(st.st_mode)) { /* * So we have "ln -h" with the target being a symlink pointing * to a directory; if there are multiple sources but the target * is a symlink, then it's an error as we're not following * symlinks; if OTOH there's just one source, then we need to * either fail EEXIST or if "-f" given then remove the target. */ if(a > args+1) { errno = ENOTDIR; zwarnnam(nam, "%s: %e", *a, errno); return 1; } if(flags & MV_FORCE) { unlink(rp); have_dir = 0; } else { errno = EEXIST; zwarnnam(nam, "%s: %e", *a, errno); return 1; } } /* Normal case, target is a directory, chase into it */ if (have_dir) goto havedir; } } if(a > args+1) { zwarnnam(nam, "last of many arguments must be a directory"); return 1; } if(!args[1]) { ptr = strrchr(args[0], '/'); if(ptr) args[1] = ptr+1; else args[1] = args[0]; } return domove(nam, movefn, args[0], args[1], flags); havedir: buf = ztrdup(*a); *a = NULL; buf = appstr(buf, "/"); blen = strlen(buf); for(; *args; args++) { ptr = strrchr(*args, '/'); if(ptr) ptr++; else ptr = *args; buf[blen] = 0; buf = appstr(buf, ptr); err |= domove(nam, movefn, *args, buf, flags); } zsfree(buf); return err; }
mod_export Cmatcher parse_cmatcher(char *name, char *s) { Cmatcher ret = NULL, r = NULL, n; Cpattern line, word, left, right; int fl, fl2, ll, wl, lal, ral, err, both; if (!*s) return NULL; while (*s) { lal = ral = both = fl2 = 0; left = right = NULL; while (*s && inblank(*s)) s++; if (!*s) break; switch (*s) { case 'b': fl2 = CMF_INTER; case 'l': fl = CMF_LEFT; break; case 'e': fl2 = CMF_INTER; case 'r': fl = CMF_RIGHT; break; case 'm': fl = 0; break; case 'B': fl2 = CMF_INTER; case 'L': fl = CMF_LEFT | CMF_LINE; break; case 'E': fl2 = CMF_INTER; case 'R': fl = CMF_RIGHT | CMF_LINE; break; case 'M': fl = CMF_LINE; break; default: if (name) zwarnnam(name, "unknown match specification character `%c'", *s); return pcm_err; } if (s[1] != ':') { if (name) zwarnnam(name, "missing `:'"); return pcm_err; } s += 2; if (!*s) { if (name) zwarnnam(name, "missing patterns"); return pcm_err; } if ((fl & CMF_LEFT) && !fl2) { left = parse_pattern(name, &s, &lal, '|', &err); if (err) return pcm_err; if ((both = (*s && s[1] == '|'))) s++; if (!*s || !*++s) { if (name) zwarnnam(name, "missing line pattern"); return pcm_err; } } else left = NULL; line = parse_pattern(name, &s, &ll, (((fl & CMF_RIGHT) && !fl2) ? '|' : '='), &err); if (err) return pcm_err; if (both) { right = line; ral = ll; line = NULL; ll = 0; } if ((fl & CMF_RIGHT) && !fl2 && (!*s || !*++s)) { if (name) zwarnnam(name, "missing right anchor"); } else if (!(fl & CMF_RIGHT) || fl2) { if (!*s) { if (name) zwarnnam(name, "missing word pattern"); return pcm_err; } s++; } if ((fl & CMF_RIGHT) && !fl2) { if (*s == '|') { left = line; lal = ll; line = NULL; ll = 0; s++; } right = parse_pattern(name, &s, &ral, '=', &err); if (err) return pcm_err; if (!*s) { if (name) zwarnnam(name, "missing word pattern"); return pcm_err; } s++; } else right = NULL; if (*s == '*') { if (!(fl & (CMF_LEFT | CMF_RIGHT))) { if (name) zwarnnam(name, "need anchor for `*'"); return pcm_err; } word = NULL; if (*++s == '*') { s++; wl = -2; } else wl = -1; } else { word = parse_pattern(name, &s, &wl, 0, &err); if (!word && !line) { if (name) zwarnnam(name, "need non-empty word or line pattern"); return pcm_err; } } if (err) return pcm_err; n = (Cmatcher) hcalloc(sizeof(*ret)); n->next = NULL; n->flags = fl | fl2; n->line = line; n->llen = ll; n->word = word; n->wlen = wl; n->left = left; n->lalen = lal; n->right = right; n->ralen = ral; if (ret) r->next = n; else ret = n; r = n; } return ret; }
static int bin_ztie(char *nam, char **args, Options ops, UNUSED(int func)) { char *resource_name, *pmname; GDBM_FILE dbf = NULL; int read_write = GDBM_SYNC, pmflags = PM_REMOVABLE; Param tied_param; if(!OPT_ISSET(ops,'d')) { zwarnnam(nam, "you must pass `-d %s'", backtype); return 1; } if(!OPT_ISSET(ops,'f')) { zwarnnam(nam, "you must pass `-f' with a filename", NULL); return 1; } if (OPT_ISSET(ops,'r')) { read_write |= GDBM_READER; pmflags |= PM_READONLY; } else { read_write |= GDBM_WRCREAT; } /* Here should be a lookup of the backend type against * a registry. */ if (strcmp(OPT_ARG(ops, 'd'), backtype) != 0) { zwarnnam(nam, "unsupported backend type `%s'", OPT_ARG(ops, 'd')); return 1; } resource_name = OPT_ARG(ops, 'f'); pmname = *args; if ((tied_param = (Param)paramtab->getnode(paramtab, pmname)) && !(tied_param->node.flags & PM_UNSET)) { /* * Unset any existing parameter. Note there's no implicit * "local" here, but if the existing parameter is local * that will be reflected in the new one. * * We need to do this before attempting to open the DB * in case this variable is already tied to a DB. * * This can fail if the variable is readonly or restricted. * We could call unsetparam() and check errflag instead * of the return status. */ if (unsetparam_pm(tied_param, 0, 1)) return 1; } dbf = gdbm_open(resource_name, 0, read_write, 0666, 0); if(!dbf) { zwarnnam(nam, "error opening database file %s", resource_name); return 1; } if (!(tied_param = createspecialhash(pmname, &getgdbmnode, &scangdbmkeys, pmflags))) { zwarnnam(nam, "cannot create the requested parameter %s", pmname); gdbm_close(dbf); return 1; } tied_param->gsu.h = &gdbm_hash_gsu; tied_param->u.hash->tmpdata = (void *)dbf; return 0; }