static void pioact(struct shf *shf, int indent, struct ioword *iop) { int flag = iop->flag; int type = flag & IOTYPE; int expected; expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 : (type == IOCAT || type == IOWRITE) ? 1 : (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit : iop->unit + 1; if (iop->unit != expected) shf_fprintf(shf, "%d", iop->unit); switch (type) { case IOREAD: shf_puts("<", shf); break; case IOHERE: shf_puts(flag & IOSKIP ? "<<-" : "<<", shf); break; case IOCAT: shf_puts(">>", shf); break; case IOWRITE: shf_puts(flag & IOCLOB ? ">|" : ">", shf); break; case IORDWR: shf_puts("<>", shf); break; case IODUP: shf_puts(flag & IORDUP ? "<&" : ">&", shf); break; } /* name/delim are NULL when printing syntax errors */ if (type == IOHERE) { if (iop->delim) wdvarput(shf, iop->delim, 0, WDS_TPUTS); if (iop->flag & IOHERESTR) shf_putc(' ', shf); } else if (iop->name) fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", iop->name); prevent_semicolon = false; }
/* * print a command tree */ static void ptree(struct op *t, int indent, struct shf *shf) { const char **w; struct ioword **ioact; struct op *t1; int i; Chain: if (t == NULL) return; switch (t->type) { case TCOM: prevent_semicolon = false; /* * special-case 'var=<<EOF' (rough; see * exec.c:execute() for full code) */ if ( /* we have zero arguments, i.e. no programme to run */ t->args[0] == NULL && /* we have exactly one variable assignment */ t->vars[0] != NULL && t->vars[1] == NULL && /* we have exactly one I/O redirection */ t->ioact != NULL && t->ioact[0] != NULL && t->ioact[1] == NULL && /* of type "here document" (or "here string") */ (t->ioact[0]->flag & IOTYPE) == IOHERE) { fptreef(shf, indent, "%S", t->vars[0]); break; } if (t->vars) { w = (const char **)t->vars; while (*w) fptreef(shf, indent, "%S ", *w++); } else shf_puts("#no-vars# ", shf); if (t->args) { w = t->args; while (*w) fptreef(shf, indent, "%S ", *w++); } else shf_puts("#no-args# ", shf); break; case TEXEC: t = t->left; goto Chain; case TPAREN: fptreef(shf, indent + 2, "( %T) ", t->left); break; case TPIPE: fptreef(shf, indent, "%T| ", t->left); t = t->right; goto Chain; case TLIST: fptreef(shf, indent, "%T%;", t->left); t = t->right; goto Chain; case TOR: case TAND: fptreef(shf, indent, "%T%s %T", t->left, (t->type == TOR) ? "||" : "&&", t->right); break; case TBANG: shf_puts("! ", shf); prevent_semicolon = false; t = t->right; goto Chain; case TDBRACKET: w = t->args; shf_puts("[[", shf); while (*w) fptreef(shf, indent, " %S", *w++); shf_puts(" ]] ", shf); break; case TSELECT: case TFOR: fptreef(shf, indent, "%s %s ", (t->type == TFOR) ? "for" : Tselect, t->str); if (t->vars != NULL) { shf_puts("in ", shf); w = (const char **)t->vars; while (*w) fptreef(shf, indent, "%S ", *w++); fptreef(shf, indent, "%;"); } fptreef(shf, indent + INDENT, "do%N%T", t->left); fptreef(shf, indent, "%;done "); break; case TCASE: fptreef(shf, indent, "case %S in", t->str); for (t1 = t->left; t1 != NULL; t1 = t1->right) { fptreef(shf, indent, "%N("); w = (const char **)t1->vars; while (*w) { fptreef(shf, indent, "%S%c", *w, (w[1] != NULL) ? '|' : ')'); ++w; } fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left, t1->u.charflag); } fptreef(shf, indent, "%Nesac "); break; #ifdef DEBUG case TELIF: internal_errorf("TELIF in tree.c:ptree() unexpected"); /* FALLTHROUGH */ #endif case TIF: i = 2; t1 = t; goto process_TIF; do { t1 = t1->right; i = 0; fptreef(shf, indent, "%;"); process_TIF: /* 5 == strlen("elif ") */ fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left); t1 = t1->right; if (t1->left != NULL) { fptreef(shf, indent, "%;"); fptreef(shf, indent + INDENT, "%s%N%T", "then", t1->left); } } while (t1->right && t1->right->type == TELIF); if (t1->right != NULL) { fptreef(shf, indent, "%;"); fptreef(shf, indent + INDENT, "%s%N%T", "else", t1->right); } fptreef(shf, indent, "%;fi "); break; case TWHILE: case TUNTIL: /* 6 == strlen("while "/"until ") */ fptreef(shf, indent + 6, "%s %T", (t->type == TWHILE) ? "while" : "until", t->left); fptreef(shf, indent, "%;"); fptreef(shf, indent + INDENT, "do%N%T", t->right); fptreef(shf, indent, "%;done "); break; case TBRACE: fptreef(shf, indent + INDENT, "{%N%T", t->left); fptreef(shf, indent, "%;} "); break; case TCOPROC: fptreef(shf, indent, "%T|& ", t->left); prevent_semicolon = true; break; case TASYNC: fptreef(shf, indent, "%T& ", t->left); prevent_semicolon = true; break; case TFUNCT: fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left); break; case TTIME: fptreef(shf, indent, "%s %T", "time", t->left); break; default: shf_puts("<botch>", shf); prevent_semicolon = false; break; } if ((ioact = t->ioact) != NULL) { bool need_nl = false; while (*ioact != NULL) pioact(shf, *ioact++); /* Print here documents after everything else... */ ioact = t->ioact; while (*ioact != NULL) { struct ioword *iop = *ioact++; /* heredoc is NULL when tracing (set -x) */ if ((iop->flag & (IOTYPE | IOHERESTR)) == IOHERE && iop->heredoc) { shf_putc('\n', shf); shf_puts(iop->heredoc, shf); fptreef(shf, indent, "%s", iop->flag & IONDELIM ? "<<" : evalstr(iop->delim, 0)); need_nl = true; } } /* * Last delimiter must be followed by a newline (this * often leads to an extra blank line, but it's not * worth worrying about) */ if (need_nl) { shf_putc('\n', shf); prevent_semicolon = true; } } }
static void ptree(struct op *t, int indent, struct shf *shf) { char **w; struct ioword **ioact; struct op *t1; Chain: if (t == NULL) return; switch (t->type) { case TCOM: if (t->vars) for (w = t->vars; *w != NULL; ) fptreef(shf, indent, "%S ", *w++); else fptreef(shf, indent, "#no-vars# "); if (t->args) for (w = t->args; *w != NULL; ) fptreef(shf, indent, "%S ", *w++); else fptreef(shf, indent, "#no-args# "); break; case TEXEC: #if 0 /* ?not useful - can't be called? */ /* Print original vars */ if (t->left->vars) for (w = t->left->vars; *w != NULL; ) fptreef(shf, indent, "%S ", *w++); else fptreef(shf, indent, "#no-vars# "); /* Print expanded vars */ if (t->args) for (w = t->args; *w != NULL; ) fptreef(shf, indent, "%s ", *w++); else fptreef(shf, indent, "#no-args# "); /* Print original io */ t = t->left; #else t = t->left; goto Chain; #endif case TPAREN: fptreef(shf, indent + 2, "( %T) ", t->left); break; case TPIPE: fptreef(shf, indent, "%T| ", t->left); t = t->right; goto Chain; case TLIST: fptreef(shf, indent, "%T%;", t->left); t = t->right; goto Chain; case TOR: case TAND: fptreef(shf, indent, "%T%s %T", t->left, (t->type==TOR) ? "||" : "&&", t->right); break; case TBANG: fptreef(shf, indent, "! "); t = t->right; goto Chain; case TDBRACKET: { int i; fptreef(shf, indent, "[["); for (i = 0; t->args[i]; i++) fptreef(shf, indent, " %S", t->args[i]); fptreef(shf, indent, " ]] "); break; } case TSELECT: fptreef(shf, indent, "select %s ", t->str); /* FALLTHROUGH */ case TFOR: if (t->type == TFOR) fptreef(shf, indent, "for %s ", t->str); if (t->vars != NULL) { fptreef(shf, indent, "in "); for (w = t->vars; *w; ) fptreef(shf, indent, "%S ", *w++); fptreef(shf, indent, "%;"); } fptreef(shf, indent + INDENT, "do%N%T", t->left); fptreef(shf, indent, "%;done "); break; case TCASE: fptreef(shf, indent, "case %S in", t->str); for (t1 = t->left; t1 != NULL; t1 = t1->right) { fptreef(shf, indent, "%N("); for (w = t1->vars; *w != NULL; w++) fptreef(shf, indent, "%S%c", *w, (w[1] != NULL) ? '|' : ')'); fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left); } fptreef(shf, indent, "%Nesac "); break; case TIF: case TELIF: /* 3 == strlen("if ") */ fptreef(shf, indent + 3, "if %T", t->left); for (;;) { t = t->right; if (t->left != NULL) { fptreef(shf, indent, "%;"); fptreef(shf, indent + INDENT, "then%N%T", t->left); } if (t->right == NULL || t->right->type != TELIF) break; t = t->right; fptreef(shf, indent, "%;"); /* 5 == strlen("elif ") */ fptreef(shf, indent + 5, "elif %T", t->left); } if (t->right != NULL) { fptreef(shf, indent, "%;"); fptreef(shf, indent + INDENT, "else%;%T", t->right); } fptreef(shf, indent, "%;fi "); break; case TWHILE: case TUNTIL: /* 6 == strlen("while"/"until") */ fptreef(shf, indent + 6, "%s %T", (t->type==TWHILE) ? "while" : "until", t->left); fptreef(shf, indent, "%;do"); fptreef(shf, indent + INDENT, "%;%T", t->right); fptreef(shf, indent, "%;done "); break; case TBRACE: fptreef(shf, indent + INDENT, "{%;%T", t->left); fptreef(shf, indent, "%;} "); break; case TCOPROC: fptreef(shf, indent, "%T|& ", t->left); break; case TASYNC: fptreef(shf, indent, "%T& ", t->left); break; case TFUNCT: fptreef(shf, indent, t->u.ksh_func ? "function %s %T" : "%s() %T", t->str, t->left); break; case TTIME: fptreef(shf, indent, "time %T", t->left); break; default: fptreef(shf, indent, "<botch>"); break; } if ((ioact = t->ioact) != NULL) { int need_nl = 0; while (*ioact != NULL) pioact(shf, indent, *ioact++); /* Print here documents after everything else... */ for (ioact = t->ioact; *ioact != NULL; ) { struct ioword *iop = *ioact++; /* heredoc is 0 when tracing (set -x) */ if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) { tputc('\n', shf); shf_puts(iop->heredoc, shf); fptreef(shf, indent, "%s", evalstr(iop->delim, 0)); need_nl = 1; } } /* Last delimiter must be followed by a newline (this often * leads to an extra blank line, but its not worth worrying * about) */ if (need_nl) tputc('\n', shf); } }
static void pioact(struct shf *shf, int indent, struct ioword *iop) { int flag = iop->flag; int type = flag & IOTYPE; int expected; expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 : (type == IOCAT || type == IOWRITE) ? 1 : (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit : iop->unit + 1; if (iop->unit != expected) tputc('0' + iop->unit, shf); switch (type) { case IOREAD: fptreef(shf, indent, "< "); break; case IOHERE: if (flag&IOSKIP) fptreef(shf, indent, "<<- "); else fptreef(shf, indent, "<< "); break; case IOCAT: fptreef(shf, indent, ">> "); break; case IOWRITE: if (flag&IOCLOB) fptreef(shf, indent, ">| "); else fptreef(shf, indent, "> "); break; case IORDWR: fptreef(shf, indent, "<> "); break; case IODUP: if (flag & IORDUP) fptreef(shf, indent, "<&"); else fptreef(shf, indent, ">&"); break; } /* name/delim are 0 when printing syntax errors */ if (type == IOHERE) { if (iop->delim) fptreef(shf, indent, "%S ", iop->delim); } else if (iop->name) fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", iop->name); }
/* * print a command tree */ static void ptree(struct op *t, int indent, struct shf *shf) { const char **w; struct ioword **ioact; struct op *t1; int i; const char *ccp; Chain: if (t == NULL) return; switch (t->type) { case TCOM: prevent_semicolon = false; /* special-case 'var=<<EOF' (cf. exec.c:execute) */ if (t->args && /* we have zero arguments, i.e. no program to run */ t->args[0] == NULL && /* we have exactly one variable assignment */ t->vars[0] != NULL && t->vars[1] == NULL && /* we have exactly one I/O redirection */ t->ioact != NULL && t->ioact[0] != NULL && t->ioact[1] == NULL && /* of type "here document" (or "here string") */ (t->ioact[0]->ioflag & IOTYPE) == IOHERE && /* the variable assignment begins with a valid varname */ (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] && /* and has no right-hand side (i.e. "varname=") */ ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) || /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR && ccp[3] == '=' && ccp[4] == EOS))) { fptreef(shf, indent, Tf_S, t->vars[0]); break; } if (t->vars) { w = (const char **)t->vars; while (*w) fptreef(shf, indent, Tf_S_, *w++); } else shf_puts("#no-vars# ", shf); if (t->args) { w = t->args; if (*w && **w == CHAR) { char *cp = wdstrip(*w++, WDS_TPUTS); if (valid_alias_name(cp)) shf_putc('\\', shf); shf_puts(cp, shf); shf_putc(' ', shf); afree(cp, ATEMP); } while (*w) fptreef(shf, indent, Tf_S_, *w++); } else shf_puts("#no-args# ", shf); break; case TEXEC: t = t->left; goto Chain; case TPAREN: fptreef(shf, indent + 2, "( %T) ", t->left); break; case TPIPE: fptreef(shf, indent, "%T| ", t->left); t = t->right; goto Chain; case TLIST: fptreef(shf, indent, "%T%;", t->left); t = t->right; goto Chain; case TOR: case TAND: fptreef(shf, indent, "%T%s %T", t->left, (t->type == TOR) ? "||" : "&&", t->right); break; case TBANG: shf_puts("! ", shf); prevent_semicolon = false; t = t->right; goto Chain; case TDBRACKET: w = t->args; shf_puts("[[", shf); while (*w) fptreef(shf, indent, Tf__S, *w++); shf_puts(" ]] ", shf); break; case TSELECT: case TFOR: fptreef(shf, indent, "%s %s ", (t->type == TFOR) ? "for" : Tselect, t->str); if (t->vars != NULL) { shf_puts("in ", shf); w = (const char **)t->vars; while (*w) fptreef(shf, indent, Tf_S_, *w++); fptreef(shf, indent, Tft_end); } fptreef(shf, indent + INDENT, "do%N%T", t->left); fptreef(shf, indent, "%;done "); break; case TCASE: fptreef(shf, indent, "case %S in", t->str); for (t1 = t->left; t1 != NULL; t1 = t1->right) { fptreef(shf, indent, "%N("); w = (const char **)t1->vars; while (*w) { fptreef(shf, indent, "%S%c", *w, (w[1] != NULL) ? '|' : ')'); ++w; } fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left, t1->u.charflag); } fptreef(shf, indent, "%Nesac "); break; case TELIF: internal_errorf(TELIF_unexpected); /* FALLTHROUGH */ case TIF: i = 2; t1 = t; goto process_TIF; do { t1 = t1->right; i = 0; fptreef(shf, indent, Tft_end); process_TIF: /* 5 == strlen("elif ") */ fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left); t1 = t1->right; if (t1->left != NULL) { fptreef(shf, indent, Tft_end); fptreef(shf, indent + INDENT, "%s%N%T", "then", t1->left); } } while (t1->right && t1->right->type == TELIF); if (t1->right != NULL) { fptreef(shf, indent, Tft_end); fptreef(shf, indent + INDENT, "%s%N%T", "else", t1->right); } fptreef(shf, indent, "%;fi "); break; case TWHILE: case TUNTIL: /* 6 == strlen("while "/"until ") */ fptreef(shf, indent + 6, Tf_s_T, (t->type == TWHILE) ? "while" : "until", t->left); fptreef(shf, indent, Tft_end); fptreef(shf, indent + INDENT, "do%N%T", t->right); fptreef(shf, indent, "%;done "); break; case TBRACE: fptreef(shf, indent + INDENT, "{%N%T", t->left); fptreef(shf, indent, "%;} "); break; case TCOPROC: fptreef(shf, indent, "%T|& ", t->left); prevent_semicolon = true; break; case TASYNC: fptreef(shf, indent, "%T& ", t->left); prevent_semicolon = true; break; case TFUNCT: fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left); break; case TTIME: fptreef(shf, indent, Tf_s_T, Ttime, t->left); break; default: shf_puts("<botch>", shf); prevent_semicolon = false; break; } if ((ioact = t->ioact) != NULL) { bool need_nl = false; while (*ioact != NULL) pioact(shf, *ioact++); /* Print here documents after everything else... */ ioact = t->ioact; while (*ioact != NULL) { struct ioword *iop = *ioact++; /* heredoc is NULL when tracing (set -x) */ if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE && iop->heredoc) { shf_putc('\n', shf); shf_puts(iop->heredoc, shf); fptreef(shf, indent, Tf_s, evalstr(iop->delim, 0)); need_nl = true; } } /* * Last delimiter must be followed by a newline (this * often leads to an extra blank line, but it's not * worth worrying about) */ if (need_nl) { shf_putc('\n', shf); prevent_semicolon = true; } } }
/* * set up redirection, saving old fds in e->savefd */ static int iosetup(struct ioword *iop, struct tbl *tp) { int u = -1; char *cp = iop->name; int iotype = iop->flag & IOTYPE; bool do_open = true, do_close = false; int flags = 0; struct ioword iotmp; struct stat statb; if (iotype != IOHERE) cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0)); /* Used for tracing and error messages to print expanded cp */ iotmp = *iop; iotmp.name = (iotype == IOHERE) ? NULL : cp; iotmp.flag |= IONAMEXP; if (Flag(FXTRACE)) { change_xtrace(2, false); fptreef(shl_xtrace, 0, "%R", &iotmp); change_xtrace(1, false); } switch (iotype) { case IOREAD: flags = O_RDONLY; break; case IOCAT: flags = O_WRONLY | O_APPEND | O_CREAT; break; case IOWRITE: flags = O_WRONLY | O_CREAT | O_TRUNC; /* * The stat() is here to allow redirections to * things like /dev/null without error. */ if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) && (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode))) flags |= O_EXCL; break; case IORDWR: flags = O_RDWR | O_CREAT; break; case IOHERE: do_open = false; /* herein() returns -2 if error has been printed */ u = herein(iop, NULL); /* cp may have wrong name */ break; case IODUP: { const char *emsg; do_open = false; if (*cp == '-' && !cp[1]) { /* prevent error return below */ u = 1009; do_close = true; } else if ((u = check_fd(cp, X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK), &emsg)) < 0) { char *sp; warningf(true, "%s: %s", (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg); afree(sp, ATEMP); return (-1); } if (u == iop->unit) /* "dup from" == "dup to" */ return (0); break; } } if (do_open) { if (Flag(FRESTRICTED) && (flags & O_CREAT)) { warningf(true, "%s: %s", cp, "restricted"); return (-1); } u = open(cp, flags | O_BINARY, 0666); } if (u < 0) { /* herein() may already have printed message */ if (u == -1) { u = errno; warningf(true, "can't %s %s: %s", iotype == IODUP ? "dup" : (iotype == IOREAD || iotype == IOHERE) ? "open" : "create", cp, cstrerror(u)); } return (-1); } /* Do not save if it has already been redirected (i.e. "cat >x >y"). */ if (e->savefd[iop->unit] == 0) { /* If these are the same, it means unit was previously closed */ if (u == iop->unit) e->savefd[iop->unit] = -1; else /* * c_exec() assumes e->savefd[fd] set for any * redirections. Ask savefd() not to close iop->unit; * this allows error messages to be seen if iop->unit * is 2; also means we can't lose the fd (eg, both * dup2 below and dup2 in restfd() failing). */ e->savefd[iop->unit] = savefd(iop->unit); } if (do_close) close(iop->unit); else if (u != iop->unit) { if (ksh_dup2(u, iop->unit, true) < 0) { int eno; char *sp; eno = errno; warningf(true, "%s %s %s", "can't finish (dup) redirection", (sp = snptreef(NULL, 32, "%R", &iotmp)), cstrerror(eno)); afree(sp, ATEMP); if (iotype != IODUP) close(u); return (-1); } if (iotype != IODUP) close(u); /* * Touching any co-process fd in an empty exec * causes the shell to close its copies */ else if (tp && tp->type == CSHELL && tp->val.f == c_exec) { if (iop->flag & IORDUP) /* possible exec <&p */ coproc_read_close(u); else /* possible exec >&p */ coproc_write_close(u); } } if (u == 2) /* Clear any write errors */ shf_reopen(2, SHF_WR, shl_out); return (0); }