1 /* $OpenBSD: main.c,v 1.47 2011/09/07 11:33:25 otto Exp $ */
2 /* $OpenBSD: tty.c,v 1.9 2006/03/14 22:08:01 deraadt Exp $ */
3 /* $OpenBSD: io.c,v 1.22 2006/03/17 16:30:13 millert Exp $ */
4 /* $OpenBSD: table.c,v 1.13 2009/01/17 22:06:44 millert Exp $ */
7 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
8 * Thorsten Glaser <tg@mirbsd.org>
10 * Provided that these terms and disclaimer and all copyright notices
11 * are retained or reproduced in an accompanying document, permission
12 * is granted to deal in this work without restriction, including un-
13 * limited rights to use, publicly perform, distribute, sell, modify,
14 * merge, give away, or sublicence.
16 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
17 * the utmost extent permitted by applicable law, neither express nor
18 * implied; without malicious intent or gross negligence. In no event
19 * may a licensor, author or contributor be held liable for indirect,
20 * direct, other damage, loss, or other issues arising in any way out
21 * of dealing in the work, even if advised of the possibility of such
22 * damage or existence of a defect, except proven that it results out
23 * of said person's immediate fault when using the work as intended.
29 #if HAVE_LANGINFO_CODESET
32 #if HAVE_SETLOCALE_CTYPE
36 __RCSID("$MirOS: src/bin/mksh/main.c,v 1.200 2011/10/07 19:51:28 tg Exp $");
38 extern char **environ;
41 #define MKSHRC_PATH "~/.mkshrc"
44 #ifndef MKSH_DEFAULT_TMPDIR
45 #define MKSH_DEFAULT_TMPDIR "/tmp"
48 void chvt_reinit(void);
49 static void reclaim(void);
50 static void remove_temps(struct temp *);
51 static mksh_uari_t rndsetup(void);
53 static void x_sigwinch(int);
56 static const char initifs[] = "IFS= \t\n";
58 static const char initsubs[] =
59 "${PS2=> } ${PS3=#? } ${PS4=+ } ${SECONDS=0} ${TMOUT=0}";
61 static const char *initcoms[] = {
62 Ttypeset, "-r", initvsn, NULL,
63 Ttypeset, "-x", "HOME", "PATH", "RANDOM", "SHELL", NULL,
64 Ttypeset, "-i10", "SECONDS", "TMOUT", NULL,
68 /* not "alias -t --": hash -r needs to work */
71 #if !defined(ANDROID) && !defined(MKSH_UNEMPLOYED)
72 /* not in Android for political reasons */
73 /* not in ARGE mksh due to no job control */
75 "suspend=kill -STOP $$",
77 "autoload=typeset -fu",
78 "functions=typeset -f",
83 "source=PATH=$PATH:. command .",
86 /* this is what AT&T ksh seems to track, with the addition of emacs */
88 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
89 "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", NULL,
93 static const char *restr_com[] = {
94 Ttypeset, "-r", "PATH", "ENV", "SHELL", NULL
97 static int initio_done;
99 /* top-level parsing and execution environment */
100 static struct env env;
101 struct env *e = &env;
108 ALLOC_ITEM alloc_INT;
109 void *dataptr, *stkptr, *mallocptr;
116 cp = alloc(sizeof(*bufptr) - ALLOC_SIZE, APERM);
118 /* clear the allocated space, for valgrind */
119 memset(cp, 0, sizeof(*bufptr) - ALLOC_SIZE);
121 /* undo what alloc() did to the malloc result address */
122 bufptr = (void *)(cp - ALLOC_SIZE);
123 /* PIE or something similar provides us with deltas here */
124 bufptr->dataptr = &rndsetupstate;
125 /* ASLR in at least Windows, Linux, some BSDs */
126 bufptr->stkptr = &bufptr;
127 /* randomised malloc in BSD (and possibly others) */
128 bufptr->mallocptr = bufptr;
129 /* glibc pointer guard */
130 sigsetjmp(bufptr->jbuf, 1);
131 /* introduce variation */
132 gettimeofday(&bufptr->tv, &bufptr->tz);
135 /* variation through pid, ppid, and the works */
136 NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
137 /* some variation, some possibly entropy, depending on OE */
138 NZATUpdateMem(h, bufptr, sizeof(*bufptr));
142 return ((mksh_uari_t)h);
148 kshpid = procpid = getpid();
154 static const char *empty_argv[] = {
159 main(int argc, const char *argv[])
164 unsigned char restricted, errexit, utf_flag;
166 const char *ccp, **wp;
169 #if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
173 /* do things like getpgrp() et al. */
176 /* make sure argv[] is sane */
183 /* initialise permanent Area */
186 /* set up base environment */
189 /* set up global l->vars and l->funs */
192 /* Do this first so output routines (eg, errorf, shellf) can work */
195 /* determine the basename (without '-' or path) of the executable */
197 goto begin_parse_kshname;
198 while ((i = ccp[argi++])) {
210 /* define built-in commands and see if we were called as one */
211 ktinit(APERM, &builtins,
212 /* currently 50 builtins -> 80% of 64 (2^6) */
214 for (i = 0; mkshbuiltins[i].name != NULL; i++)
215 if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
216 mkshbuiltins[i].func)))
217 Flag(FAS_BUILTIN) = 1;
219 if (!Flag(FAS_BUILTIN)) {
220 /* check for -T option early */
221 argi = parse_args(argv, OF_FIRSTTIME, NULL);
225 #ifdef MKSH_BINSHREDUCED
226 /* set FSH if we're called as -sh or /bin/sh or so */
227 if (!strcmp(ccp, "sh"))
228 change_flag(FSH, OF_FIRSTTIME, 1);
240 /* set up variable and command dictionaries */
241 ktinit(APERM, &taliases, 0);
242 ktinit(APERM, &aliases, 0);
244 ktinit(APERM, &homedirs, 0);
247 /* define shell keywords */
253 def_path = _PATH_DEFPATH;
256 if ((k = confstr(_CS_PATH, NULL, 0)) > 0 &&
257 confstr(_CS_PATH, cp = alloc(k + 1, APERM), k + 1) == k + 1)
262 * this is uniform across all OSes unless it
263 * breaks somewhere; don't try to optimise,
264 * e.g. add stuff for Interix or remove /usr
265 * for HURD, because e.g. Debian GNU/HURD is
266 * "keeping a regular /usr"; this is supposed
267 * to be a sane 'basic' default PATH
269 def_path = "/bin:/usr/bin:/sbin:/usr/sbin";
273 * Set PATH to def_path (will set the path global variable).
274 * (import of environment below will probably change this setting).
277 /* setstr can't fail here */
278 setstr(vp, def_path, KSH_RETURN_ERROR);
281 * Turn on nohup by default for now - will change to off
282 * by default once people are aware of its existence
283 * (AT&T ksh does not have a nohup option - it always sends
289 * Turn on brace expansion by default. AT&T kshs that have
290 * alternation always have it on.
292 Flag(FBRACEEXPAND) = 1;
295 * Set edit mode to emacs by default, may be overridden
296 * by the environment or the user. Also, we want tab completion
297 * on in vi by default.
299 change_flag(FEMACS, OF_SPECIAL, 1);
301 Flag(FVITABCOMPLETE) = 1;
304 /* import environment */
306 for (wp = (const char **)environ; *wp != NULL; wp++)
307 typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
310 typeset(initifs, 0, 0, 0, 0);
312 /* assign default shell variable values */
313 substitute(initsubs, 0);
315 /* Figure out the current working directory and set $PWD */
318 /* Try to use existing $PWD if it is valid */
319 set_current_wd((cp[0] == '/' && test_eval(NULL, TO_FILEQ, cp, ".",
322 simplify_path(current_wd);
323 /* Only set pwd if we know where we are or if it had a bogus value */
324 if (current_wd[0] || *cp)
325 /* setstr can't fail here */
326 setstr(vp, current_wd, KSH_RETURN_ERROR);
328 for (wp = initcoms; *wp != NULL; wp++) {
333 setint_n(global("COLUMNS"), 0);
334 setint_n(global("LINES"), 0);
335 setint_n(global("OPTIND"), 1);
341 safe_prompt = ksheuid ? "$ " : "# ";
343 /* Set PS1 if unset or we are root and prompt doesn't contain a # */
344 if (!(vp->flag & ISSET) ||
345 (!ksheuid && !strchr(str_val(vp), '#')))
346 /* setstr can't fail here */
347 setstr(vp, safe_prompt, KSH_RETURN_ERROR);
348 setint_n((vp = global("PGRP")), (mksh_uari_t)kshpgrp);
350 setint_n((vp = global("PPID")), (mksh_uari_t)kshppid);
352 setint_n((vp = global("USER_ID")), (mksh_uari_t)ksheuid);
354 setint_n((vp = global("KSHUID")), (mksh_uari_t)kshuid);
356 setint_n((vp = global("KSHEGID")), (mksh_uari_t)kshegid);
358 setint_n((vp = global("KSHGID")), (mksh_uari_t)kshgid);
360 setint_n((vp = global("RANDOM")), rndsetup());
362 setint_n((vp_pipest = global("PIPESTATUS")), 0);
364 /* Set this before parsing arguments */
365 Flag(FPRIVILEGED) = kshuid != ksheuid || kshgid != kshegid;
367 /* this to note if monitor is set on command line (see below) */
368 #ifndef MKSH_UNEMPLOYED
369 Flag(FMONITOR) = 127;
371 /* this to note if utf-8 mode is set on command line (see below) */
374 if (!Flag(FAS_BUILTIN)) {
375 argi = parse_args(argv, OF_CMDLINE, NULL);
381 /* test wraparound of arithmetic types */
384 volatile unsigned long xul;
386 volatile unsigned int xui;
387 volatile mksh_ari_t xa;
388 volatile mksh_uari_t xua, xua2;
410 if ((xua2 != 2147483648UL) ||
411 (xl != -2147483648L) || (xul != 2147483648UL) ||
412 (xi != -1) || (xui != 4294967295U) ||
413 (xa != 0) || (xua != 0) || (xc != 255))
414 errorf("integer wraparound test failed");
418 /* process this later only, default to off (hysterical raisins) */
422 if (Flag(FAS_BUILTIN)) {
423 /* auto-detect from environment variables, always */
425 } else if (Flag(FCOMMAND)) {
426 s = pushs(SSTRING, ATEMP);
427 if (!(s->start = s->str = argv[argi++]))
428 errorf("%s %s", "-c", "requires an argument");
429 #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
430 /* compatibility to MidnightBSD 0.1 /bin/sh (kludge) */
431 if (Flag(FSH) && argv[argi] && !strcmp(argv[argi], "--"))
435 kshname = argv[argi++];
436 } else if (argi < argc && !Flag(FSTDIN)) {
437 s = pushs(SFILE, ATEMP);
438 s->file = argv[argi++];
439 s->u.shf = shf_open(s->file, O_RDONLY, 0,
440 SHF_MAPHI | SHF_CLEXEC);
441 if (s->u.shf == NULL) {
442 shl_stdout_ok = false;
443 warningf(true, "%s: %s", s->file, strerror(errno));
444 /* mandated by SUSv4 */
451 s = pushs(SSTDIN, ATEMP);
453 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
455 if (isatty(0) && isatty(2)) {
456 Flag(FTALKING) = Flag(FTALKING_I) = 1;
457 /* The following only if isatty(0) */
459 s->u.shf->flags |= SHF_INTERRUPT;
464 /* this bizarreness is mandated by POSIX */
465 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
469 /* initialise job control */
471 /* Do this after j_init(), as tty_fd is not initialised until then */
472 if (Flag(FTALKING)) {
474 #ifndef MKSH_ASSUME_UTF8
475 /* auto-detect from locale or environment */
477 #elif MKSH_ASSUME_UTF8
480 /* always disable UTF-8 (for interactive) */
488 sigtraps[SIGWINCH].flags |= TF_SHELL_USES;
489 setsig(&sigtraps[SIGWINCH], x_sigwinch,
490 SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP);
494 if (Flag(FAS_BUILTIN)) {
499 l->argc = argc - argi;
500 l->argv = &argv[argi - 1];
501 l->argv[0] = kshname;
505 /* divine the initial state of the utf8-mode Flag */
506 #define isuc(x) (((x) != NULL) && \
507 (stristr((x), "UTF-8") || stristr((x), "utf8")))
511 /* auto-detect from locale or environment */
513 #if HAVE_SETLOCALE_CTYPE
514 ccp = setlocale(LC_CTYPE, "");
515 #if HAVE_LANGINFO_CODESET
517 ccp = nl_langinfo(CODESET);
524 /* auto-detect from environment */
526 /* these were imported from environ earlier */
528 ccp = str_val(global("LC_ALL"));
530 ccp = str_val(global("LC_CTYPE"));
532 ccp = str_val(global("LANG"));
536 /* not set on command line, not FTALKING */
551 /* Disable during .profile/ENV reading */
552 restricted = Flag(FRESTRICTED);
553 Flag(FRESTRICTED) = 0;
554 errexit = Flag(FERREXIT);
558 * Do this before profile/$ENV so that if it causes problems in them,
559 * user will know why things broke.
561 if (!current_wd[0] && Flag(FTALKING))
562 warningf(false, "can't determine current directory");
565 include(MKSH_SYSTEM_PROFILE, 0, NULL, 1);
566 if (!Flag(FPRIVILEGED))
567 include(substitute("$HOME/.profile", 0), 0,
570 if (Flag(FPRIVILEGED))
571 include(MKSH_SUID_PROFILE, 0, NULL, 1);
572 else if (Flag(FTALKING)) {
576 env_file = substitute(substitute("${ENV:-" MKSHRC_PATH "}", 0),
578 if (*env_file != '\0')
579 include(env_file, 0, NULL, 1);
583 shcomexec(restr_com);
584 /* After typeset command... */
585 Flag(FRESTRICTED) = 1;
587 Flag(FERREXIT) = errexit;
597 if (Flag(FAS_BUILTIN))
598 return (shcomexec(l->argv));
607 include(const char *name, int argc, const char **argv, int intr_ok)
609 Source *volatile s = NULL;
611 const char **volatile old_argv;
612 volatile int old_argc;
615 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
620 old_argv = e->loc->argv;
621 old_argc = e->loc->argc;
627 i = sigsetjmp(e->jbuf, 0);
629 quitenv(s ? s->u.shf : NULL);
631 e->loc->argv = old_argv;
632 e->loc->argc = old_argc;
638 return (exstat & 0xFF);
641 * intr_ok is set if we are including .profile or $ENV.
642 * If user ^Cs out, we don't want to kill the shell...
644 if (intr_ok && (exstat - 128) != SIGTERM)
653 internal_errorf("%s %d", "include", i);
661 s = pushs(SFILE, ATEMP);
663 strdupx(s->file, name, ATEMP);
667 e->loc->argv = old_argv;
668 e->loc->argc = old_argc;
670 /* & 0xff to ensure value not -1 */
674 /* spawn a command into a shell optionally keeping track of the line number */
676 command(const char *comm, int line)
680 s = pushs(SSTRING, ATEMP);
681 s->start = s->str = comm;
683 return (shell(s, false));
687 * run the commands from the input source, returning status.
690 shell(Source * volatile s, volatile int toplevel)
693 volatile int wastty = s->flags & SF_TTY;
694 volatile int attempts = 13;
695 volatile int interactive = Flag(FTALKING) && toplevel;
696 volatile bool sfirst = true;
697 Source *volatile old_source = source;
703 i = sigsetjmp(e->jbuf, 0);
707 /* we get here if SIGINT not caught or ignored */
714 * Reset any eof that was read as part of a
717 if (Flag(FIGNOREEOF) && s->type == SEOF &&
721 * Used by exit command to get back to
722 * top level shell. Kind of strange since
723 * interactive is set if we are reading from
724 * a tty, but to have stopped jobs, one only
725 * needs FMONITOR set (not FTALKING/SF_TTY)...
727 /* toss any input we have so far */
728 s->start = s->str = null;
743 internal_errorf("%s %d", "shell", i);
747 while (/* CONSTCOND */ 1) {
751 if (s->next == NULL) {
755 s->flags &= ~SF_ECHO;
761 t = compile(s, sfirst);
763 if (t != NULL && t->type == TEOF) {
764 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
765 shellf("Use 'exit' to leave mksh\n");
767 } else if (wastty && !really_exit &&
768 j_stopped_running()) {
773 * this for POSIX which says EXIT traps
774 * shall be taken in the environment
775 * immediately after the last command
783 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
784 exstat = execute(t, 0, NULL);
786 if (t != NULL && t->type != TEOF && interactive && really_exit)
796 /* return to closest error handler or shell(), exit if none found */
800 /* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
801 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) &&
802 sigtraps[ksh_SIGEXIT].trap)) {
804 runtrap(&sigtraps[ksh_SIGEXIT], trap_nested == 1);
807 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
809 runtrap(&sigtraps[ksh_SIGERR], trap_nested == 1);
813 while (/* CONSTCOND */ 1) {
820 siglongjmp(e->jbuf, i);
824 e->flags |= EF_FAKE_SIGDIE;
839 * struct env includes ALLOC_ITEM for alignment constraints
840 * so first get the actually used memory, then assign it
842 cp = alloc(sizeof(struct env) - ALLOC_SIZE, ATEMP);
843 /* undo what alloc() did to the malloc result address */
844 ep = (void *)(cp - ALLOC_SIZE);
845 /* initialise public members of struct env (not the ALLOC_ITEM) */
853 /* jump buffer is invalid because flags == 0 */
858 quitenv(struct shf *shf)
864 if (ep->oenv && ep->oenv->loc != ep->loc)
866 if (ep->savefd != NULL) {
867 for (fd = 0; fd < NUFILE; fd++)
868 /* if ep->savefd[fd] < 0, means fd was closed */
870 restfd(fd, ep->savefd[fd]);
872 /* Clear any write errors */
873 shf_reopen(2, SHF_WR, shl_out);
876 * Bottom of the stack.
877 * Either main shell is exiting or cleanup_parents_env() was called.
879 if (ep->oenv == NULL) {
880 if (ep->type == E_NONE) {
881 /* Main shell exiting? */
882 #if HAVE_PERSISTENT_HISTORY
887 if (ep->flags & EF_FAKE_SIGDIE) {
888 int sig = exstat - 128;
891 * ham up our death a bit (AT&T ksh
892 * only seems to do this for SIGTERM)
893 * Don't do it for SIGQUIT, since we'd
896 if ((sig == SIGINT || sig == SIGTERM) &&
897 (kshpgrp == kshpid)) {
898 setsig(&sigtraps[sig], SIG_DFL,
899 SS_RESTORE_CURR | SS_FORCE);
915 /* free the struct env - tricky due to the ALLOC_ITEM inside */
917 afree(cp + ALLOC_SIZE, ATEMP);
920 /* Called after a fork to cleanup stuff left over from parents environment */
922 cleanup_parents_env(void)
930 * Don't clean up temporary files - parent will probably need them.
931 * Also, can't easily reclaim memory since variables, etc. could be
935 /* close all file descriptors hiding in savefd */
936 for (ep = e; ep; ep = ep->oenv) {
938 for (fd = 0; fd < NUFILE; fd++)
939 if (ep->savefd[fd] > 0)
940 close(ep->savefd[fd]);
941 afree(ep->savefd, &ep->area);
948 /* Called just before an execve cleanup stuff temporary files */
950 cleanup_proc_env(void)
954 for (ep = e; ep; ep = ep->oenv)
955 remove_temps(ep->temps);
958 /* remove temp files and free ATEMP Area */
962 remove_temps(e->temps);
968 remove_temps(struct temp *tp)
970 for (; tp != NULL; tp = tp->next)
971 if (tp->pid == procpid)
976 * Initialise tty_fd. Used for saving/reseting tty modes upon
977 * foreground job completion and for setting up tty process group.
980 tty_init(bool init_ttystate, bool need_tty)
982 bool do_close = true;
994 /* fd 3 on UWIN _is_ /dev/tty (or our controlling tty) */
999 if ((tfd = open("/dev/tty", O_RDWR, 0)) < 0) {
1002 warningf(false, "%s: %s %s: %s",
1003 "No controlling tty", "open", "/dev/tty",
1014 warningf(false, "can't find tty fd");
1018 if ((tty_fd = fcntl(tfd, F_DUPFD, FDBASE)) < 0) {
1020 warningf(false, "%s: %s %s: %s", "j_ttyinit",
1021 "dup of tty fd", "failed", strerror(errno));
1022 } else if (fcntl(tty_fd, F_SETFD, FD_CLOEXEC) < 0) {
1024 warningf(false, "%s: %s: %s", "j_ttyinit",
1025 "can't set close-on-exec flag", strerror(errno));
1028 } else if (init_ttystate)
1029 tcgetattr(tty_fd, &tty_state);
1043 /* A shell error occurred (eg, syntax error, etc.) */
1045 #define VWARNINGF_ERRORPREFIX 1
1046 #define VWARNINGF_FILELINE 2
1047 #define VWARNINGF_BUILTIN 4
1048 #define VWARNINGF_INTERNAL 8
1050 static void vwarningf(unsigned int, const char *, va_list)
1051 MKSH_A_FORMAT(__printf__, 2, 0);
1054 vwarningf(unsigned int flags, const char *fmt, va_list ap)
1057 if (flags & VWARNINGF_INTERNAL)
1058 shf_fprintf(shl_out, "internal error: ");
1059 if (flags & VWARNINGF_ERRORPREFIX)
1060 error_prefix(tobool(flags & VWARNINGF_FILELINE));
1061 if ((flags & VWARNINGF_BUILTIN) &&
1062 /* not set when main() calls parse_args() */
1063 builtin_argv0 && builtin_argv0 != kshname)
1064 shf_fprintf(shl_out, "%s: ", builtin_argv0);
1065 shf_vfprintf(shl_out, fmt, ap);
1066 shf_putchar('\n', shl_out);
1072 errorfx(int rc, const char *fmt, ...)
1078 /* debugging: note that stdout not valid */
1079 shl_stdout_ok = false;
1082 vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
1088 errorf(const char *fmt, ...)
1094 /* debugging: note that stdout not valid */
1095 shl_stdout_ok = false;
1098 vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
1103 /* like errorf(), but no unwind is done */
1105 warningf(bool fileline, const char *fmt, ...)
1110 vwarningf(VWARNINGF_ERRORPREFIX | (fileline ? VWARNINGF_FILELINE : 0),
1116 * Used by built-in utilities to prefix shell and utility name to message
1117 * (also unwinds environments for special builtins).
1120 bi_errorf(const char *fmt, ...)
1124 /* debugging: note that stdout not valid */
1125 shl_stdout_ok = false;
1130 vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE |
1131 VWARNINGF_BUILTIN, fmt, va);
1135 * POSIX special builtins and ksh special builtins cause
1136 * non-interactive shells to exit.
1137 * XXX odd use of KEEPASN; also may not want LERROR here
1139 if (builtin_flag & SPEC_BI) {
1140 builtin_argv0 = NULL;
1145 /* Called when something that shouldn't happen does */
1147 internal_errorf(const char *fmt, ...)
1152 vwarningf(VWARNINGF_INTERNAL, fmt, va);
1158 internal_warningf(const char *fmt, ...)
1163 vwarningf(VWARNINGF_INTERNAL, fmt, va);
1167 /* used by error reporting functions to print "ksh: .kshrc[25]: " */
1169 error_prefix(bool fileline)
1171 /* Avoid foo: foo[2]: ... */
1172 if (!fileline || !source || !source->file ||
1173 strcmp(source->file, kshname) != 0)
1174 shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
1175 if (fileline && source && source->file != NULL) {
1176 shf_fprintf(shl_out, "%s[%d]: ", source->file,
1177 source->errline > 0 ? source->errline : source->line);
1178 source->errline = 0;
1182 /* printf to shl_out (stderr) with flush */
1184 shellf(const char *fmt, ...)
1189 /* shl_out may not be set up yet... */
1192 shf_vfprintf(shl_out, fmt, va);
1197 /* printf to shl_stdout (stdout) */
1199 shprintf(const char *fmt, ...)
1204 internal_errorf("shl_stdout not valid");
1206 shf_vfprintf(shl_stdout, fmt, va);
1210 /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
1216 return (fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
1220 struct shf shf_iob[3];
1225 /* force buffer allocation */
1226 shf_fdopen(1, SHF_WR, shl_stdout);
1227 shf_fdopen(2, SHF_WR, shl_out);
1228 /* force buffer allocation */
1229 shf_fdopen(2, SHF_WR, shl_spare);
1233 /* A dup2() with error checking */
1235 ksh_dup2(int ofd, int nfd, bool errok)
1239 if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF))
1240 errorf("too many files open in shell");
1243 /*XXX imake style */
1245 fcntl(nfd, F_SETFD, 0);
1252 * Move fd from user space (0 <= fd < 10) to shell space (fd >= 10),
1253 * set close-on-exec flag. See FDBASE in sh.h, maybe 24 not 10 here.
1260 if (fd < FDBASE && (nfd = fcntl(fd, F_DUPFD, FDBASE)) < 0 &&
1263 if (nfd < 0 || nfd > SHRT_MAX)
1264 errorf("too many files open in shell");
1265 fcntl(nfd, F_SETFD, FD_CLOEXEC);
1266 return ((short)nfd);
1270 restfd(int fd, int ofd)
1273 shf_flush(&shf_iob[fd]);
1275 /* original fd closed */
1277 else if (fd != ofd) {
1278 /*XXX: what to do if this dup fails? */
1279 ksh_dup2(ofd, fd, true);
1290 errorf("can't create pipe - try again");
1291 pv[0] = savefd(lpv[0]);
1292 if (pv[0] != lpv[0])
1294 pv[1] = savefd(lpv[1]);
1295 if (pv[1] != lpv[1])
1307 * Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
1308 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
1311 check_fd(const char *name, int mode, const char **emsgp)
1315 if (name[0] == 'p' && !name[1])
1316 return (coproc_getfd(mode, emsgp));
1317 for (fd = 0; ksh_isdigit(*name); ++name)
1318 fd = (fd * 10) + *name - '0';
1319 if (*name || fd >= FDBASE) {
1321 *emsgp = "illegal file descriptor name";
1324 if ((fl = fcntl(fd, F_GETFL, 0)) < 0) {
1326 *emsgp = "bad file descriptor";
1331 * X_OK is a kludge to disable this check for dups (x<&1):
1332 * historical shells never did this check (XXX don't know what
1333 * POSIX has to say).
1335 if (!(mode & X_OK) && fl != O_RDWR && (
1336 ((mode & R_OK) && fl != O_RDONLY) ||
1337 ((mode & W_OK) && fl != O_WRONLY))) {
1339 *emsgp = (fl == O_WRONLY) ?
1340 "fd not open for reading" :
1341 "fd not open for writing";
1347 /* Called once from main */
1351 coproc.read = coproc.readw = coproc.write = -1;
1356 /* Called by c_read() when eof is read - close fd if it is the co-process fd */
1358 coproc_read_close(int fd)
1360 if (coproc.read >= 0 && fd == coproc.read) {
1361 coproc_readw_close(fd);
1368 * Called by c_read() and by iosetup() to close the other side of the
1369 * read pipe, so reads will actually terminate.
1372 coproc_readw_close(int fd)
1374 if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
1375 close(coproc.readw);
1381 * Called by c_print when a write to a fd fails with EPIPE and by iosetup
1382 * when co-process input is dup'd
1385 coproc_write_close(int fd)
1387 if (coproc.write >= 0 && fd == coproc.write) {
1388 close(coproc.write);
1394 * Called to check for existence of/value of the co-process file descriptor.
1395 * (Used by check_fd() and by c_read/c_print to deal with -p option).
1398 coproc_getfd(int mode, const char **emsgp)
1400 int fd = (mode & R_OK) ? coproc.read : coproc.write;
1405 *emsgp = "no coprocess";
1410 * called to close file descriptors related to the coprocess (if any)
1411 * Should be called with SIGCHLD blocked.
1414 coproc_cleanup(int reuse)
1416 /* This to allow co-processes to share output pipe */
1417 if (!reuse || coproc.readw < 0 || coproc.read < 0) {
1418 if (coproc.read >= 0) {
1422 if (coproc.readw >= 0) {
1423 close(coproc.readw);
1427 if (coproc.write >= 0) {
1428 close(coproc.write);
1434 maketemp(Area *ap, Temp_type type, struct temp **tlist)
1442 dir = tmpdir ? tmpdir : MKSH_DEFAULT_TMPDIR;
1444 len = strlen(dir) + 6 + 10 + 1;
1446 pathname = tempnam(dir, "mksh.");
1447 len = ((pathname == NULL) ? 0 : strlen(pathname)) + 1;
1449 /* reasonably sure that this will not overflow */
1450 tp = alloc(sizeof(struct temp) + len, ap);
1451 tp->name = (char *)&tp[1];
1453 if (pathname == NULL)
1456 memcpy(tp->name, pathname, len);
1457 free_ostempnam(pathname);
1460 pathname = tp->name;
1464 shf_snprintf(pathname, len, "%s%s", dir, "/mksh.XXXXXXXXXX");
1465 if ((fd = mkstemp(pathname)) >= 0)
1467 if (tp->name[0] && (fd = open(tp->name, O_CREAT | O_RDWR, 0600)) >= 0)
1469 tp->shf = shf_fdopen(fd, SHF_WR, NULL);
1478 * We use a similar collision resolution algorithm as Python 2.5.4
1479 * but with a slightly tweaked implementation written from scratch.
1482 #define INIT_TBLSHIFT 3 /* initial table shift (2^3 = 8) */
1483 #define PERTURB_SHIFT 5 /* see Python 2.5.4 Objects/dictobject.c */
1485 static void tgrow(struct table *);
1486 static int tnamecmp(const void *, const void *);
1489 tgrow(struct table *tp)
1491 size_t i, j, osize, mask, perturb;
1492 struct tbl *tblp, **pp;
1493 struct tbl **ntblp, **otblp = tp->tbls;
1495 if (tp->tshift > 29)
1496 internal_errorf("hash table size limit reached");
1498 /* calculate old size, new shift and new size */
1499 osize = (size_t)1 << (tp->tshift++);
1502 ntblp = alloc2(i, sizeof(struct tbl *), tp->areap);
1503 /* multiplication cannot overflow: alloc2 checked that */
1504 memset(ntblp, 0, i * sizeof(struct tbl *));
1506 /* table can get 80% full except when reaching its limit */
1507 tp->nfree = (tp->tshift == 30) ? 0x3FFF0000UL : ((i * 4) / 5);
1513 for (i = 0; i < osize; i++)
1514 if ((tblp = otblp[i]) != NULL) {
1515 if ((tblp->flag & DEFINED)) {
1516 /* search for free hash table slot */
1517 j = (perturb = tblp->ua.hval) & mask;
1518 goto find_first_empty_slot;
1519 find_next_empty_slot:
1520 j = (j << 2) + j + perturb + 1;
1521 perturb >>= PERTURB_SHIFT;
1522 find_first_empty_slot:
1523 pp = &ntblp[j & mask];
1525 goto find_next_empty_slot;
1526 /* found an empty hash table slot */
1529 } else if (!(tblp->flag & FINUSE)) {
1530 afree(tblp, tp->areap);
1533 afree(otblp, tp->areap);
1537 ktinit(Area *ap, struct table *tp, uint8_t initshift)
1541 tp->tshift = ((initshift > INIT_TBLSHIFT) ?
1542 initshift : INIT_TBLSHIFT) - 1;
1546 /* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
1548 ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
1550 size_t j, perturb, mask;
1551 struct tbl **pp, *p;
1553 mask = ((size_t)1 << (tp->tshift)) - 1;
1554 /* search for hash table slot matching name */
1555 j = (perturb = h) & mask;
1556 goto find_first_slot;
1558 j = (j << 2) + j + perturb + 1;
1559 perturb >>= PERTURB_SHIFT;
1561 pp = &tp->tbls[j & mask];
1562 if ((p = *pp) != NULL && (p->ua.hval != h || !(p->flag & DEFINED) ||
1563 strcmp(p->name, name)))
1564 goto find_next_slot;
1565 /* p == NULL if not found, correct found entry otherwise */
1571 /* table, name (key) to enter, hash(n) */
1573 ktenter(struct table *tp, const char *n, uint32_t h)
1575 struct tbl **pp, *p;
1579 if ((p = ktscan(tp, n, h, &pp)))
1582 if (tp->nfree == 0) {
1588 /* create new tbl entry */
1590 checkoktoadd(len, offsetof(struct tbl, name[0]) + 1);
1591 p = alloc(offsetof(struct tbl, name[0]) + ++len, tp->areap);
1594 p->areap = tp->areap;
1598 memcpy(p->name, n, len);
1600 /* enter in tp->tbls */
1607 ktwalk(struct tstate *ts, struct table *tp)
1609 ts->left = (size_t)1 << (tp->tshift);
1610 ts->next = tp->tbls;
1614 ktnext(struct tstate *ts)
1616 while (--ts->left >= 0) {
1617 struct tbl *p = *ts->next++;
1618 if (p != NULL && (p->flag & DEFINED))
1625 tnamecmp(const void *p1, const void *p2)
1627 const struct tbl *a = *((const struct tbl * const *)p1);
1628 const struct tbl *b = *((const struct tbl * const *)p2);
1630 return (strcmp(a->name, b->name));
1634 ktsort(struct table *tp)
1637 struct tbl **p, **sp, **dp;
1640 * since the table is never entirely full, no need to reserve
1641 * additional space for the trailing NULL appended below
1643 i = (size_t)1 << (tp->tshift);
1644 p = alloc2(i, sizeof(struct tbl *), ATEMP);
1645 sp = tp->tbls; /* source */
1648 if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
1649 ((*dp)->flag & ARRAY)))
1651 qsort(p, (i = dp - p), sizeof(struct tbl *), tnamecmp);
1658 x_sigwinch(int sig MKSH_A_UNUSED)
1660 /* this runs inside interrupt context, with errno saved */