/*VARARGS4*/ int start_command(char *cmd, sigset_t *mask, int infd, int outfd, char *a0, char *a1, char *a2) { int pid; if ((pid = fork()) < 0) { warn("fork"); return (-1); } if (pid == 0) { char *argv[100]; int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); if ((argv[i++] = a0) != NULL && (argv[i++] = a1) != NULL && (argv[i++] = a2) != NULL) argv[i] = NULL; prepare_child(mask, infd, outfd); execvp(argv[0], argv); warn("%s", argv[0]); _exit(1); } return (pid); }
/* * Run a command without a shell, with optional arguments and splicing * of stdin (-1 means none) and stdout. The command name can be a sequence * of words. * Signals must be handled by the caller. * "nset" contains the signals to ignore in the new process. * SIGINT is enabled unless it's in "nset". */ static pid_t start_commandv(char *cmd, sigset_t *nset, int infd, int outfd, va_list args) { pid_t pid; if ((pid = fork()) < 0) { warn("fork"); return (-1); } if (pid == 0) { char *argv[100]; int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv)); while ((argv[i++] = va_arg(args, char *))) ; argv[i] = NULL; prepare_child(nset, infd, outfd); execvp(argv[0], argv); warn("%s", argv[0]); _exit(1); }
/* * Do a shell-like extraction of a line * and make a list of name from it. * Return the list or NULL if none found. */ static struct name * shextract(char *line, int ntype) { struct name *begin, *np, *t; char *argv[MAXARGC]; size_t argc, i; begin = NULL; if (line) { np = NULL; argc = getrawlist(line, argv, (int)__arraycount(argv)); for (i = 0; i < argc; i++) { t = nalloc(argv[i], ntype); if (begin == NULL) begin = t; else np->n_flink = t; t->n_blink = np; np = t; } } return begin; }
/* * Execute a single command. * Command functions return 0 for success, 1 for error, and -1 * for abort. A 1 or -1 aborts a load or source. A -1 aborts * the interactive command loop. * Contxt is non-zero if called while composing mail. */ int execute(char linebuf[], int contxt) { char word[LINESIZE]; char *arglist[MAXARGC]; const struct cmd *com; char *cp, *cp2; int c, muvec[2]; int e = 1; /* * Strip the white space away from the beginning * of the command, then scan out a word, which * consists of anything except digits and white space. * * Handle ! escapes differently to get the correct * lexical conventions. */ for (cp = linebuf; isspace((unsigned char)*cp); cp++) ; if (*cp == '!') { if (sourcing) { printf("Can't \"!\" while sourcing\n"); goto out; } shell(cp+1); return (0); } cp2 = word; while (*cp != '\0' && strchr(" \t0123456789$^.:/-+*'\"", *cp) == NULL) *cp2++ = *cp++; *cp2 = '\0'; /* * Look up the command; if not found, bitch. * Normally, a blank command would map to the * first command in the table; while sourcing, * however, we ignore blank lines to eliminate * confusion. */ if (sourcing && *word == '\0') return (0); com = lex(word); if (com == NULL) { printf("Unknown command: \"%s\"\n", word); goto out; } /* * See if we should execute the command -- if a conditional * we always execute it, otherwise, check the state of cond. */ if ((com->c_argtype & F) == 0) if ((cond == CRCV && !rcvmode) || (cond == CSEND && rcvmode)) return (0); /* * Process the arguments to the command, depending * on the type he expects. Default to an error. * If we are sourcing an interactive command, it's * an error. */ if (!rcvmode && (com->c_argtype & M) == 0) { printf("May not execute \"%s\" while sending\n", com->c_name); goto out; } if (sourcing && com->c_argtype & I) { printf("May not execute \"%s\" while sourcing\n", com->c_name); goto out; } if (readonly && com->c_argtype & W) { printf("May not execute \"%s\" -- message file is read only\n", com->c_name); goto out; } if (contxt && com->c_argtype & R) { printf("Cannot recursively invoke \"%s\"\n", com->c_name); goto out; } switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { case MSGLIST: /* * A message list defaulting to nearest forward * legal message. */ if (msgvec == 0) { printf("Illegal use of \"message list\"\n"); break; } if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) break; if (c == 0) { *msgvec = first(com->c_msgflag, com->c_msgmask); msgvec[1] = 0; } if (*msgvec == 0) { printf("No applicable messages\n"); break; } e = (*com->c_func)(msgvec); break; case NDMLIST: /* * A message list with no defaults, but no error * if none exist. */ if (msgvec == 0) { printf("Illegal use of \"message list\"\n"); break; } if (getmsglist(cp, msgvec, com->c_msgflag) < 0) break; e = (*com->c_func)(msgvec); break; case STRLIST: /* * Just the straight string, with * leading blanks removed. */ while (isspace((unsigned char)*cp)) cp++; e = (*com->c_func)(cp); break; case RAWLIST: /* * A vector of strings, in shell style. */ if ((c = getrawlist(cp, arglist, sizeof(arglist) / sizeof(*arglist))) < 0) break; if (c < com->c_minargs) { printf("%s requires at least %d arg(s)\n", com->c_name, com->c_minargs); break; } if (c > com->c_maxargs) { printf("%s takes no more than %d arg(s)\n", com->c_name, com->c_maxargs); break; } e = (*com->c_func)(arglist); break; case NOLIST: /* * Just the constant zero, for exiting, * eg. */ e = (*com->c_func)(0); break; default: errx(1, "Unknown argtype"); } out: /* * Exit the current source file on * error. */ if (e) { if (e < 0) return (1); if (loading) return (1); if (sourcing) unstack(); return (0); } if (com == NULL) return (0); if (value("autoprint") != NULL && com->c_argtype & P) if ((dot->m_flag & MDELETED) == 0) { muvec[0] = dot - &message[0] + 1; muvec[1] = 0; type(muvec); } if (!sourcing && (com->c_argtype & T) == 0) sawcom = 1; return (0); }