/* Initialize tty_fd. Used for saving/resetting tty modes upon * foreground job completion and for setting up tty process group. */ void tty_init(int init_ttystate) { int do_close = 1; int tfd; tty_close(); tty_devtty = 1; tfd = open("/dev/tty", O_RDWR, 0); if (tfd < 0) { tty_devtty = 0; warningf(false, "No controlling tty (open /dev/tty: %s)", strerror(errno)); do_close = 0; if (isatty(0)) tfd = 0; else if (isatty(2)) tfd = 2; else { warningf(false, "Can't find tty file descriptor"); return; } } if ((tty_fd = fcntl(tfd, F_DUPFD_CLOEXEC, FDBASE)) < 0) { warningf(false, "j_ttyinit: dup of tty fd failed: %s", strerror(errno)); } else if (init_ttystate) tcgetattr(tty_fd, &tty_state); if (do_close) close(tfd); }
static void handle_attribute_alias(const attribute_t *attribute, entity_t *entity) { const attribute_argument_t *argument = attribute->a.arguments; string_t const *const string = get_argument_string(argument); if (string == NULL) { errorf(&attribute->pos, "attribute 'alias' requires a string argument"); return; } symbol_t *const symbol = symbol_table_insert(string->begin); switch (entity->kind) { case ENTITY_VARIABLE: entity->variable.alias.symbol = symbol; break; case ENTITY_FUNCTION: entity->function.alias.symbol = symbol; break; default: warningf(WARN_OTHER, &attribute->pos, "alias attribute on %N ignored", entity); return; } declaration_t *decl = &entity->declaration; if (decl->storage_class == STORAGE_CLASS_EXTERN) { /* code generator will ignore the extern declaration */ warningf(WARN_OTHER, &entity->base.pos, "extern storage class ignored for alias %N", entity); } ARR_APP1(entity_t*, alias_entities, entity); }
static int herein(struct ioword *iop, char **resbuf) { int fd = -1; struct shf *shf; struct temp *h; int i; /* ksh -c 'cat << EOF' can cause this... */ if (iop->heredoc == NULL) { warningf(true, "%s missing", "here document"); /* special to iosetup(): don't print error */ return (-2); } /* lexer substitution flags */ i = (iop->flag & IOEVAL) ? (ONEWORD | HEREDOC) : 0; /* skip all the fd setup if we just want the value */ if (resbuf != NULL) return (hereinval(iop->heredoc, i, resbuf, NULL)); /* * Create temp file to hold content (done before newenv * so temp doesn't get removed too soon). */ h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps); if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY, 0)) < 0) { i = errno; warningf(true, "can't %s temporary file %s: %s", !shf ? "create" : "open", h->tffn, cstrerror(i)); if (shf) shf_close(shf); /* special to iosetup(): don't print error */ return (-2); } if (hereinval(iop->heredoc, i, NULL, shf) == -2) { close(fd); /* special to iosetup(): don't print error */ return (-2); } if (shf_close(shf) == EOF) { i = errno; close(fd); warningf(true, "can't %s temporary file %s: %s", "write", h->tffn, cstrerror(i)); /* special to iosetup(): don't print error */ return (-2); } return (fd); }
int c_brkcont(char **wp) { int n, quit; struct env *ep, *last_ep = NULL; char *arg; if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; arg = wp[builtin_opt.optind]; if (!arg) n = 1; else if (!bi_getn(arg, &n)) return 1; quit = n; if (quit <= 0) { /* at&t ksh does this for non-interactive shells only - weird */ bi_errorf("%s: bad value", arg); return 1; } /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */ for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv) if (ep->type == E_LOOP) { if (--quit == 0) break; ep->flags |= EF_BRKCONT_PASS; last_ep = ep; } if (quit) { /* at&t ksh doesn't print a message - just does what it * can. We print a message 'cause it helps in debugging * scripts, but don't generate an error (ie, keep going). */ if (n == quit) { warningf(true, "%s: cannot %s", wp[0], wp[0]); return 0; } /* POSIX says if n is too big, the last enclosing loop * shall be used. Doesn't say to print an error but we * do anyway 'cause the user messed up. */ if (last_ep) last_ep->flags &= ~EF_BRKCONT_PASS; warningf(true, "%s: can only %s %d level(s)", wp[0], wp[0], n - quit); } unwind(*wp[0] == 'b' ? LBREAK : LCONTIN); /* NOTREACHED */ }
/* suspend the shell */ void j_suspend(void) { struct sigaction sa, osa; /* Restore tty and pgrp. */ if (ttypgrp_ok) { tcsetattr(tty_fd, TCSADRAIN, &tty_state); if (restore_ttypgrp >= 0) { if (tcsetpgrp(tty_fd, restore_ttypgrp) < 0) { warningf(false, "j_suspend: tcsetpgrp() failed: %s", strerror(errno)); } else { if (setpgid(0, restore_ttypgrp) < 0) { warningf(false, "j_suspend: setpgid() failed: %s", strerror(errno)); } } } } /* Suspend the shell. */ memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_handler = SIG_DFL; sigaction(SIGTSTP, &sa, &osa); kill(0, SIGTSTP); /* Back from suspend, reset signals, pgrp and tty. */ sigaction(SIGTSTP, &osa, NULL); if (ttypgrp_ok) { if (restore_ttypgrp >= 0) { if (setpgid(0, kshpid) < 0) { warningf(false, "j_suspend: setpgid() failed: %s", strerror(errno)); ttypgrp_ok = 0; } else { if (tcsetpgrp(tty_fd, kshpid) < 0) { warningf(false, "j_suspend: tcsetpgrp() failed: %s", strerror(errno)); ttypgrp_ok = 0; } } } tty_init(true); } }
type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type) { type_t *type = skip_typeref(orig_type); /* at least: byte, word, pointer, list of machine modes * __XXX___ is interpreted as XXX */ /* This isn't really correct, the backend should provide a list of machine * specific modes (according to gcc philosophy that is...) */ attribute_argument_t *arg = attribute->a.arguments; if (arg == NULL) { errorf(&attribute->pos, "__attribute__((mode(X))) misses argument"); return orig_type; } const char *symbol_str = arg->v.symbol->string; bool sign = is_type_signed(type); atomic_type_kind_t akind; if (streq_underscore("QI", symbol_str) || streq_underscore("byte", symbol_str)) { akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR; } else if (streq_underscore("HI", symbol_str)) { akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT; } else if (streq_underscore("SI", symbol_str) || streq_underscore("word", symbol_str) || streq_underscore("pointer", symbol_str)) { akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT; } else if (streq_underscore("DI", symbol_str)) { akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG; } else { warningf(WARN_OTHER, &attribute->pos, "ignoring unknown mode '%s'", symbol_str); return orig_type; } if (type->kind == TYPE_ATOMIC || type->kind == TYPE_ENUM) { type_t *copy = duplicate_type(type); copy->atomic.akind = akind; return identify_new_type(copy); } else if (is_type_pointer(type)) { warningf(WARN_OTHER, &attribute->pos, "__attribute__((mode)) on pointers not implemented yet (ignored)"); return type; } errorf(&attribute->pos, "__attribute__((mode)) only allowed on integer, enum or pointer type"); return orig_type; }
static void handle_attribute_aligned(const attribute_t *attribute, entity_t *entity) { int alignment = 32; /* TODO: fill in maximum useful alignment for target machine */ if (attribute->a.arguments) { attribute_argument_t *argument = attribute->a.arguments; alignment = fold_expression_to_int(argument->v.expression); } if (!is_po2(alignment)) { errorf(&attribute->pos, "alignment must be a power of 2 but is %d", alignment); return; } if (alignment <= 0) { errorf(&attribute->pos, "alignment must be bigger than 0 but is %d", alignment); return; } switch (entity->kind) { case DECLARATION_KIND_CASES: entity->declaration.alignment = alignment; break; case ENTITY_STRUCT: case ENTITY_UNION: entity->compound.alignment = MAX(entity->compound.alignment, alignment); break; default: warningf(WARN_OTHER, &attribute->pos, "alignment attribute specification on %N ignored", entity); break; } }
static void handle_attribute_visibility(const attribute_t *attribute, entity_t *entity) { /* This isn't really correct, the backend should provide a list of machine * specific modes (according to gcc philosophy that is...) */ string_t const *const string = get_argument_string(attribute->a.arguments); if (string == NULL) { errorf(&attribute->pos, "__attribute__((visibility(X))) requires a string argument"); return; } elf_visibility_t visibility = get_elf_visibility_from_string(string->begin); if (visibility == ELF_VISIBILITY_ERROR) { errorf(&attribute->pos, "unknown visibility type '%S'", string); return; } switch (entity->kind) { case ENTITY_VARIABLE: entity->variable.elf_visibility = visibility; break; case ENTITY_FUNCTION: entity->function.elf_visibility = visibility; break; default: warningf(WARN_OTHER, &attribute->pos, "visibility attribute specification on %N ignored", entity); break; } }
/* wait for last job: only used for `command` jobs */ int waitlast(void) { int rv; Job *j; sigset_t omask; sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); j = last_job; if (!j || !(j->flags & JF_STARTED)) { if (!j) warningf(true, "waitlast: no last job"); else internal_errorf(0, "waitlast: not started"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); return 125; /* not so arbitrary, non-zero value */ } rv = j_waitj(j, JW_NONE, "jw:waitlast"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); return rv; }
/* set variable to string value */ int setstr(struct tbl *vq, const char *s, int error_ok) { const char *fs = NULL; int no_ro_check = error_ok & 0x4; error_ok &= ~0x4; if ((vq->flag & RDONLY) && !no_ro_check) { warningf(true, "%s: is read only", vq->name); if (!error_ok) errorf(null); return 0; } if (!(vq->flag&INTEGER)) { /* string dest */ if ((vq->flag&ALLOC)) { /* debugging */ if (s >= vq->val.s && s <= vq->val.s + strlen(vq->val.s)) internal_errorf(true, "setstr: %s=%s: assigning to self", vq->name, s); afree((void*)vq->val.s, vq->areap); } vq->flag &= ~(ISSET|ALLOC); vq->type = 0; if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) fs = s = formatstr(vq, s); if ((vq->flag&EXPORT)) export(vq, s); else { vq->val.s = str_save(s, vq->areap); vq->flag |= ALLOC; } } else { /* integer dest */
static void handle_attribute_packed_e(const attribute_t *attribute, entity_t *entity) { warn_arguments(attribute); if (entity->kind == ENTITY_STRUCT) { compound_t *compound = &entity->compound; compound->packed = true; /* GCC: Specifying this attribute for `struct' and `union' types is * equivalent to specifying the `packed' attribute on each of the * structure or union members. */ for (entity_t *member = compound->members.first_entity; member != NULL; member = member->base.next) { if (member->kind != ENTITY_COMPOUND_MEMBER) continue; member->declaration.modifiers |= DM_PACKED; } } else if (is_declaration(entity)) { entity->declaration.modifiers |= DM_PACKED; } else { position_t const *const pos = &attribute->pos; warningf(WARN_OTHER, pos, "packed attribute on entity %N ignored", entity); return; } }
bool protocolUpdate(int pSocket, fd_set *pSocketSet, int pMaxSocket, int pBufferSize) { UNUSED(pMaxSocket); bufferGrow(&gMessageBuffer, pBufferSize); bufferClear(&gMessageBuffer); infof("Communication on socket %d.\n", pSocket); // send(), recv(), close() // Call FD_CLR(pSocket, pSocketSet) on disconnection bool success = true; int messageSize; int flags = 0; // Receive a message from client messageSize = recv(pSocket, gMessageBuffer->buffer, gMessageBuffer->size, flags); if (0 < messageSize) { // Return the message to the sender networkMessagePrivate(pSocket, gMessageBuffer->buffer); } else if (0 == messageSize) { close(pSocket); FD_CLR(pSocket, pSocketSet); noticef("Client disconnected from socket %d.\n", pSocket); fflush(stdout); } else if (messageSize < 0) { warningf("Failed to receive data from socket %d.", pSocket); success = false; } return success; }
/* * run any pending traps. If intr is set, only run traps that * can interrupt commands. */ void runtraps(int flag) { int i; Trap *p; if (ksh_tmout_state == TMOUT_LEAVING) { ksh_tmout_state = TMOUT_EXECUTING; warningf(false, "timed out waiting for input"); unwind(LEXIT); } else /* XXX: this means the alarm will have no effect if a trap * is caught after the alarm() was started...not good. */ ksh_tmout_state = TMOUT_EXECUTING; if (!flag) trap = 0; if (flag & TF_DFL_INTR) intrsig = 0; if (flag & TF_FATAL) fatal_trap = 0; for (p = sigtraps, i = NSIG+1; --i >= 0; p++) if (p->set && (!flag || ((p->flags & flag) && p->trap == (char *) 0))) runtrap(p); }
void myfileopt(const char* fn, const struct cmdinfo* cmdinfos) { FILE* file; char linebuf[MAXDIVERTFILENAME]; file= fopen(fn, "r"); if (!file) { if (errno==ENOENT) return; warningf(_("failed to open configuration file `%.255s' for reading"),fn); return; } while (fgets(linebuf, sizeof(linebuf), file)) { char* opt; const struct cmdinfo *cip; int l; if ((linebuf[0]=='#') || (linebuf[0]=='\n') || (linebuf[0]==0)) continue; l=strlen(linebuf); if (linebuf[l-1]=='\n') linebuf[l-1]=0; for (opt=linebuf;isalnum(*opt)||*opt=='-';opt++) ; if (*opt==0) opt=NULL; else { *opt++=0; if (*opt=='=') opt++; while (isspace(*opt)) opt++; } for (cip=cmdinfos; cip->olong || cip->oshort; cip++) { int l; if (!cip->olong) continue; if (!strcmp(cip->olong,linebuf)) break; l=strlen(cip->olong); if ((cip->takesvalue==2) && (linebuf[l]=='-') && !opt && !strncmp(linebuf,cip->olong,l)) { opt=linebuf+l+1; break; } } if (!cip->olong) ohshite(_("configuration error: unknown option %s"), linebuf); if (cip->takesvalue) { if (!opt) ohshite(_("configuration error: %s needs a value"), linebuf); if (cip->call) cip->call(cip,opt); else *cip->sassignto = m_strdup(opt); } else { if (opt) ohshite(_("configuration error: %s does not take a value"), linebuf); if (cip->call) cip->call(cip,NULL); else *cip->iassignto= cip->arg; } } if (ferror(file)) ohshite(_("read error in configuration file `%.255s'"), fn); if (fclose(file)) ohshite(_("error closing configuration file `%.255s'"), fn); }
static void warn_arguments(const attribute_t *attribute) { if (attribute->a.arguments == NULL) return; position_t const *const pos = &attribute->pos; char const *const what = get_attribute_name(attribute->kind); warningf(WARN_OTHER, pos, "attribute '%s' needs no arguments", what); }
static void handle_attribute_packed(const attribute_t *attribute, type_t *type) { if (type->kind != TYPE_COMPOUND_STRUCT) { position_t const *const pos = &attribute->pos; warningf(WARN_OTHER, pos, "packed attribute on type '%T' ignored", type); return; } handle_attribute_packed_e(attribute, (entity_t*) type->compound.compound); }
/* set variable to string value */ int setstr(struct tbl *vq, const char *s, int error_ok) { char *salloc = NULL; bool no_ro_check = tobool(error_ok & 0x4); error_ok &= ~0x4; if ((vq->flag & RDONLY) && !no_ro_check) { warningf(true, "read-only: %s", vq->name); if (!error_ok) errorfxz(2); return (0); } if (!(vq->flag&INTEGER)) { /* string dest */ if ((vq->flag&ALLOC)) { #ifndef MKSH_SMALL /* debugging */ if (s >= vq->val.s && s <= vq->val.s + strlen(vq->val.s)) { internal_errorf( "setstr: %s=%s: assigning to self", vq->name, s); } #endif afree(vq->val.s, vq->areap); } vq->flag &= ~(ISSET|ALLOC); vq->type = 0; if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST))) s = salloc = formatstr(vq, s); if ((vq->flag&EXPORT)) exportprep(vq, s); else { strdupx(vq->val.s, s, vq->areap); vq->flag |= ALLOC; } } else { /* integer dest */ if (!v_evaluate(vq, s, error_ok, true)) return (0); } vq->flag |= ISSET; if ((vq->flag&SPECIAL)) setspec(vq); afree(salloc, ATEMP); return (1); }
int c_exitreturn(char **wp) { int how = LEXIT; int n; char *arg; if (!Flag(FPOSIX) // not posix && *wp && *(wp + 1) && !*(wp + 2)) // only one argument passed arg=*(wp + 1); // code regardless of starting with '-' or not else { if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; arg = wp[builtin_opt.optind]; } if (arg) { if (!getn(arg, &n)) { exstat = 1; warningf(true, "%s: bad number", arg); } else exstat = n; } if (wp[0][0] == 'r') { /* return */ struct env *ep; /* need to tell if this is exit or return so trap exit will * work right (POSIX) */ for (ep = e; ep; ep = ep->oenv) if (STOP_RETURN(ep->type)) { how = LRETURN; break; } } if (how == LEXIT && !really_exit && j_stopped_running()) { really_exit = 1; how = LSHELL; } quitenv(); /* get rid of any i/o redirections */ unwind(how); /*NOTREACHED*/ return 0; }
static void array_qualifiers(node_t * atype) { int cons, vol, res; int *p; cons = vol = res = 0; while (token->kind == CONST) { int t = token->id; struct source src = source; switch (t) { case CONST: p = &cons; gettok(); break; case VOLATILE: p = &vol; gettok(); break; case RESTRICT: p = &res; gettok(); break; default: cc_assert(0); } if (*p != 0) warningf(src, "duplicate type qualifier '%s'", id2s(*p)); *p = t; } if (cons) TYPE_A_CONST(atype) = 1; if (vol) TYPE_A_VOLATILE(atype) = 1; if (res) TYPE_A_RESTRICT(atype) = 1; }
int c_exitreturn(char **wp) { int how = LEXIT; int n; char *arg; if (ksh_getopt(wp, &builtin_opt, null) == '?') return 1; arg = wp[builtin_opt.optind]; if (arg) { if (!getn(arg, &n)) { exstat = 1; warningf(true, "%s: bad number", arg); } else exstat = n; } if (wp[0][0] == 'r') { /* return */ struct env *ep; /* need to tell if this is exit or return so trap exit will * work right (POSIX) */ for (ep = e; ep; ep = ep->oenv) if (STOP_RETURN(ep->type)) { how = LRETURN; break; } } if (how == LEXIT && !really_exit && j_stopped_running()) { really_exit = 1; how = LSHELL; } quitenv(NULL); /* get rid of any i/o redirections */ unwind(how); /* NOTREACHED */ return 0; }
type_t *handle_type_attributes(const attribute_t *attributes, type_t *type) { const attribute_t *attribute = attributes; for ( ; attribute != NULL; attribute = attribute->next) { switch (attribute->kind) { case ATTRIBUTE_GNU_PACKED: handle_attribute_packed(attribute, type); break; case ATTRIBUTE_GNU_CDECL: case ATTRIBUTE_MS_CDECL: type = change_calling_convention(type, CC_CDECL); break; case ATTRIBUTE_MS_STDCALL: case ATTRIBUTE_GNU_STDCALL: if (dialect.support_fastcall_stdcall) { type = change_calling_convention(type, CC_STDCALL); } else { warningf(WARN_OTHER, &attribute->pos, "Ignoring attribute 'stdcall' for this target"); } break; case ATTRIBUTE_MS_FASTCALL: case ATTRIBUTE_GNU_FASTCALL: if (dialect.support_fastcall_stdcall) { type = change_calling_convention(type, CC_FASTCALL); } else { warningf(WARN_OTHER, &attribute->pos, "Ignoring attribute 'fastcall' for this target"); } break; case ATTRIBUTE_MS_THISCALL: type = change_calling_convention(type, CC_THISCALL); break; case ATTRIBUTE_GNU_RETURNS_TWICE: case ATTRIBUTE_MS_RETURNS_TWICE: type = add_modifiers(type, DM_RETURNS_TWICE); break; case ATTRIBUTE_GNU_NORETURN: case ATTRIBUTE_MS_NORETURN: type = add_modifiers(type, DM_NORETURN); break; case ATTRIBUTE_GNU_MALLOC: case ATTRIBUTE_MS_ALLOCATE: type = add_modifiers(type, DM_MALLOC); break; case ATTRIBUTE_GNU_CONST: type = add_modifiers(type, DM_CONST); break; case ATTRIBUTE_GNU_PURE: type = add_modifiers(type, DM_PURE); break; case ATTRIBUTE_GNU_NOTHROW: case ATTRIBUTE_MS_NOTHROW: type = add_modifiers(type, DM_NOTHROW); break; case ATTRIBUTE_GNU_MODE: type = handle_attribute_mode(attribute, type); break; default: break; } } return type; }
/* fg and bg built-ins: called only if Flag(FMONITOR) set */ int j_resume(const char *cp, int bg) { Job *j; Proc *p; int ecode; int running; int rv = 0; sigset_t omask; sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); if ((j = j_lookup(cp, &ecode)) == (Job *) 0) { sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); bi_errorf("%s: %s", cp, lookup_msgs[ecode]); return 1; } if (j->pgrp == 0) { sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); bi_errorf("job not job-controlled"); return 1; } if (bg) shprintf("[%d] ", j->job); running = 0; for (p = j->proc_list; p != (Proc *) 0; p = p->next) { if (p->state == PSTOPPED) { p->state = PRUNNING; p->status = 0; running = 1; } shprintf("%s%s", p->command, p->next ? "| " : null); } shprintf("%s", newline); shf_flush(shl_stdout); if (running) j->state = PRUNNING; put_job(j, PJ_PAST_STOPPED); if (bg) j_set_async(j); else { # ifdef JOBS /* attach tty to job */ if (j->state == PRUNNING) { if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) tcsetattr(tty_fd, TCSADRAIN, &j->ttystate); /* See comment in j_waitj regarding saved_ttypgrp. */ if (ttypgrp_ok && tcsetpgrp(tty_fd, (j->flags & JF_SAVEDTTYPGRP) ? j->saved_ttypgrp : j->pgrp) < 0) { if (j->flags & JF_SAVEDTTY) tcsetattr(tty_fd, TCSADRAIN, &tty_state); sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); bi_errorf("1st tcsetpgrp(%d, %d) failed: %s", tty_fd, (int) ((j->flags & JF_SAVEDTTYPGRP) ? j->saved_ttypgrp : j->pgrp), strerror(errno)); return 1; } } # endif /* JOBS */ j->flags |= JF_FG; j->flags &= ~JF_KNOWN; if (j == async_job) async_job = (Job *) 0; } if (j->state == PRUNNING && killpg(j->pgrp, SIGCONT) < 0) { int err = errno; if (!bg) { j->flags &= ~JF_FG; # ifdef JOBS if (ttypgrp_ok && (j->flags & JF_SAVEDTTY)) tcsetattr(tty_fd, TCSADRAIN, &tty_state); if (ttypgrp_ok && tcsetpgrp(tty_fd, our_pgrp) < 0) { warningf(true, "fg: 2nd tcsetpgrp(%d, %d) failed: %s", tty_fd, (int) our_pgrp, strerror(errno)); } # endif /* JOBS */ } sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); bi_errorf("cannot continue job %s: %s", cp, strerror(err)); return 1; } if (!bg) { # ifdef JOBS if (ttypgrp_ok) { j->flags &= ~(JF_SAVEDTTY | JF_SAVEDTTYPGRP); } # endif /* JOBS */ rv = j_waitj(j, JW_NONE, "jw:resume"); } sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0); return rv; }
/* * wait for job to complete or change state * * If jobs are compiled in then this routine expects sigchld to be blocked. */ static int j_waitj(Job *j, int flags, /* see JW_* */ const char *where) { int rv; /* * No auto-notify on the job we are waiting on. */ j->flags |= JF_WAITING; if (flags & JW_ASYNCNOTIFY) j->flags |= JF_W_ASYNCNOTIFY; if (!Flag(FMONITOR)) flags |= JW_STOPPEDWAIT; while ((volatile int) j->state == PRUNNING || ((flags & JW_STOPPEDWAIT) && (volatile int) j->state == PSTOPPED)) { sigsuspend(&sm_default); if (fatal_trap) { int oldf = j->flags & (JF_WAITING|JF_W_ASYNCNOTIFY); j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); runtraps(TF_FATAL); j->flags |= oldf; /* not reached... */ } if ((flags & JW_INTERRUPT) && (rv = trap_pending())) { j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); return -rv; } } j->flags &= ~(JF_WAITING|JF_W_ASYNCNOTIFY); if (j->flags & JF_FG) { int status; j->flags &= ~JF_FG; #ifdef JOBS if (Flag(FMONITOR) && ttypgrp_ok && j->pgrp) { /* * Save the tty's current pgrp so it can be restored * when the job is foregrounded. This is to * deal with things like the GNU su which does * a fork/exec instead of an exec (the fork means * the execed shell gets a different pid from its * pgrp, so naturally it sets its pgrp and gets hosed * when it gets foregrounded by the parent shell, which * has restored the tty's pgrp to that of the su * process). */ if (j->state == PSTOPPED && (j->saved_ttypgrp = tcgetpgrp(tty_fd)) >= 0) j->flags |= JF_SAVEDTTYPGRP; if (tcsetpgrp(tty_fd, our_pgrp) < 0) { warningf(true, "j_waitj: tcsetpgrp(%d, %d) failed: %s", tty_fd, (int) our_pgrp, strerror(errno)); } if (j->state == PSTOPPED) { j->flags |= JF_SAVEDTTY; tcgetattr(tty_fd, &j->ttystate); } } #endif /* JOBS */ if (tty_fd >= 0) { /* Only restore tty settings if job was originally * started in the foreground. Problems can be * caused by things like `more foobar &' which will * typically get and save the shell's vi/emacs tty * settings before setting up the tty for itself; * when more exits, it restores the `original' * settings, and things go down hill from there... */ if (j->state == PEXITED && j->status == 0 && (j->flags & JF_USETTYMODE)) { tcgetattr(tty_fd, &tty_state); } else { tcsetattr(tty_fd, TCSADRAIN, &tty_state); /* Don't use tty mode if job is stopped and * later restarted and exits. Consider * the sequence: * vi foo (stopped) * ... * stty something * ... * fg (vi; ZZ) * mode should be that of the stty, not what * was before the vi started. */ if (j->state == PSTOPPED) j->flags &= ~JF_USETTYMODE; } } #ifdef JOBS /* If it looks like user hit ^C to kill a job, pretend we got * one too to break out of for loops, etc. (at&t ksh does this * even when not monitoring, but this doesn't make sense since * a tty generated ^C goes to the whole process group) */ status = j->last_proc->status; if (Flag(FMONITOR) && j->state == PSIGNALLED && WIFSIGNALED(status) && (sigtraps[WTERMSIG(status)].flags & TF_TTY_INTR)) trapsig(WTERMSIG(status)); #endif /* JOBS */ } j_usrtime = j->usrtime; j_systime = j->systime; rv = j->status; if (!(flags & JW_ASYNCNOTIFY) && (!Flag(FMONITOR) || j->state != PSTOPPED)) { j_print(j, JP_SHORT, shl_out); shf_flush(shl_out); } if (j->state != PSTOPPED && (!Flag(FMONITOR) || !(flags & JW_ASYNCNOTIFY))) remove_job(j, where); return rv; }
void layout_struct_type(compound_type_t *type) { assert(type->compound != NULL); compound_t *compound = type->compound; if (!compound->complete) return; if (type->compound->layouted) return; il_size_t offset = 0; il_alignment_t alignment = compound->alignment; bool need_pad = false; entity_t *entry = compound->members.entities; while (entry != NULL) { if (entry->kind != ENTITY_COMPOUND_MEMBER) { entry = entry->base.next; continue; } type_t *const m_type = skip_typeref(entry->declaration.type); if (!is_type_valid(m_type)) { entry = entry->base.next; continue; } if (entry->compound_member.bitfield) { entry = pack_bitfield_members(&offset, &alignment, compound->packed, entry); continue; } il_alignment_t m_alignment = get_type_alignment_compound(m_type); if (m_alignment > alignment) alignment = m_alignment; if (!compound->packed) { il_size_t new_offset = (offset + m_alignment-1) & -m_alignment; if (new_offset > offset) { need_pad = true; offset = new_offset; } } entry->compound_member.offset = offset; offset += get_type_size(m_type); entry = entry->base.next; } if (!compound->packed) { il_size_t new_offset = (offset + alignment-1) & -alignment; if (new_offset > offset) { need_pad = true; offset = new_offset; } } source_position_t const *const pos = &compound->base.source_position; if (need_pad) { warningf(WARN_PADDED, pos, "'%T' needs padding", type); } else if (compound->packed) { warningf(WARN_PACKED, pos, "superfluous packed attribute on '%T'", type); } compound->size = offset; compound->alignment = alignment; compound->layouted = true; }
static int comexec(struct op *t, struct tbl * volatile tp, const char **ap, volatile int flags, volatile int *xerrok) { int i; volatile int rv = 0; const char *cp; const char **lastp; /* Must be static (XXX but why?) */ static struct op texec; int type_flags; bool keepasn_ok; int fcflags = FC_BI|FC_FUNC|FC_PATH; bool bourne_function_call = false; struct block *l_expand, *l_assign; /* * snag the last argument for $_ XXX not the same as AT&T ksh, * which only seems to set $_ after a newline (but not in * functions/dot scripts, but in interactive and script) - * perhaps save last arg here and set it in shell()?. */ if (Flag(FTALKING) && *(lastp = ap)) { while (*++lastp) ; /* setstr() can't fail here */ setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp, KSH_RETURN_ERROR); } /** * Deal with the shell builtins builtin, exec and command since * they can be followed by other commands. This must be done before * we know if we should create a local block which must be done * before we can do a path search (in case the assignments change * PATH). * Odd cases: * FOO=bar exec >/dev/null FOO is kept but not exported * FOO=bar exec foobar FOO is exported * FOO=bar command exec >/dev/null FOO is neither kept nor exported * FOO=bar command FOO is neither kept nor exported * PATH=... foobar use new PATH in foobar search */ keepasn_ok = true; while (tp && tp->type == CSHELL) { /* undo effects of command */ fcflags = FC_BI|FC_FUNC|FC_PATH; if (tp->val.f == c_builtin) { if ((cp = *++ap) == NULL || (!strcmp(cp, "--") && (cp = *++ap) == NULL)) { tp = NULL; break; } if ((tp = findcom(cp, FC_BI)) == NULL) errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin"); continue; } else if (tp->val.f == c_exec) { if (ap[1] == NULL) break; ap++; flags |= XEXEC; } else if (tp->val.f == c_command) { int optc, saw_p = 0; /* * Ugly dealing with options in two places (here * and in c_command(), but such is life) */ ksh_getopt_reset(&builtin_opt, 0); while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p') saw_p = 1; if (optc != EOF) /* command -vV or something */ break; /* don't look for functions */ fcflags = FC_BI|FC_PATH; if (saw_p) { if (Flag(FRESTRICTED)) { warningf(true, "%s: %s", "command -p", "restricted"); rv = 1; goto Leave; } fcflags |= FC_DEFPATH; } ap += builtin_opt.optind; /* * POSIX says special builtins lose their status * if accessed using command. */ keepasn_ok = false; if (!ap[0]) { /* ensure command with no args exits with 0 */ subst_exstat = 0; break; } #ifndef MKSH_NO_EXTERNAL_CAT } else if (tp->val.f == c_cat) { /* * if we have any flags, do not use the builtin * in theory, we could allow -u, but that would * mean to use ksh_getopt here and possibly ad- * ded complexity and more code and isn't worth * additional hassle (and the builtin must call * ksh_getopt already but can't come back here) */ if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' && /* argument, begins with -, is not - or -- */ (ap[1][1] != '-' || ap[1][2] != '\0')) /* don't look for builtins or functions */ fcflags = FC_PATH; else /* go on, use the builtin */ break; #endif #if !defined(MKSH_SMALL) } else if (tp->val.f == c_trap) { t->u.evalflags &= ~DOTCOMEXEC; break; #endif } else break; tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC)); } #if !defined(MKSH_SMALL) if (t->u.evalflags & DOTCOMEXEC) flags |= XEXEC; #endif l_expand = e->loc; if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN)))) type_flags = 0; else { /* create new variable/function block */ newblock(); /* ksh functions don't keep assignments, POSIX functions do. */ if (keepasn_ok && tp && tp->type == CFUNC && !(tp->flag & FKSH)) { bourne_function_call = true; type_flags = EXPORT; } else type_flags = LOCAL|LOCAL_COPY|EXPORT; } l_assign = e->loc; if (Flag(FEXPORT)) type_flags |= EXPORT; for (i = 0; t->vars[i]; i++) { /* do NOT lookup in the new var/fn block just created */ e->loc = l_expand; cp = evalstr(t->vars[i], DOASNTILDE); e->loc = l_assign; /* but assign in there as usual */ if (Flag(FXTRACE)) { if (i == 0) shf_puts(substitute(str_val(global("PS4")), 0), shl_out); shf_fprintf(shl_out, "%s%c", cp, t->vars[i + 1] ? ' ' : '\n'); if (!t->vars[i + 1]) shf_flush(shl_out); } typeset(cp, type_flags, 0, 0, 0); if (bourne_function_call && !(type_flags & EXPORT)) typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0); } if ((cp = *ap) == NULL) { rv = subst_exstat; goto Leave; } else if (!tp) { if (Flag(FRESTRICTED) && vstrchr(cp, '/')) { warningf(true, "%s: %s", cp, "restricted"); rv = 1; goto Leave; } tp = findcom(cp, fcflags); } switch (tp->type) { /* shell built-in */ case CSHELL: rv = call_builtin(tp, (const char **)ap, null); if (!keepasn_ok && tp->val.f == c_shift) { l_expand->argc = l_assign->argc; l_expand->argv = l_assign->argv; } break; /* function call */ case CFUNC: { volatile unsigned char old_xflag; volatile uint32_t old_inuse; const char * volatile old_kshname; if (!(tp->flag & ISSET)) { struct tbl *ftp; if (!tp->u.fpath) { rv = (tp->u2.errnov == ENOENT) ? 127 : 126; warningf(true, "%s: %s %s: %s", cp, "can't find", "function definition file", cstrerror(tp->u2.errnov)); break; } if (include(tp->u.fpath, 0, NULL, false) < 0) { rv = errno; warningf(true, "%s: %s %s %s: %s", cp, "can't open", "function definition file", tp->u.fpath, cstrerror(rv)); rv = 127; break; } if (!(ftp = findfunc(cp, hash(cp), false)) || !(ftp->flag & ISSET)) { warningf(true, "%s: %s %s", cp, "function not defined by", tp->u.fpath); rv = 127; break; } tp = ftp; } /* * ksh functions set $0 to function name, POSIX * functions leave $0 unchanged. */ old_kshname = kshname; if (tp->flag & FKSH) kshname = ap[0]; else ap[0] = kshname; e->loc->argv = ap; for (i = 0; *ap++ != NULL; i++) ; e->loc->argc = i - 1; /* * ksh-style functions handle getopts sanely, * Bourne/POSIX functions are insane... */ if (tp->flag & FKSH) { e->loc->flags |= BF_DOGETOPTS; e->loc->getopts_state = user_opt; getopts_reset(1); } old_xflag = Flag(FXTRACE); Flag(FXTRACE) |= tp->flag & TRACE ? 1 : 0; old_inuse = tp->flag & FINUSE; tp->flag |= FINUSE; e->type = E_FUNC; if (!(i = kshsetjmp(e->jbuf))) { execute(tp->val.t, flags & XERROK, NULL); i = LRETURN; } kshname = old_kshname; Flag(FXTRACE) = old_xflag; tp->flag = (tp->flag & ~FINUSE) | old_inuse; /* * Were we deleted while executing? If so, free the * execution tree. TODO: Unfortunately, the table entry * is never re-used until the lookup table is expanded. */ if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) { if (tp->flag & ALLOC) { tp->flag &= ~ALLOC; tfree(tp->val.t, tp->areap); } tp->flag = 0; } switch (i) { case LRETURN: case LERROR: rv = exstat & 0xFF; break; case LINTR: case LEXIT: case LLEAVE: case LSHELL: quitenv(NULL); unwind(i); /* NOTREACHED */ default: quitenv(NULL); internal_errorf("%s %d", "CFUNC", i); } break; } /* executable command */ case CEXEC: /* tracked alias */ case CTALIAS: if (!(tp->flag&ISSET)) { if (tp->u2.errnov == ENOENT) { rv = 127; warningf(true, "%s: %s", cp, "not found"); } else { rv = 126; warningf(true, "%s: %s: %s", cp, "can't execute", cstrerror(tp->u2.errnov)); } break; } /* set $_ to programme's full path */ /* setstr() can't fail here */ setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s, KSH_RETURN_ERROR); if (flags&XEXEC) { j_exit(); if (!(flags&XBGND) #ifndef MKSH_UNEMPLOYED || Flag(FMONITOR) #endif ) { setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG); setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG); } } /* to fork we set up a TEXEC node and call execute */ texec.type = TEXEC; /* for tprint */ texec.left = t; texec.str = tp->val.s; texec.args = ap; rv = exchild(&texec, flags, xerrok, -1); break; } Leave: if (flags & XEXEC) { exstat = rv & 0xFF; unwind(LLEAVE); } return (rv); }
static int main_init(int argc, const char *argv[], Source **sp, struct block **lp) { int argi, i; Source *s = NULL; struct block *l; unsigned char restricted_shell, errexit, utf_flag; char *cp; const char *ccp, **wp; struct tbl *vp; struct stat s_stdin; #if !defined(_PATH_DEFPATH) && defined(_CS_PATH) ssize_t k; #endif #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC) ebcdic_init(); #endif set_ifs(TC_IFSWS); #ifdef __OS2__ os2_init(&argc, &argv); #endif /* do things like getpgrp() et al. */ chvt_reinit(); /* make sure argv[] is sane, for weird OSes */ if (!*argv) { argv = empty_argv; argc = 1; } kshname = argv[0]; /* initialise permanent Area */ ainit(&aperm); /* max. name length: -2147483648 = 11 (+ NUL) */ vtemp = alloc(offsetof(struct tbl, name[0]) + 12, APERM); /* set up base environment */ env.type = E_NONE; ainit(&env.area); /* set up global l->vars and l->funs */ newblock(); /* Do this first so output routines (eg, errorf, shellf) can work */ initio(); /* determine the basename (without '-' or path) of the executable */ ccp = kshname; goto begin_parsing_kshname; while ((i = ccp[argi++])) { if (mksh_cdirsep(i)) { ccp += argi; begin_parsing_kshname: argi = 0; if (*ccp == '-') ++ccp; } } if (!*ccp) ccp = empty_argv[0]; /* * Turn on nohup by default. (AT&T ksh does not have a nohup * option - it always sends the hup). */ Flag(FNOHUP) = 1; /* * Turn on brace expansion by default. AT&T kshs that have * alternation always have it on. */ Flag(FBRACEEXPAND) = 1; /* * Turn on "set -x" inheritance by default. */ Flag(FXTRACEREC) = 1; /* define built-in commands and see if we were called as one */ ktinit(APERM, &builtins, /* currently up to 54 builtins: 75% of 128 = 2^7 */ 7); for (i = 0; mkshbuiltins[i].name != NULL; i++) if (!strcmp(ccp, builtin(mkshbuiltins[i].name, mkshbuiltins[i].func))) Flag(FAS_BUILTIN) = 1; if (!Flag(FAS_BUILTIN)) { /* check for -T option early */ argi = parse_args(argv, OF_FIRSTTIME, NULL); if (argi < 0) return (1); #if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED) /* are we called as -sh or /bin/sh or so? */ if (!strcmp(ccp, "sh" MKSH_EXE_EXT)) { /* either also turns off braceexpand */ #ifdef MKSH_BINSHPOSIX /* enable better POSIX conformance */ change_flag(FPOSIX, OF_FIRSTTIME, true); #endif #ifdef MKSH_BINSHREDUCED /* enable kludge/compat mode */ change_flag(FSH, OF_FIRSTTIME, true); #endif } #endif } initvar(); inittraps(); coproc_init(); /* set up variable and command dictionaries */ ktinit(APERM, &taliases, 0); ktinit(APERM, &aliases, 0); #ifndef MKSH_NOPWNAM ktinit(APERM, &homedirs, 0); #endif /* define shell keywords */ initkeywords(); init_histvec(); /* initialise tty size before importing environment */ change_winsz(); #ifdef _PATH_DEFPATH def_path = _PATH_DEFPATH; #else #ifdef _CS_PATH if ((k = confstr(_CS_PATH, NULL, 0)) > 0 && confstr(_CS_PATH, cp = alloc(k + 1, APERM), k + 1) == k + 1) def_path = cp; else #endif /* * this is uniform across all OSes unless it * breaks somewhere hard; don't try to optimise, * e.g. add stuff for Interix or remove /usr * for HURD, because e.g. Debian GNU/HURD is * "keeping a regular /usr"; this is supposed * to be a sane 'basic' default PATH */ def_path = MKSH_UNIXROOT "/bin" MKSH_PATHSEPS MKSH_UNIXROOT "/usr/bin" MKSH_PATHSEPS MKSH_UNIXROOT "/sbin" MKSH_PATHSEPS MKSH_UNIXROOT "/usr/sbin"; #endif /* * Set PATH to def_path (will set the path global variable). * (import of environment below will probably change this setting). */ vp = global(TPATH); /* setstr can't fail here */ setstr(vp, def_path, KSH_RETURN_ERROR); #ifndef MKSH_NO_CMDLINE_EDITING /* * Set edit mode to emacs by default, may be overridden * by the environment or the user. Also, we want tab completion * on in vi by default. */ change_flag(FEMACS, OF_SPECIAL, true); #if !MKSH_S_NOVI Flag(FVITABCOMPLETE) = 1; #endif #endif /* import environment */ init_environ(); /* override default PATH regardless of environment */ #ifdef MKSH_DEFPATH_OVERRIDE vp = global(TPATH); setstr(vp, MKSH_DEFPATH_OVERRIDE, KSH_RETURN_ERROR); #endif /* for security */ typeset(TinitIFS, 0, 0, 0, 0); /* assign default shell variable values */ typeset("PATHSEP=" MKSH_PATHSEPS, 0, 0, 0, 0); substitute(initsubs, 0); /* Figure out the current working directory and set $PWD */ vp = global(TPWD); cp = str_val(vp); /* Try to use existing $PWD if it is valid */ set_current_wd((mksh_abspath(cp) && test_eval(NULL, TO_FILEQ, cp, Tdot, true)) ? cp : NULL); if (current_wd[0]) simplify_path(current_wd); /* Only set pwd if we know where we are or if it had a bogus value */ if (current_wd[0] || *cp) /* setstr can't fail here */ setstr(vp, current_wd, KSH_RETURN_ERROR); for (wp = initcoms; *wp != NULL; wp++) { c_builtin(wp); while (*wp != NULL) wp++; } setint_n(global("OPTIND"), 1, 10); kshuid = getuid(); kshgid = getgid(); kshegid = getegid(); safe_prompt = ksheuid ? "$ " : "# "; vp = global("PS1"); /* Set PS1 if unset or we are root and prompt doesn't contain a # */ if (!(vp->flag & ISSET) || (!ksheuid && !strchr(str_val(vp), '#'))) /* setstr can't fail here */ setstr(vp, safe_prompt, KSH_RETURN_ERROR); setint_n((vp = global("BASHPID")), 0, 10); vp->flag |= INT_U; setint_n((vp = global("PGRP")), (mksh_uari_t)kshpgrp, 10); vp->flag |= INT_U; setint_n((vp = global("PPID")), (mksh_uari_t)kshppid, 10); vp->flag |= INT_U; setint_n((vp = global("USER_ID")), (mksh_uari_t)ksheuid, 10); vp->flag |= INT_U; setint_n((vp = global("KSHUID")), (mksh_uari_t)kshuid, 10); vp->flag |= INT_U; setint_n((vp = global("KSHEGID")), (mksh_uari_t)kshegid, 10); vp->flag |= INT_U; setint_n((vp = global("KSHGID")), (mksh_uari_t)kshgid, 10); vp->flag |= INT_U; setint_n((vp = global("RANDOM")), rndsetup(), 10); vp->flag |= INT_U; setint_n((vp_pipest = global("PIPESTATUS")), 0, 10); /* Set this before parsing arguments */ Flag(FPRIVILEGED) = (kshuid != ksheuid || kshgid != kshegid) ? 2 : 0; /* this to note if monitor is set on command line (see below) */ #ifndef MKSH_UNEMPLOYED Flag(FMONITOR) = 127; #endif /* this to note if utf-8 mode is set on command line (see below) */ UTFMODE = 2; if (!Flag(FAS_BUILTIN)) { argi = parse_args(argv, OF_CMDLINE, NULL); if (argi < 0) return (1); } /* process this later only, default to off (hysterical raisins) */ utf_flag = UTFMODE; UTFMODE = 0; if (Flag(FAS_BUILTIN)) { /* auto-detect from environment variables, always */ utf_flag = 3; } else if (Flag(FCOMMAND)) { s = pushs(SSTRINGCMDLINE, ATEMP); if (!(s->start = s->str = argv[argi++])) errorf(Tf_optfoo, "", "", 'c', Treq_arg); while (*s->str) { if (ctype(*s->str, C_QUOTE)) break; s->str++; } if (!*s->str) s->flags |= SF_MAYEXEC; s->str = s->start; #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT /* compatibility to MidnightBSD 0.1 /bin/sh (kludge) */ if (Flag(FSH) && argv[argi] && !strcmp(argv[argi], "--")) ++argi; #endif if (argv[argi]) kshname = argv[argi++]; } else if (argi < argc && !Flag(FSTDIN)) { s = pushs(SFILE, ATEMP); #ifdef __OS2__ /* * A bug in OS/2 extproc (like shebang) handling makes * it not pass the full pathname of a script, so we need * to search for it. This changes the behaviour of a * simple "mksh foo", but can't be helped. */ s->file = argv[argi++]; if (search_access(s->file, X_OK) != 0) s->file = search_path(s->file, path, X_OK, NULL); if (!s->file || !*s->file) s->file = argv[argi - 1]; #else s->file = argv[argi++]; #endif s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC); if (s->u.shf == NULL) { shl_stdout_ok = false; warningf(true, Tf_sD_s, s->file, cstrerror(errno)); /* mandated by SUSv4 */ exstat = 127; unwind(LERROR); } kshname = s->file; } else { Flag(FSTDIN) = 1; s = pushs(SSTDIN, ATEMP); s->file = "<stdin>"; s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), NULL); if (isatty(0) && isatty(2)) { Flag(FTALKING) = Flag(FTALKING_I) = 1; /* The following only if isatty(0) */ s->flags |= SF_TTY; s->u.shf->flags |= SHF_INTERRUPT; s->file = NULL; } } /* this bizarreness is mandated by POSIX */ if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) && Flag(FTALKING)) reset_nonblock(0); /* initialise job control */ j_init(); /* do this after j_init() which calls tty_init_state() */ if (Flag(FTALKING)) { if (utf_flag == 2) { #ifndef MKSH_ASSUME_UTF8 /* auto-detect from locale or environment */ utf_flag = 4; #else /* this may not be an #elif */ #if MKSH_ASSUME_UTF8 utf_flag = 1; #else /* always disable UTF-8 (for interactive) */ utf_flag = 0; #endif #endif } #ifndef MKSH_NO_CMDLINE_EDITING x_init(); #endif } #ifdef SIGWINCH sigtraps[SIGWINCH].flags |= TF_SHELL_USES; setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP); #endif l = e->loc; if (Flag(FAS_BUILTIN)) { l->argc = argc; l->argv = argv; l->argv[0] = ccp; } else { l->argc = argc - argi; /* * allocate a new array because otherwise, when we modify * it in-place, ps(1) output changes; the meaning of argc * here is slightly different as it excludes kshname, and * we add a trailing NULL sentinel as well */ l->argv = alloc2(l->argc + 2, sizeof(void *), APERM); l->argv[0] = kshname; memcpy(&l->argv[1], &argv[argi], l->argc * sizeof(void *)); l->argv[l->argc + 1] = NULL; getopts_reset(1); } /* divine the initial state of the utf8-mode Flag */ ccp = null; switch (utf_flag) { /* auto-detect from locale or environment */ case 4: #if HAVE_SETLOCALE_CTYPE ccp = setlocale(LC_CTYPE, ""); #if HAVE_LANGINFO_CODESET if (!isuc(ccp)) ccp = nl_langinfo(CODESET); #endif if (!isuc(ccp)) ccp = null; #endif /* FALLTHROUGH */ /* auto-detect from environment */ case 3: /* these were imported from environ earlier */ if (ccp == null) ccp = str_val(global("LC_ALL")); if (ccp == null) ccp = str_val(global("LC_CTYPE")); if (ccp == null) ccp = str_val(global("LANG")); UTFMODE = isuc(ccp); break; /* not set on command line, not FTALKING */ case 2: /* unknown values */ default: utf_flag = 0; /* FALLTHROUGH */ /* known values */ case 1: case 0: UTFMODE = utf_flag; break; } /* Disable during .profile/ENV reading */ restricted_shell = Flag(FRESTRICTED); Flag(FRESTRICTED) = 0; errexit = Flag(FERREXIT); Flag(FERREXIT) = 0; /* * Do this before profile/$ENV so that if it causes problems in them, * user will know why things broke. */ if (!current_wd[0] && Flag(FTALKING)) warningf(false, "can't determine current directory"); if (Flag(FLOGIN)) include(MKSH_SYSTEM_PROFILE, 0, NULL, true); if (!Flag(FPRIVILEGED)) { if (Flag(FLOGIN)) include(substitute("$HOME/.profile", 0), 0, NULL, true); if (Flag(FTALKING)) { cp = substitute("${ENV:-" MKSHRC_PATH "}", DOTILDE); if (cp[0] != '\0') include(cp, 0, NULL, true); } } else { include(MKSH_SUID_PROFILE, 0, NULL, true); /* turn off -p if not set explicitly */ if (Flag(FPRIVILEGED) != 1) change_flag(FPRIVILEGED, OF_INTERNAL, false); } if (restricted_shell) { c_builtin(restr_com); /* After typeset command... */ Flag(FRESTRICTED) = 1; } Flag(FERREXIT) = errexit; if (Flag(FTALKING) && s) hist_init(s); else /* set after ENV */ Flag(FTRACKALL) = 1; alarm_init(); *sp = s; *lp = l; return (0); }
/* * 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)) shellf("%s%s\n", substitute(str_val(global("PS4")), 0), snptreef(NULL, 32, "%R", &iotmp)); 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) { warningf(true, "%s: %s", snptreef(NULL, 32, "%R", &iotmp), emsg); 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, 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; eno = errno; warningf(true, "%s %s %s", "can't finish (dup) redirection", snptreef(NULL, 32, "%R", &iotmp), cstrerror(eno)); 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); }
void layout_compound(compound_t *const compound) { bool const is_union = compound->base.kind == ENTITY_UNION; unsigned alignment = compound->alignment; size_t bit_offset = 0; unsigned size = 0; bool need_pad = false; for (entity_t *entry = compound->members.first_entity; entry; entry = entry->base.next) { if (entry->kind != ENTITY_COMPOUND_MEMBER) continue; compound_member_t *const member = &entry->compound_member; type_t *const m_type = skip_typeref(member->base.type); if (!is_type_valid(m_type)) continue; unsigned m_alignment = get_declaration_alignment(&member->base); alignment = MAX(alignment, m_alignment); unsigned const m_size = get_ctype_size(m_type); if (is_union) { size = MAX(size, m_size); } else if (member->bitfield) { unsigned const alignment_mask = m_alignment - 1; size_t const base_size = m_size * BITS_PER_BYTE; size_t const bit_size = member->bit_size; bit_offset += (size & alignment_mask) * BITS_PER_BYTE; size &= ~alignment_mask; if (bit_offset + bit_size > base_size || (bit_size == 0 && !(member->base.modifiers & DM_PACKED))) { size += (bit_offset + BITS_PER_BYTE - 1) / BITS_PER_BYTE; size = round_up2(size, m_alignment); bit_offset = 0; } if (target.byte_order_big_endian) { member->offset = size & ~alignment_mask; member->bit_offset = base_size - bit_offset - bit_size; } else { member->offset = size; member->bit_offset = bit_offset; } bit_offset += bit_size; size += bit_offset / BITS_PER_BYTE; bit_offset %= BITS_PER_BYTE; } else { if (bit_offset != 0) { bit_offset = 0; size += 1; } unsigned const new_size = round_up2(size, m_alignment); if (new_size > size) { need_pad = true; size = new_size; } member->offset = size; size += m_size; } } if (bit_offset != 0) size += 1; unsigned const new_size = round_up2(size, alignment); if (new_size > size) { need_pad = true; size = new_size; } position_t const *const pos = &compound->base.pos; if (need_pad) { warningf(WARN_PADDED, pos, "%N needs padding", compound); } else if (compound->packed) { warningf(WARN_PACKED, pos, "superfluous packed attribute on %N", compound); } compound->size = size; compound->alignment = alignment; }
/* getopt() used for shell built-in commands, the getopts command, and * command line options. * A leading ':' in options means don't print errors, instead return '?' * or ':' and set go->optarg to the offending option character. * If GF_ERROR is set (and option doesn't start with :), errors result in * a call to bi_errorf(). * * Non-standard features: * - ';' is like ':' in options, except the argument is optional * (if it isn't present, optarg is set to 0). * Used for 'set -o'. * - ',' is like ':' in options, except the argument always immediately * follows the option character (optarg is set to the null string if * the option is missing). * Used for 'read -u2', 'print -u2' and fc -40. * - '#' is like ':' in options, expect that the argument is optional * and must start with a digit. If the argument doesn't start with a * digit, it is assumed to be missing and normal option processing * continues (optarg is set to 0 if the option is missing). * Used for 'typeset -LZ4'. * - accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an * option starting with + is accepted, the GI_PLUS flag will be set * in go->info. */ int ksh_getopt(char **argv, Getopt *go, const char *options) { char c; char *o; if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') { char *arg = argv[go->optind], flag = arg ? *arg : '\0'; go->p = 1; if (flag == '-' && arg[1] == '-' && arg[2] == '\0') { go->optind++; go->p = 0; go->info |= GI_MINUSMINUS; return -1; } if (arg == (char *) 0 || ((flag != '-' ) && /* neither a - nor a + (if + allowed) */ (!(go->flags & GF_PLUSOPT) || flag != '+')) || (c = arg[1]) == '\0') { go->p = 0; return -1; } go->optind++; go->info &= ~(GI_MINUS|GI_PLUS); go->info |= flag == '-' ? GI_MINUS : GI_PLUS; } go->p++; if (c == '?' || c == ':' || c == ';' || c == ',' || c == '#' || !(o = strchr(options, c))) { if (options[0] == ':') { go->buf[0] = c; go->optarg = go->buf; } else { warningf(true, "%s%s-%c: unknown option", (go->flags & GF_NONAME) ? "" : argv[0], (go->flags & GF_NONAME) ? "" : ": ", c); if (go->flags & GF_ERROR) bi_errorf(null); } return '?'; } /* : means argument must be present, may be part of option argument * or the next argument * ; same as : but argument may be missing * , means argument is part of option argument, and may be null. */ if (*++o == ':' || *o == ';') { if (argv[go->optind - 1][go->p]) go->optarg = argv[go->optind - 1] + go->p; else if (argv[go->optind]) go->optarg = argv[go->optind++]; else if (*o == ';') go->optarg = (char *) 0; else { if (options[0] == ':') { go->buf[0] = c; go->optarg = go->buf; return ':'; } warningf(true, "%s%s-`%c' requires argument", (go->flags & GF_NONAME) ? "" : argv[0], (go->flags & GF_NONAME) ? "" : ": ", c); if (go->flags & GF_ERROR) bi_errorf(null); return '?'; } go->p = 0; } else if (*o == ',') { /* argument is attatched to option character, even if null */ go->optarg = argv[go->optind - 1] + go->p; go->p = 0; } else if (*o == '#') { /* argument is optional and may be attatched or unattatched * but must start with a digit. optarg is set to 0 if the * argument is missing. */ if (argv[go->optind - 1][go->p]) { if (digit(argv[go->optind - 1][go->p])) { go->optarg = argv[go->optind - 1] + go->p; go->p = 0; } else go->optarg = (char *) 0;; } else { if (argv[go->optind] && digit(argv[go->optind][0])) { go->optarg = argv[go->optind++]; go->p = 0; } else go->optarg = (char *) 0;; } } return c; }
void layout_compound(compound_t *const compound) { bool const is_union = compound->base.kind == ENTITY_UNION; bool const is_packed = compound->packed; il_alignment_t alignment = compound->alignment; size_t bit_offset = 0; il_size_t size = 0; bool need_pad = false; for (entity_t *entry = compound->members.entities; entry; entry = entry->base.next) { if (entry->kind != ENTITY_COMPOUND_MEMBER) continue; compound_member_t *const member = &entry->compound_member; type_t *const m_type = skip_typeref(member->base.type); if (!is_type_valid(m_type)) continue; if (is_packed) { /* GCC: Specifying this attribute for `struct' and `union' types is * equivalent to specifying the `packed' attribute on each of the * structure or union members. */ member->base.alignment = 1; } il_alignment_t const m_alignment = member->base.alignment; alignment = MAX(alignment, m_alignment); unsigned const m_size = get_type_size(m_type); if (is_union) { size = MAX(size, m_size); } else if (member->bitfield) { il_alignment_t const alignment_mask = m_alignment - 1; size_t const base_size = m_size * BITS_PER_BYTE; size_t const bit_size = member->bit_size; if (!is_packed) { bit_offset += (size & alignment_mask) * BITS_PER_BYTE; size &= ~alignment_mask; if (bit_offset + bit_size > base_size || bit_size == 0) { size += (bit_offset + BITS_PER_BYTE - 1) / BITS_PER_BYTE; size = round_up2(size, m_alignment); bit_offset = 0; } } if (target.byte_order_big_endian) { member->offset = size & ~alignment_mask; member->bit_offset = base_size - bit_offset - bit_size; } else { member->offset = size; member->bit_offset = bit_offset; } bit_offset += bit_size; size += bit_offset / BITS_PER_BYTE; bit_offset %= BITS_PER_BYTE; } else { if (bit_offset != 0) { bit_offset = 0; size += 1; } il_size_t const new_size = round_up2(size, m_alignment); if (new_size > size) { need_pad = true; size = new_size; } member->offset = size; size += m_size; } } if (bit_offset != 0) size += 1; il_size_t const new_size = round_up2(size, alignment); if (new_size > size) { need_pad = true; size = new_size; } position_t const *const pos = &compound->base.pos; if (need_pad) { warningf(WARN_PADDED, pos, "'%N' needs padding", compound); } else if (is_packed) { warningf(WARN_PACKED, pos, "superfluous packed attribute on '%N'", compound); } compound->size = size; compound->alignment = alignment; }