STATIC void evalpipe(shinstance *psh, union node *n) { struct job *jp; struct nodelist *lp; int pipelen; int prevfd; int pip[2]; TRACE((psh, "evalpipe(0x%lx) called\n", (long)n)); pipelen = 0; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) pipelen++; INTOFF; jp = makejob(psh, n, pipelen); prevfd = -1; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { prehash(psh, lp->n); pip[1] = -1; if (lp->next) { if (sh_pipe(psh, pip) < 0) { shfile_close(&psh->fdtab, prevfd); error(psh, "Pipe call failed"); } } if (forkshell(psh, jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) { INTON; if (prevfd > 0) { movefd(psh, prevfd, 0); } if (pip[1] >= 0) { shfile_close(&psh->fdtab, pip[0]); if (pip[1] != 1) { movefd(psh, pip[1], 1); } } evaltree(psh, lp->n, EV_EXIT); } if (prevfd >= 0) shfile_close(&psh->fdtab, prevfd); prevfd = pip[0]; shfile_close(&psh->fdtab, pip[1]); } if (n->npipe.backgnd == 0) { psh->exitstatus = waitforjob(psh, jp); TRACE((psh, "evalpipe: job done exit status %d\n", psh->exitstatus)); } INTON; }
static void inetbind(void) { int s, port; struct sockaddr_in addr; int len = sizeof(addr); int one = 1; struct servent *se; if ((se = getservbyname("identd", "tcp")) == NULL) port = IDENT_PORT; else port = se->s_port; if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) bb_perror_msg_and_die("Cannot create server socket"); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = inet_addr(bind_ip_address); addr.sin_family = AF_INET; addr.sin_port = htons(port); if (bind(s, (struct sockaddr *)&addr, len) < 0) bb_perror_msg_and_die("Cannot bind() port %i", IDENT_PORT); if (listen(s, 5) < 0) bb_perror_msg_and_die("Cannot listen() on port %i", IDENT_PORT); movefd(s, 0); }
static void inetbind(void) { int s, port; struct sockaddr_in addr; int len = sizeof(addr); int one = 1; struct servent *se; if ((se = getservbyname("identd", "tcp")) == NULL) port = IDENT_PORT; else port = se->s_port; s = bb_xsocket(AF_INET, SOCK_STREAM, 0); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = inet_addr(bind_ip_address); addr.sin_family = AF_INET; addr.sin_port = htons(port); bb_xbind(s, (struct sockaddr *)&addr, len); bb_xlisten(s, 5); movefd(s, 0); }
static void deleteConn(int s) { int i = s - FCS; close(s); G.conncnt--; /* * Most of the time there is 0 connections. Most often that there * is connections, there is just one connection. When this one connection * closes, i == G.conncnt = 0 -> no copying. * When there is more than one connection, the oldest connections closes * earlier on average. When this happens, the code below starts copying * the connection structure w/ highest index to the place which which is * just deleted. This means that the connection structures are no longer * in chronological order. I'd quess this means that when there is more * than 1 connection, on average every other connection structure needs * to be copied over the time all these connections are deleted. */ if (i != G.conncnt) { memcpy(&conns[i], &conns[G.conncnt], sizeof(conns[0])); movefd(G.conncnt + FCS, s); } FD_CLR(G.conncnt + FCS, &G.readfds); }
void evalbackcmd(shinstance *psh, union node *n, struct backcmd *result) { int pip[2]; struct job *jp; struct stackmark smark; /* unnecessary */ setstackmark(psh, &smark); result->fd = -1; result->buf = NULL; result->nleft = 0; result->jp = NULL; if (n == NULL) { goto out; } #ifdef notyet /* * For now we disable executing builtins in the same * context as the shell, because we are not keeping * enough state to recover from changes that are * supposed only to affect subshells. eg. echo "`cd /`" */ if (n->type == NCMD) { psh->exitstatus = opsh->exitstatus; evalcommand(psh, n, EV_BACKCMD, result); } else #endif { INTOFF; if (sh_pipe(psh, pip) < 0) error(psh, "Pipe call failed"); jp = makejob(psh, n, 1); if (forkshell(psh, jp, n, FORK_NOJOB) == 0) { FORCEINTON; shfile_close(&psh->fdtab, pip[0]); if (pip[1] != 1) { movefd(psh, pip[1], 1); } eflag(psh) = 0; evaltree(psh, n, EV_EXIT); /* NOTREACHED */ } shfile_close(&psh->fdtab, pip[1]); result->fd = pip[0]; result->jp = jp; INTON; } out: popstackmark(psh, &smark); TRACE((psh, "evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", result->fd, result->buf, result->nleft, result->jp)); }
int source(char *s) { int tempfd, fd, cj, oldlineno; int oldshst, osubsh, oloops; FILE *obshin; char *old_scriptname = scriptname; if (!s || (tempfd = movefd(open(unmeta(s), O_RDONLY))) == -1) { return 1; } /* 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 */ oloops = loops; /* stored the # of nested loops we are in */ oldshst = opts[SHINSTDIN]; /* store current value of this option */ SHIN = tempfd; bshin = fdopen(SHIN, "r"); subsh = 0; lineno = 0; loops = 0; dosetopt(SHINSTDIN, 0, 1); scriptname = s; sourcelevel++; loop(0); /* loop through the file to be sourced */ sourcelevel--; fclose(bshin); fdtable[SHIN] = 0; /* restore the current shell state */ SHIN = fd; /* the shell input fd */ bshin = obshin; /* file handle for buffered shell input */ subsh = osubsh; /* whether we are in a subshell */ thisjob = cj; /* current job number */ lineno = oldlineno; /* our current lineno */ loops = oloops; /* the # of nested loops we are in */ dosetopt(SHINSTDIN, oldshst, 1); /* SHINSTDIN option */ errflag = 0; retflag = 0; scriptname = old_scriptname; return 0; }
void init_misc(void) { if (cmd) { if (SHIN >= 10) fclose(bshin); SHIN = movefd(open("/dev/null", O_RDONLY)); bshin = fdopen(SHIN, "r"); execstring(cmd, 0, 1); stopmsg = 1; zexit(lastval, 0); } if (interact && isset(RCS)) readhistfile(getsparam("HISTFILE"), 0); adjustwinsize(); /* check window size and adjust if necessary */ }
STATIC void free_rl(struct redirtab *rt, int reset) { struct renamelist *rl, *rn = rt->renamed; while ((rl = rn) != NULL) { rn = rl->next; if (rl->orig == 0) fd0_redirected--; if (reset) { if (rl->into < 0) close(rl->orig); else movefd(rl->into, rl->orig); } ckfree(rl); } rt->renamed = NULL; }
int executeServerCommand(int msfd, struct url *url, struct config *cfg) { /* In base al comando inserito, viene chiamata la rispettiva funzione. */ // Si controlla l'esistenza dell'identificativo e si cambia directory. int returnCode = checkIdentifier(url->identifier, cfg->rootdir); if (returnCode != BAD_IDENTIFIER) { char* identifierPath = createFullPath(cfg->rootdir, url->identifier); char* command = url->command; if (strcmp(command, "mkdir") == 0) { returnCode = makeDir(identifierPath, url->argument); } else if (strcmp(command, "put") == 0) { returnCode = putf(msfd, identifierPath, url->argument, url->optionalArgument, "wb"); } else if (strcmp(command, "puta") == 0) { returnCode = putf(msfd, identifierPath, url->argument, url->optionalArgument, "ab"); } else if (strcmp(command, "move") == 0) { returnCode = movefd(identifierPath, url->argument, url->optionalArgument); } else if (strcmp(command, "dele") == 0) { returnCode = deletefd(identifierPath, url->argument); } else if (strcmp(command, "get") == 0) { returnCode = getf(msfd, identifierPath, url->argument); } else { log_err("Unknown_command"); returnCode = MALFORMED_COMMAND; } free(identifierPath); } else { if (strcmp(url->command, "get") == 0) { /* Se l'identificativo non è valido, bisogna comunque avvertire il client che non sta per ricevere alcun file. */ sendEntireFile(msfd, NULL); } else if (strcmp(url->command, "put") == 0 || strcmp(url->command, "puta") == 0) { /* E allo stesso modo devo avvertire il client, nel caso in cui lui voglia effettuare un put ma l'identificativo è errato. */ sendReturnCode(msfd, returnCode); } } log_info("Return code: %d", returnCode); return returnCode; }
void init_io(void) { long ttpgrp; static char outbuf[BUFSIZ], errbuf[BUFSIZ]; #ifdef RSH_BUG_WORKAROUND int i; #endif /* stdout, stderr fully buffered */ #ifdef _IOFBF setvbuf(stdout, outbuf, _IOFBF, BUFSIZ); setvbuf(stderr, errbuf, _IOFBF, BUFSIZ); #else setbuffer(stdout, outbuf, BUFSIZ); setbuffer(stderr, errbuf, BUFSIZ); #endif /* This works around a bug in some versions of in.rshd. * * Currently this is not defined by default. */ #ifdef RSH_BUG_WORKAROUND if (cmd) { for (i = 3; i < 10; i++) close(i); } #endif if (shout) { fclose(shout); shout = 0; } if (SHTTY != -1) { zclose(SHTTY); SHTTY = -1; } /* Make sure the tty is opened read/write. */ if (isatty(0)) { zsfree(ttystrname); if ((ttystrname = ztrdup(ttyname(0)))) SHTTY = movefd(open(ttystrname, O_RDWR)); } if (SHTTY == -1 && (SHTTY = movefd(open("/dev/tty", O_RDWR))) != -1) { zsfree(ttystrname); ttystrname = ztrdup("/dev/tty"); } if (SHTTY == -1) { zsfree(ttystrname); ttystrname = ztrdup(""); } /* We will only use zle if shell is interactive, * * SHTTY != -1, and shout != 0 */ if (interact && SHTTY != -1) { init_shout(); if(!shout) opts[USEZLE] = 0; } else opts[USEZLE] = 0; #ifdef JOB_CONTROL /* If interactive, make the shell the foreground process */ if (opts[MONITOR] && interact && (SHTTY != -1)) { attachtty(GETPGRP()); if ((mypgrp = GETPGRP()) > 0) { while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) { sleep(1); mypgrp = GETPGRP(); if (mypgrp == gettygrp()) break; #ifndef __EMX__ killpg(mypgrp, SIGTTIN); #endif mypgrp = GETPGRP(); } } else opts[MONITOR] = 0; } else opts[MONITOR] = 0; #else opts[MONITOR] = 0; #endif }
int fakeidentd_main(int argc, char **argv) { int fd; pid_t pid; /* FD_ZERO(&G.readfds); - in bss, already zeroed */ FD_SET(0, &G.readfds); /* handle -b <ip> parameter */ getopt32(argc, argv, "b:", &bind_ip_address); /* handle optional REPLY STRING */ if (optind < argc) G.identuser = argv[optind]; else G.identuser = "******"; writepid(); signal(SIGTERM, handlexitsigs); signal(SIGINT, handlexitsigs); signal(SIGQUIT, handlexitsigs); signal(SIGHUP, SIG_IGN); signal(SIGPIPE, SIG_IGN); /* ignore closed connections when writing */ fd = create_and_bind_stream_or_die(bind_ip_address, bb_lookup_port("identd", "tcp", 113)); xlisten(fd, 5); pid = fork(); if (pid < 0) bb_perror_msg_and_die("fork"); if (pid != 0) /* parent */ exit(0); /* child */ setsid(); movefd(fd, 0); while (fd) close(fd--); openlog(applet_name, 0, LOG_DAEMON); logmode = LOGMODE_SYSLOG; /* main loop where we process all events and never exit */ while (1) { fd_set rfds = G.readfds; struct timeval tv = { 15, 0 }; int i; int tim = time(NULL); select(G.conncnt + FCS, &rfds, NULL, NULL, G.conncnt? &tv: NULL); for (i = G.conncnt - 1; i >= 0; i--) { int s = i + FCS; if (FD_ISSET(s, &rfds)) { char *buf = conns[i].buf; unsigned len = conns[i].len; unsigned l; l = read(s, buf + len, sizeof(conns[0].buf) - len); if (l > 0) { if (checkInput(buf, len, l)) { reply(s, buf); goto deleteconn; } else if (len + l >= sizeof(conns[0].buf)) { replyError(s, "X-INVALID-REQUEST"); goto deleteconn; } else { conns[i].len += l; } } else { goto deleteconn; } conns[i].lasttime = tim; continue; deleteconn: deleteConn(s); } else { /* implement as time_after() in linux kernel sources ... */ if (conns[i].lasttime + MAXIDLETIME <= tim) { replyError(s, "X-TIMEOUT"); deleteConn(s); } } } if (FD_ISSET(0, &rfds)) { int s = accept(0, NULL, 0); if (s < 0) { if (errno != EINTR) bb_perror_msg("accept"); } else { if (G.conncnt == MAXCONNS) i = closeOldest(); else i = G.conncnt++; movefd(s, i + FCS); /* move if not already there */ FD_SET(i + FCS, &G.readfds); conns[i].len = 0; conns[i].lasttime = time(NULL); } } } /* end of while (1) */ return 0; }
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 */ }
int execzlefunc(Thingy func, char **args, int set_bindk) { int r = 0, ret = 0, remetafy = 0; Widget w; Thingy save_bindk = bindk; if (set_bindk) bindk = func; if (zlemetaline) { unmetafy_line(); remetafy = 1; } if(func->flags & DISABLED) { /* this thingy is not the name of a widget */ char *nm = nicedup(func->nam, 0); char *msg = tricat("No such widget `", nm, "'"); zsfree(nm); showmsg(msg); zsfree(msg); ret = 1; } else if((w = func->widget)->flags & (WIDGET_INT|WIDGET_NCOMP)) { int wflags = w->flags; /* * The rule is that "zle -N" widgets suppress EOF warnings. When * a "zle -N" widget invokes "zle another-widget" we pass through * this code again, but with actual arguments rather than with the * zlenoargs placeholder. */ if (keybuf[0] == eofchar && !keybuf[1] && args == zlenoargs && !zlell && isfirstln && (zlereadflags & ZLRF_IGNOREEOF)) { showmsg((!islogin) ? "zsh: use 'exit' to exit." : "zsh: use 'logout' to logout."); use_exit_printed = 1; eofsent = 1; ret = 1; } else { if(!(wflags & ZLE_KEEPSUFFIX)) removesuffix(); if(!(wflags & ZLE_MENUCMP)) { fixsuffix(); invalidatelist(); } if (wflags & ZLE_LINEMOVE) vilinerange = 1; if(!(wflags & ZLE_LASTCOL)) lastcol = -1; if (wflags & WIDGET_NCOMP) { int atcurhist = histline == curhist; compwidget = w; ret = completecall(args); if (atcurhist) histline = curhist; } else if (!w->u.fn) { handlefeep(zlenoargs); } else { queue_signals(); ret = w->u.fn(args); unqueue_signals(); } if (!(wflags & ZLE_NOTCOMMAND)) lastcmd = wflags; } r = 1; } else { Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam); if (!shf) { /* the shell function doesn't exist */ char *nm = nicedup(w->u.fnnam, 0); char *msg = tricat("No such shell function `", nm, "'"); zsfree(nm); showmsg(msg); zsfree(msg); ret = 1; } else { int osc = sfcontext, osi = movefd(0); int oxt = isset(XTRACE); LinkList largs = NULL; if (*args) { largs = newlinklist(); addlinknode(largs, dupstring(w->u.fnnam)); while (*args) addlinknode(largs, dupstring(*args++)); } startparamscope(); makezleparams(0); sfcontext = SFC_WIDGET; opts[XTRACE] = 0; ret = doshfunc(shf, largs, 1); opts[XTRACE] = oxt; sfcontext = osc; endparamscope(); lastcmd = w->flags; w->flags = 0; r = 1; redup(osi, 0); } } if (r) { unrefthingy(lbindk); refthingy(func); lbindk = func; } if (set_bindk) bindk = save_bindk; /* * Goodness knows where the user's left us; make sure * it's not on a combining character that won't be displayed * directly. */ CCRIGHT(); if (remetafy) metafy_line(); return ret; }
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; }
int fakeidentd_main(int argc, char **argv) { memset(conns, 0, sizeof(conns)); memset(&G, 0, sizeof(G)); FD_ZERO(&G.readfds); FD_SET(0, &G.readfds); /* handle -b <ip> parameter */ bb_getopt_ulflags(argc, argv, "b:", &bind_ip_address); /* handle optional REPLY STRING */ if (optind < argc) G.identuser = argv[optind]; else G.identuser = nobodystr; /* daemonize and have the parent return */ if (godaemon() == 0) return 0; /* main loop where we process all events and never exit */ while (1) { fd_set rfds = G.readfds; struct timeval tv = { 15, 0 }; int i; int tim = time(NULL); select(G.conncnt + FCS, &rfds, NULL, NULL, G.conncnt? &tv: NULL); for (i = G.conncnt - 1; i >= 0; i--) { int s = i + FCS; if (FD_ISSET(s, &rfds)) { char *buf = conns[i].buf; unsigned int len = conns[i].len; unsigned int l; if ((l = read(s, buf + len, sizeof(conns[0].buf) - len)) > 0) { if (checkInput(buf, len, l)) { reply(s, buf); goto deleteconn; } else if (len + l >= sizeof(conns[0].buf)) { replyError(s, "X-INVALID-REQUEST"); goto deleteconn; } else { conns[i].len += l; } } else { goto deleteconn; } conns[i].lasttime = tim; continue; deleteconn: deleteConn(s); } else { /* implement as time_after() in linux kernel sources ... */ if (conns[i].lasttime + MAXIDLETIME <= tim) { replyError(s, "X-TIMEOUT"); deleteConn(s); } } } if (FD_ISSET(0, &rfds)) { int s = accept(0, NULL, 0); if (s < 0) { if (errno != EINTR) /* EINTR */ syslog(LOG_ERR, "accept: %s", strerror(errno)); } else { if (G.conncnt == MAXCONNS) i = closeOldest(); else i = G.conncnt++; movefd(s, i + FCS); /* move if not already there */ FD_SET(i + FCS, &G.readfds); conns[i].len = 0; conns[i].lasttime = time(NULL); } } } /* end of while(1) */ return 0; }
STATIC void evalcommand(shinstance *psh, union node *cmd, int flags, struct backcmd *backcmd) { struct stackmark smark; union node *argp; struct arglist arglist; struct arglist varlist; char **argv; int argc; char **envp; int varflag; struct strlist *sp; int mode; int pip[2]; struct cmdentry cmdentry; struct job *jp; struct jmploc jmploc; struct jmploc *volatile savehandler; char *volatile savecmdname; volatile struct shparam saveparam; struct localvar *volatile savelocalvars; volatile int e; char *lastarg; const char *path = pathval(psh); volatile int temp_path; #if __GNUC__ /* Avoid longjmp clobbering */ (void) &argv; (void) &argc; (void) &lastarg; (void) &flags; #endif psh->vforked = 0; /* First expand the arguments. */ TRACE((psh, "evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); setstackmark(psh, &smark); psh->back_exitstatus = 0; arglist.lastp = &arglist.list; varflag = 1; /* Expand arguments, ignoring the initial 'name=value' ones */ for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { char *p = argp->narg.text; if (varflag && is_name(*p)) { do { p++; } while (is_in_name(*p)); if (*p == '=') continue; } expandarg(psh, argp, &arglist, EXP_FULL | EXP_TILDE); varflag = 0; } *arglist.lastp = NULL; expredir(psh, cmd->ncmd.redirect); /* Now do the initial 'name=value' ones we skipped above */ varlist.lastp = &varlist.list; for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { char *p = argp->narg.text; if (!is_name(*p)) break; do p++; while (is_in_name(*p)); if (*p != '=') break; expandarg(psh, argp, &varlist, EXP_VARTILDE); } *varlist.lastp = NULL; argc = 0; for (sp = arglist.list ; sp ; sp = sp->next) argc++; argv = stalloc(psh, sizeof (char *) * (argc + 1)); for (sp = arglist.list ; sp ; sp = sp->next) { TRACE((psh, "evalcommand arg: %s\n", sp->text)); *argv++ = sp->text; } *argv = NULL; lastarg = NULL; if (iflag(psh) && psh->funcnest == 0 && argc > 0) lastarg = argv[-1]; argv -= argc; /* Print the command if xflag is set. */ if (xflag(psh)) { char sep = 0; out2str(psh, ps4val(psh)); for (sp = varlist.list ; sp ; sp = sp->next) { if (sep != 0) outc(sep, &psh->errout); out2str(psh, sp->text); sep = ' '; } for (sp = arglist.list ; sp ; sp = sp->next) { if (sep != 0) outc(sep, &psh->errout); out2str(psh, sp->text); sep = ' '; } outc('\n', &psh->errout); flushout(&psh->errout); } /* Now locate the command. */ if (argc == 0) { cmdentry.cmdtype = CMDSPLBLTIN; cmdentry.u.bltin = bltincmd; } else { static const char PATH[] = "PATH="; int cmd_flags = DO_ERR; /* * Modify the command lookup path, if a PATH= assignment * is present */ for (sp = varlist.list; sp; sp = sp->next) if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) path = sp->text + sizeof(PATH) - 1; do { int argsused, use_syspath; find_command(psh, argv[0], &cmdentry, cmd_flags, path); if (cmdentry.cmdtype == CMDUNKNOWN) { psh->exitstatus = 127; flushout(&psh->errout); goto out; } /* implement the 'command' builtin here */ if (cmdentry.cmdtype != CMDBUILTIN || cmdentry.u.bltin != bltincmd) break; cmd_flags |= DO_NOFUNC; argsused = parse_command_args(psh, argc, argv, &use_syspath); if (argsused == 0) { /* use 'type' builting to display info */ cmdentry.u.bltin = typecmd; break; } argc -= argsused; argv += argsused; if (use_syspath) path = syspath(psh) + 5; } while (argc != 0); if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) /* posix mandates that 'command <splbltin>' act as if <splbltin> was a normal builtin */ cmdentry.cmdtype = CMDBUILTIN; } /* Fork off a child process if necessary. */ if (cmd->ncmd.backgnd || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) || ((flags & EV_BACKCMD) != 0 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) || cmdentry.u.bltin == dotcmd || cmdentry.u.bltin == evalcmd))) { INTOFF; jp = makejob(psh, cmd, 1); mode = cmd->ncmd.backgnd; if (flags & EV_BACKCMD) { mode = FORK_NOJOB; if (sh_pipe(psh, pip) < 0) error(psh, "Pipe call failed"); } #ifdef DO_SHAREDVFORK /* It is essential that if DO_SHAREDVFORK is defined that the * child's address space is actually shared with the parent as * we rely on this. */ if (cmdentry.cmdtype == CMDNORMAL) { pid_t pid; savelocalvars = psh->localvars; psh->localvars = NULL; psh->vforked = 1; switch (pid = vfork()) { case -1: TRACE((psh, "Vfork failed, errno=%d\n", errno)); INTON; error(psh, "Cannot vfork"); break; case 0: /* Make sure that exceptions only unwind to * after the vfork(2) */ if (setjmp(jmploc.loc)) { if (psh->exception == EXSHELLPROC) { /* We can't progress with the vfork, * so, set vforked = 2 so the parent * knows, and _exit(); */ psh->vforked = 2; sh__exit(psh, 0); } else { sh__exit(psh, psh->exerrno); } } savehandler = psh->handler; psh->handler = &jmploc; listmklocal(psh, varlist.list, VEXPORT | VNOFUNC); forkchild(psh, jp, cmd, mode, psh->vforked); break; default: psh->handler = savehandler; /* restore from vfork(2) */ poplocalvars(psh); psh->localvars = savelocalvars; if (psh->vforked == 2) { psh->vforked = 0; (void)sh_waitpid(psh, pid, NULL, 0); /* We need to progress in a normal fork fashion */ goto normal_fork; } psh->vforked = 0; forkparent(psh, jp, cmd, mode, pid); goto parent; } } else { normal_fork: #endif if (forkshell(psh, jp, cmd, mode) != 0) goto parent; /* at end of routine */ FORCEINTON; #ifdef DO_SHAREDVFORK } #endif if (flags & EV_BACKCMD) { if (!psh->vforked) { FORCEINTON; } shfile_close(&psh->fdtab, pip[0]); if (pip[1] != 1) { movefd(psh, pip[1], 1); } } flags |= EV_EXIT; } /* This is the child process if a fork occurred. */ /* Execute the command. */ switch (cmdentry.cmdtype) { case CMDFUNCTION: #ifdef DEBUG trputs(psh, "Shell function: "); trargs(psh, argv); #endif redirect(psh, cmd->ncmd.redirect, REDIR_PUSH); saveparam = psh->shellparam; psh->shellparam.malloc = 0; psh->shellparam.reset = 1; psh->shellparam.nparam = argc - 1; psh->shellparam.p = argv + 1; psh->shellparam.optnext = NULL; INTOFF; savelocalvars = psh->localvars; psh->localvars = NULL; INTON; if (setjmp(jmploc.loc)) { if (psh->exception == EXSHELLPROC) { freeparam(psh, (volatile struct shparam *) &saveparam); } else { freeparam(psh, &psh->shellparam); psh->shellparam = saveparam; } poplocalvars(psh); psh->localvars = savelocalvars; psh->handler = savehandler; longjmp(psh->handler->loc, 1); } savehandler = psh->handler; psh->handler = &jmploc; listmklocal(psh, varlist.list, 0); /* stop shell blowing its stack */ if (++psh->funcnest > 1000) error(psh, "too many nested function calls"); evaltree(psh, cmdentry.u.func, flags & EV_TESTED); psh->funcnest--; INTOFF; poplocalvars(psh); psh->localvars = savelocalvars; freeparam(psh, &psh->shellparam); psh->shellparam = saveparam; psh->handler = savehandler; popredir(psh); INTON; if (psh->evalskip == SKIPFUNC) { psh->evalskip = 0; psh->skipcount = 0; } if (flags & EV_EXIT) exitshell(psh, psh->exitstatus); break; case CMDBUILTIN: case CMDSPLBLTIN: #ifdef DEBUG trputs(psh, "builtin command: "); trargs(psh, argv); #endif mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; if (flags == EV_BACKCMD) { psh->memout.nleft = 0; psh->memout.nextc = psh->memout.buf; psh->memout.bufsize = 64; mode |= REDIR_BACKQ; } e = -1; savehandler = psh->handler; savecmdname = psh->commandname; psh->handler = &jmploc; if (!setjmp(jmploc.loc)) { /* We need to ensure the command hash table isn't * corruped by temporary PATH assignments. * However we must ensure the 'local' command works! */ if (path != pathval(psh) && (cmdentry.u.bltin == hashcmd || cmdentry.u.bltin == typecmd)) { savelocalvars = psh->localvars; psh->localvars = 0; mklocal(psh, path - 5 /* PATH= */, 0); temp_path = 1; } else temp_path = 0; redirect(psh, cmd->ncmd.redirect, mode); /* exec is a special builtin, but needs this list... */ psh->cmdenviron = varlist.list; /* we must check 'readonly' flag for all builtins */ listsetvar(psh, varlist.list, cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); psh->commandname = argv[0]; /* initialize nextopt */ psh->argptr = argv + 1; psh->optptr = NULL; /* and getopt */ #if 0 /** @todo fix getop usage! */ #if defined(__FreeBSD__) || defined(__EMX__) || defined(__APPLE__) optreset = 1; optind = 1; #else optind = 0; /* init */ #endif #endif psh->exitstatus = cmdentry.u.bltin(psh, argc, argv); } else { e = psh->exception; psh->exitstatus = e == EXINT ? SIGINT + 128 : e == EXEXEC ? psh->exerrno : 2; } psh->handler = savehandler; output_flushall(psh); psh->out1 = &psh->output; psh->out2 = &psh->errout; freestdout(psh); if (temp_path) { poplocalvars(psh); psh->localvars = savelocalvars; } psh->cmdenviron = NULL; if (e != EXSHELLPROC) { psh->commandname = savecmdname; if (flags & EV_EXIT) exitshell(psh, psh->exitstatus); } if (e != -1) { if ((e != EXERROR && e != EXEXEC) || cmdentry.cmdtype == CMDSPLBLTIN) exraise(psh, e); FORCEINTON; } if (cmdentry.u.bltin != execcmd) popredir(psh); if (flags == EV_BACKCMD) { backcmd->buf = psh->memout.buf; backcmd->nleft = (int)(psh->memout.nextc - psh->memout.buf); psh->memout.buf = NULL; } break; default: #ifdef DEBUG trputs(psh, "normal command: "); trargs(psh, argv); #endif clearredir(psh, psh->vforked); redirect(psh, cmd->ncmd.redirect, psh->vforked ? REDIR_VFORK : 0); if (!psh->vforked) for (sp = varlist.list ; sp ; sp = sp->next) setvareq(psh, sp->text, VEXPORT|VSTACK); envp = environment(psh); shellexec(psh, argv, envp, path, cmdentry.u.index, psh->vforked); break; } goto out; parent: /* parent process gets here (if we forked) */ if (mode == FORK_FG) { /* argument to fork */ psh->exitstatus = waitforjob(psh, jp); } else if (mode == FORK_NOJOB) { backcmd->fd = pip[0]; shfile_close(&psh->fdtab, pip[1]); backcmd->jp = jp; } FORCEINTON; out: if (lastarg) /* dsl: I think this is intended to be used to support * '_' in 'vi' command mode during line editing... * However I implemented that within libedit itself. */ setvar(psh, "_", lastarg, 0); popstackmark(psh, &smark); if (eflag(psh) && psh->exitstatus && !(flags & EV_TESTED)) exitshell(psh, psh->exitstatus); }
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; }
void parseargs(char **argv) { char **x; int action, optno; LinkList paramlist; int bourne = (emulation == EMULATE_KSH || emulation == EMULATE_SH); hackzero = argzero = *argv++; SHIN = 0; /* There's a bit of trickery with opts[INTERACTIVE] here. It starts * * at a value of 2 (instead of 1) or 0. If it is explicitly set on * * the command line, it goes to 1 or 0. If input is coming from * * somewhere that normally makes the shell non-interactive, we do * * "opts[INTERACTIVE] &= 1", so that only a *default* on state will * * be changed. At the end of the function, a value of 2 gets * * changed to 1. */ opts[INTERACTIVE] = isatty(0) ? 2 : 0; opts[SHINSTDIN] = 0; opts[SINGLECOMMAND] = 0; /* loop through command line options (begins with "-" or "+") */ while (*argv && (**argv == '-' || **argv == '+')) { action = (**argv == '-'); if(!argv[0][1]) *argv = "--"; while (*++*argv) { /* The pseudo-option `--' signifies the end of options. * * `-b' does too, csh-style, unless we're emulating a * * Bourne style shell. */ if (**argv == '-' || (!bourne && **argv == 'b')) { argv++; goto doneoptions; } if (**argv == 'c') { /* -c command */ if (!*++argv) { zerr("string expected after -c", NULL, 0); exit(1); } cmd = *argv++; opts[INTERACTIVE] &= 1; opts[SHINSTDIN] = 0; goto doneoptions; } else if (**argv == 'o') { if (!*++*argv) argv++; if (!*argv) { zerr("string expected after -o", NULL, 0); exit(1); } if(!(optno = optlookup(*argv))) zerr("no such option: %s", *argv, 0); else dosetopt(optno, action, 1); break; } else { if (!(optno = optlookupc(**argv))) { zerr("bad option: -%c", NULL, **argv); exit(1); } else dosetopt(optno, action, 1); } } argv++; } doneoptions: paramlist = newlinklist(); if (*argv) { if (unset(SHINSTDIN)) { argzero = *argv; if (!cmd) SHIN = movefd(open(unmeta(argzero), O_RDONLY)); if (SHIN == -1) { zerr("can't open input file: %s", argzero, 0); exit(1); } opts[INTERACTIVE] &= 1; argv++; } while (*argv) addlinknode(paramlist, ztrdup(*argv++)); } else opts[SHINSTDIN] = 1; if(isset(SINGLECOMMAND)) opts[INTERACTIVE] &= 1; opts[INTERACTIVE] = !!opts[INTERACTIVE]; pparams = x = (char **) zcalloc((countlinknodes(paramlist) + 1) * sizeof(char *)); while ((*x++ = (char *)getlinknode(paramlist))); free(paramlist); argzero = ztrdup(argzero); }