ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/branches/MIROS/contrib/mksh/main.c
Revision: 1225
Committed: Tue Sep 11 22:02:31 2007 UTC (16 years, 8 months ago) by laffer1
Content type: text/plain
File size: 28828 byte(s)
Log Message:
Virgin import of mksh version R31b.

File Contents

# Content
1 /* $OpenBSD: main.c,v 1.43 2007/05/31 20:47:44 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.12 2005/12/11 20:31:21 otto Exp $ */
5
6 #define EXTERN
7 #include "sh.h"
8
9 #if HAVE_LANGINFO_CODESET
10 #include <langinfo.h>
11 #endif
12 #if HAVE_SETLOCALE_CTYPE
13 #include <locale.h>
14 #endif
15
16 __RCSID("$MirOS: src/bin/mksh/main.c,v 1.87 2007/08/19 22:06:26 tg Exp $");
17
18 extern char **environ;
19
20 #if !HAVE_SETRESUGID
21 extern uid_t kshuid;
22 extern gid_t kshgid, kshegid;
23 #endif
24
25 static void reclaim(void);
26 static void remove_temps(struct temp *);
27
28 static const char initifs[] = "IFS= \t\n";
29
30 static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
31
32 static const char *initcoms[] = {
33 "typeset", "-r", initvsn, NULL,
34 "typeset", "-x", "SHELL", "PATH", "HOME", NULL,
35 "typeset", "-i", "PPID", "OPTIND=1", NULL,
36 "eval", "typeset -i RANDOM SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,
37 "alias", "integer=typeset -i", "local=typeset", NULL,
38 NULL
39 };
40
41 static const char *initcoms_korn[] = {
42 "alias",
43 "hash=alias -t", /* not "alias -t --": hash -r needs to work */
44 "type=whence -v",
45 "stop=kill -STOP",
46 "suspend=kill -STOP $$",
47 "autoload=typeset -fu",
48 "functions=typeset -f",
49 "history=fc -l",
50 "nohup=nohup ",
51 "r=fc -e -",
52 "source=PATH=$PATH:. command .",
53 "login=exec login",
54 NULL,
55 /* this is what at&t ksh seems to track, with the addition of emacs */
56 "alias", "-tU",
57 "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
58 "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", NULL,
59 NULL
60 };
61
62 static int initio_done;
63
64 int
65 main(int argc, const char *argv[])
66 {
67 int argi, i;
68 Source *s;
69 struct block *l;
70 int restricted, errexit;
71 const char **wp, *cc;
72 struct env env;
73 pid_t ppid;
74 struct tbl *vp;
75 struct stat s_stdin;
76 #if !defined(_PATH_DEFPATH) && defined(_CS_PATH)
77 size_t k;
78 char *cp;
79 #endif
80
81 /* make sure argv[] is sane */
82 if (!*argv) {
83 static const char *empty_argv[] = {
84 "mksh", NULL
85 };
86
87 argv = empty_argv;
88 argc = 1;
89 }
90 kshname = *argv;
91
92 ainit(&aperm); /* initialise permanent Area */
93
94 /* set up base environment */
95 memset(&env, 0, sizeof(env));
96 env.type = E_NONE;
97 ainit(&env.area);
98 e = &env;
99 newblock(); /* set up global l->vars and l->funs */
100
101 /* Do this first so output routines (eg, errorf, shellf) can work */
102 initio();
103
104 argi = parse_args(argv, OF_FIRSTTIME, NULL);
105 if (argi < 0)
106 exit(1);
107
108 initvar();
109
110 initctypes();
111
112 inittraps();
113
114 coproc_init();
115
116 /* set up variable and command dictionaries */
117 ktinit(&taliases, APERM, 0);
118 ktinit(&aliases, APERM, 0);
119 #ifndef MKSH_SMALL
120 ktinit(&homedirs, APERM, 0);
121 #endif
122
123 /* define shell keywords */
124 initkeywords();
125
126 /* define built-in commands */
127 ktinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
128 for (i = 0; mkshbuiltins[i].name != NULL; i++)
129 builtin(mkshbuiltins[i].name, mkshbuiltins[i].func);
130
131 init_histvec();
132
133 #ifdef _PATH_DEFPATH
134 def_path = _PATH_DEFPATH;
135 #else
136 #ifdef _CS_PATH
137 if ((k = confstr(_CS_PATH, NULL, 0)) != (size_t)-1 && k > 0 &&
138 confstr(_CS_PATH, cp = alloc(k + 1, APERM), k + 1) == k + 1)
139 def_path = cp;
140 else
141 #endif
142 /*
143 * this is uniform across all OSes unless it
144 * breaks somewhere; don't try to optimise,
145 * e.g. add stuff for Interix or remove /usr
146 * for HURD, because e.g. Debian GNU/HURD is
147 * "keeping a regular /usr"; this is supposed
148 * to be a sane 'basic' default PATH
149 */
150 def_path = "/bin:/usr/bin:/sbin:/usr/sbin";
151 #endif
152
153 /* Set PATH to def_path (will set the path global variable).
154 * (import of environment below will probably change this setting).
155 */
156 vp = global("PATH");
157 /* setstr can't fail here */
158 setstr(vp, def_path, KSH_RETURN_ERROR);
159
160 /* Set FPOSIX if we're called as -sh or /bin/sh or so */
161 cc = kshname;
162 i = 0; argi = 0;
163 while (cc[i] != '\0')
164 if ((cc[i++] | 2) == '/')
165 argi = i;
166 if (((cc[argi] | 0x20) == 's') && ((cc[argi + 1] | 0x20) == 'h'))
167 Flag(FPOSIX) = 1;
168
169 /* Turn on nohup by default for now - will change to off
170 * by default once people are aware of its existence
171 * (at&t ksh does not have a nohup option - it always sends
172 * the hup).
173 */
174 Flag(FNOHUP) = 1;
175
176 /* Turn on brace expansion by default. AT&T kshs that have
177 * alternation always have it on.
178 */
179 Flag(FBRACEEXPAND) = 1;
180
181 /* Set edit mode to emacs by default, may be overridden
182 * by the environment or the user. Also, we want tab completion
183 * on in vi by default. */
184 change_flag(FEMACS, OF_SPECIAL, 1);
185 #ifndef MKSH_NOVI
186 Flag(FVITABCOMPLETE) = 1;
187 #endif
188
189 /* import environment */
190 if (environ != NULL)
191 for (wp = (const char **)environ; *wp != NULL; wp++)
192 typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
193
194 kshpid = procpid = getpid();
195 typeset(initifs, 0, 0, 0, 0); /* for security */
196
197 /* assign default shell variable values */
198 substitute(initsubs, 0);
199
200 /* Figure out the current working directory and set $PWD */
201 {
202 struct stat s_pwd, s_dot;
203 struct tbl *pwd_v = global("PWD");
204 char *pwd = str_val(pwd_v);
205 char *pwdx = pwd;
206
207 /* Try to use existing $PWD if it is valid */
208 if (pwd[0] != '/' ||
209 stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0 ||
210 s_pwd.st_dev != s_dot.st_dev ||
211 s_pwd.st_ino != s_dot.st_ino)
212 pwdx = NULL;
213 set_current_wd(pwdx);
214 if (current_wd[0])
215 simplify_path(current_wd);
216 /* Only set pwd if we know where we are or if it had a
217 * bogus value
218 */
219 if (current_wd[0] || pwd != null)
220 /* setstr can't fail here */
221 setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
222 }
223 ppid = getppid();
224 change_random(((u_long)kshname) ^ ((u_long)time(NULL) * kshpid * ppid));
225 #if HAVE_ARC4RANDOM
226 Flag(FARC4RANDOM) = 2; /* use arc4random(3) until $RANDOM is written */
227 #endif
228 setint(global("PPID"), (long)ppid);
229
230 for (wp = initcoms; *wp != NULL; wp++) {
231 shcomexec(wp);
232 while (*wp != NULL)
233 wp++;
234 }
235
236 safe_prompt = (ksheuid = geteuid()) ? "$ " : "# ";
237 vp = global("PS1");
238 /* Set PS1 if unset or we are root and prompt doesn't contain a # */
239 if (!(vp->flag & ISSET) ||
240 (!ksheuid && !strchr(str_val(vp), '#')))
241 /* setstr can't fail here */
242 setstr(vp, safe_prompt, KSH_RETURN_ERROR);
243
244 /* Set this before parsing arguments */
245 #if HAVE_SETRESUGID
246 Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid();
247 #else
248 Flag(FPRIVILEGED) = (kshuid = getuid()) != ksheuid ||
249 (kshgid = getgid()) != (kshegid = getegid());
250 #endif
251
252 /* this to note if monitor is set on command line (see below) */
253 Flag(FMONITOR) = 127;
254 argi = parse_args(argv, OF_CMDLINE, NULL);
255 if (argi < 0)
256 exit(1);
257
258 if (!Flag(FPOSIX))
259 for (wp = initcoms_korn; *wp != NULL; wp++) {
260 shcomexec(wp);
261 while (*wp != NULL)
262 wp++;
263 }
264
265 if (Flag(FCOMMAND)) {
266 s = pushs(SSTRING, ATEMP);
267 if (!(s->start = s->str = argv[argi++]))
268 errorf("-c requires an argument");
269 if (argv[argi])
270 kshname = argv[argi++];
271 } else if (argi < argc && !Flag(FSTDIN)) {
272 s = pushs(SFILE, ATEMP);
273 s->file = kshname = argv[argi++];
274 s->u.shf = shf_open(s->file, O_RDONLY, 0,
275 SHF_MAPHI | SHF_CLEXEC);
276 if (s->u.shf == NULL) {
277 exstat = 127; /* POSIX */
278 errorf("%s: %s", s->file, strerror(errno));
279 }
280 } else {
281 Flag(FSTDIN) = 1;
282 s = pushs(SSTDIN, ATEMP);
283 s->file = "<stdin>";
284 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
285 NULL);
286 if (isatty(0) && isatty(2)) {
287 Flag(FTALKING) = Flag(FTALKING_I) = 1;
288 /* The following only if isatty(0) */
289 s->flags |= SF_TTY;
290 s->u.shf->flags |= SHF_INTERRUPT;
291 s->file = NULL;
292 }
293 }
294
295 /* This bizarreness is mandated by POSIX */
296 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
297 Flag(FTALKING))
298 reset_nonblock(0);
299
300 /* initialise job control */
301 i = Flag(FMONITOR) != 127;
302 Flag(FMONITOR) = 0;
303 j_init(i);
304 /* Do this after j_init(), as tty_fd is not initialised 'til then */
305 if (Flag(FTALKING)) {
306 #ifndef MKSH_ASSUME_UTF8
307 #if HAVE_SETLOCALE_CTYPE
308 #define isuc(x) (((x) != NULL) && \
309 (stristr((x), "UTF-8") || stristr((x), "utf8")))
310 /* Check if we're in a UTF-8 locale */
311 if (!Flag(FUTFHACK)) {
312 cc = setlocale(LC_CTYPE, "");
313 #if HAVE_LANGINFO_CODESET
314 if (!isuc(cc))
315 cc = nl_langinfo(CODESET);
316 #endif
317 Flag(FUTFHACK) = isuc(cc);
318 }
319 #undef isuc
320 #endif
321 #else
322 Flag(FUTFHACK) = 1;
323 #endif
324 x_init();
325 }
326
327 l = e->loc;
328 l->argv = &argv[argi - 1];
329 l->argc = argc - argi;
330 l->argv[0] = kshname;
331 getopts_reset(1);
332
333 /* Disable during .profile/ENV reading */
334 restricted = Flag(FRESTRICTED);
335 Flag(FRESTRICTED) = 0;
336 errexit = Flag(FERREXIT);
337 Flag(FERREXIT) = 0;
338
339 /* Do this before profile/$ENV so that if it causes problems in them,
340 * user will know why things broke.
341 */
342 if (!current_wd[0] && Flag(FTALKING))
343 warningf(false, "Cannot determine current working directory");
344
345 if (Flag(FLOGIN)) {
346 include(KSH_SYSTEM_PROFILE, 0, NULL, 1);
347 if (!Flag(FPRIVILEGED))
348 include(substitute("$HOME/.profile", 0), 0,
349 NULL, 1);
350 }
351 if (Flag(FPRIVILEGED))
352 include("/etc/suid_profile", 0, NULL, 1);
353 else if (Flag(FTALKING)) {
354 char *env_file;
355
356 /* include $ENV */
357 env_file = substitute(substitute("${ENV:-~/.mkshrc}", 0),
358 DOTILDE);
359 if (*env_file != '\0')
360 include(env_file, 0, NULL, 1);
361 }
362
363 if (restricted) {
364 static const char *restr_com[] = {
365 "typeset", "-r", "PATH",
366 "ENV", "SHELL",
367 NULL
368 };
369 shcomexec(restr_com);
370 /* After typeset command... */
371 Flag(FRESTRICTED) = 1;
372 }
373 if (errexit)
374 Flag(FERREXIT) = 1;
375
376 if (Flag(FTALKING)) {
377 hist_init(s);
378 alarm_init();
379 } else
380 Flag(FTRACKALL) = 1; /* set after ENV */
381
382 shell(s, true); /* doesn't return */
383 return 0;
384 }
385
386 int
387 include(const char *name, int argc, const char **argv, int intr_ok)
388 {
389 Source *volatile s = NULL;
390 struct shf *shf;
391 const char **volatile old_argv;
392 volatile int old_argc;
393 int i;
394
395 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
396 if (shf == NULL)
397 return -1;
398
399 if (argv) {
400 old_argv = e->loc->argv;
401 old_argc = e->loc->argc;
402 } else {
403 old_argv = NULL;
404 old_argc = 0;
405 }
406 newenv(E_INCL);
407 i = sigsetjmp(e->jbuf, 0);
408 if (i) {
409 quitenv(s ? s->u.shf : NULL);
410 if (old_argv) {
411 e->loc->argv = old_argv;
412 e->loc->argc = old_argc;
413 }
414 switch (i) {
415 case LRETURN:
416 case LERROR:
417 return exstat & 0xff; /* see below */
418 case LINTR:
419 /* intr_ok is set if we are including .profile or $ENV.
420 * If user ^Cs out, we don't want to kill the shell...
421 */
422 if (intr_ok && (exstat - 128) != SIGTERM)
423 return 1;
424 /* FALLTHRU */
425 case LEXIT:
426 case LLEAVE:
427 case LSHELL:
428 unwind(i);
429 /* NOTREACHED */
430 default:
431 internal_errorf("include: %d", i);
432 /* NOTREACHED */
433 }
434 }
435 if (argv) {
436 e->loc->argv = argv;
437 e->loc->argc = argc;
438 }
439 s = pushs(SFILE, ATEMP);
440 s->u.shf = shf;
441 s->file = str_save(name, ATEMP);
442 i = shell(s, false);
443 quitenv(s->u.shf);
444 if (old_argv) {
445 e->loc->argv = old_argv;
446 e->loc->argc = old_argc;
447 }
448 return i & 0xff; /* & 0xff to ensure value not -1 */
449 }
450
451 int
452 command(const char *comm)
453 {
454 Source *s;
455
456 s = pushs(SSTRING, ATEMP);
457 s->start = s->str = comm;
458 return shell(s, false);
459 }
460
461 /*
462 * run the commands from the input source, returning status.
463 */
464 int
465 shell(Source * volatile s, volatile int toplevel)
466 {
467 struct op *t;
468 volatile int wastty = s->flags & SF_TTY;
469 volatile int attempts = 13;
470 volatile int interactive = Flag(FTALKING) && toplevel;
471 Source *volatile old_source = source;
472 int i;
473
474 s->flags |= SF_FIRST; /* enable UTF-8 BOM check */
475
476 newenv(E_PARSE);
477 if (interactive)
478 really_exit = 0;
479 i = sigsetjmp(e->jbuf, 0);
480 if (i) {
481 switch (i) {
482 case LINTR: /* we get here if SIGINT not caught or ignored */
483 case LERROR:
484 case LSHELL:
485 if (interactive) {
486 if (i == LINTR)
487 shellf("\n");
488 /* Reset any eof that was read as part of a
489 * multiline command.
490 */
491 if (Flag(FIGNOREEOF) && s->type == SEOF &&
492 wastty)
493 s->type = SSTDIN;
494 /* Used by exit command to get back to
495 * top level shell. Kind of strange since
496 * interactive is set if we are reading from
497 * a tty, but to have stopped jobs, one only
498 * needs FMONITOR set (not FTALKING/SF_TTY)...
499 */
500 /* toss any input we have so far */
501 s->start = s->str = null;
502 break;
503 }
504 /* FALLTHRU */
505 case LEXIT:
506 case LLEAVE:
507 case LRETURN:
508 source = old_source;
509 quitenv(NULL);
510 unwind(i); /* keep on going */
511 /* NOTREACHED */
512 default:
513 source = old_source;
514 quitenv(NULL);
515 internal_errorf("shell: %d", i);
516 /* NOTREACHED */
517 }
518 }
519 while (1) {
520 if (trap)
521 runtraps(0);
522
523 if (s->next == NULL) {
524 if (Flag(FVERBOSE))
525 s->flags |= SF_ECHO;
526 else
527 s->flags &= ~SF_ECHO;
528 }
529 if (interactive) {
530 j_notify();
531 set_prompt(PS1, s);
532 }
533 t = compile(s);
534 if (t != NULL && t->type == TEOF) {
535 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
536 shellf("Use 'exit' to leave ksh\n");
537 s->type = SSTDIN;
538 } else if (wastty && !really_exit &&
539 j_stopped_running()) {
540 really_exit = 1;
541 s->type = SSTDIN;
542 } else {
543 /* this for POSIX which says EXIT traps
544 * shall be taken in the environment
545 * immediately after the last command
546 * executed.
547 */
548 if (toplevel)
549 unwind(LEXIT);
550 break;
551 }
552 }
553 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
554 exstat = execute(t, 0);
555
556 if (t != NULL && t->type != TEOF && interactive && really_exit)
557 really_exit = 0;
558
559 reclaim();
560 }
561 quitenv(NULL);
562 source = old_source;
563 return exstat;
564 }
565
566 /* return to closest error handler or shell(), exit if none found */
567 void
568 unwind(int i)
569 {
570 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
571 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) &&
572 sigtraps[SIGEXIT_].trap)) {
573 runtrap(&sigtraps[SIGEXIT_]);
574 i = LLEAVE;
575 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
576 runtrap(&sigtraps[SIGERR_]);
577 i = LLEAVE;
578 }
579 while (1) {
580 switch (e->type) {
581 case E_PARSE:
582 case E_FUNC:
583 case E_INCL:
584 case E_LOOP:
585 case E_ERRH:
586 siglongjmp(e->jbuf, i);
587 /* NOTREACHED */
588 case E_NONE:
589 if (i == LINTR)
590 e->flags |= EF_FAKE_SIGDIE;
591 /* FALLTHRU */
592 default:
593 quitenv(NULL);
594 }
595 }
596 }
597
598 void
599 newenv(int type)
600 {
601 struct env *ep;
602
603 ep = (struct env *) alloc(sizeof(*ep), ATEMP);
604 ep->type = type;
605 ep->flags = 0;
606 ainit(&ep->area);
607 ep->loc = e->loc;
608 ep->savefd = NULL;
609 ep->oenv = e;
610 ep->temps = NULL;
611 e = ep;
612 }
613
614 void
615 quitenv(struct shf *shf)
616 {
617 struct env *ep = e;
618 int fd;
619
620 if (ep->oenv && ep->oenv->loc != ep->loc)
621 popblock();
622 if (ep->savefd != NULL) {
623 for (fd = 0; fd < NUFILE; fd++)
624 /* if ep->savefd[fd] < 0, means fd was closed */
625 if (ep->savefd[fd])
626 restfd(fd, ep->savefd[fd]);
627 if (ep->savefd[2]) /* Clear any write errors */
628 shf_reopen(2, SHF_WR, shl_out);
629 }
630 /* Bottom of the stack.
631 * Either main shell is exiting or cleanup_parents_env() was called.
632 */
633 if (ep->oenv == NULL) {
634 if (ep->type == E_NONE) { /* Main shell exiting? */
635 #if HAVE_PERSISTENT_HISTORY
636 if (Flag(FTALKING))
637 hist_finish();
638 #endif
639 j_exit();
640 if (ep->flags & EF_FAKE_SIGDIE) {
641 int sig = exstat - 128;
642
643 /* ham up our death a bit (at&t ksh
644 * only seems to do this for SIGTERM)
645 * Don't do it for SIGQUIT, since we'd
646 * dump a core..
647 */
648 if ((sig == SIGINT || sig == SIGTERM) &&
649 getpgrp() == kshpid) {
650 setsig(&sigtraps[sig], SIG_DFL,
651 SS_RESTORE_CURR | SS_FORCE);
652 kill(0, sig);
653 }
654 }
655 }
656 if (shf)
657 shf_close(shf);
658 reclaim();
659 exit(exstat);
660 }
661 if (shf)
662 shf_close(shf);
663 reclaim();
664
665 e = e->oenv;
666 afree(ep, ATEMP);
667 }
668
669 /* Called after a fork to cleanup stuff left over from parents environment */
670 void
671 cleanup_parents_env(void)
672 {
673 struct env *ep;
674 int fd;
675
676 /* Don't clean up temporary files - parent will probably need them.
677 * Also, can't easily reclaim memory since variables, etc. could be
678 * anywhere.
679 */
680
681 /* close all file descriptors hiding in savefd */
682 for (ep = e; ep; ep = ep->oenv) {
683 if (ep->savefd) {
684 for (fd = 0; fd < NUFILE; fd++)
685 if (ep->savefd[fd] > 0)
686 close(ep->savefd[fd]);
687 afree(ep->savefd, &ep->area);
688 ep->savefd = NULL;
689 }
690 }
691 e->oenv = NULL;
692 }
693
694 /* Called just before an execve cleanup stuff temporary files */
695 void
696 cleanup_proc_env(void)
697 {
698 struct env *ep;
699
700 for (ep = e; ep; ep = ep->oenv)
701 remove_temps(ep->temps);
702 }
703
704 /* remove temp files and free ATEMP Area */
705 static void
706 reclaim(void)
707 {
708 remove_temps(e->temps);
709 e->temps = NULL;
710 afreeall(&e->area);
711 }
712
713 static void
714 remove_temps(struct temp *tp)
715 {
716
717 for (; tp != NULL; tp = tp->next)
718 if (tp->pid == procpid) {
719 unlink(tp->name);
720 }
721 }
722
723 /* Initialise tty_fd. Used for saving/reseting tty modes upon
724 * foreground job completion and for setting up tty process group.
725 */
726 void
727 tty_init(int init_ttystate)
728 {
729 int do_close = 1;
730 int tfd;
731
732 if (tty_fd >= 0) {
733 close(tty_fd);
734 tty_fd = -1;
735 }
736 tty_devtty = 1;
737
738 #ifdef _UWIN
739 if (isatty(3))
740 tfd = 3;
741 else
742 #endif
743 if ((tfd = open("/dev/tty", O_RDWR, 0)) < 0) {
744 tty_devtty = 0;
745 warningf(false, "No controlling tty (open /dev/tty: %s)",
746 strerror(errno));
747 }
748 if (tfd < 0) {
749 do_close = 0;
750 if (isatty(0))
751 tfd = 0;
752 else if (isatty(2))
753 tfd = 2;
754 else {
755 warningf(false, "Can't find tty file descriptor");
756 return;
757 }
758 }
759 if ((tty_fd = fcntl(tfd, F_DUPFD, FDBASE)) < 0) {
760 warningf(false, "j_ttyinit: dup of tty fd failed: %s",
761 strerror(errno));
762 } else if (fcntl(tty_fd, F_SETFD, FD_CLOEXEC) < 0) {
763 warningf(false, "j_ttyinit: can't set close-on-exec flag: %s",
764 strerror(errno));
765 close(tty_fd);
766 tty_fd = -1;
767 } else if (init_ttystate)
768 tcgetattr(tty_fd, &tty_state);
769 if (do_close)
770 close(tfd);
771 }
772
773 void
774 tty_close(void)
775 {
776 if (tty_fd >= 0) {
777 close(tty_fd);
778 tty_fd = -1;
779 }
780 }
781
782 /* A shell error occurred (eg, syntax error, etc.) */
783 void
784 errorf(const char *fmt, ...)
785 {
786 va_list va;
787
788 shl_stdout_ok = 0; /* debugging: note that stdout not valid */
789 exstat = 1;
790 if (*fmt) {
791 error_prefix(true);
792 va_start(va, fmt);
793 shf_vfprintf(shl_out, fmt, va);
794 va_end(va);
795 shf_putchar('\n', shl_out);
796 }
797 shf_flush(shl_out);
798 unwind(LERROR);
799 }
800
801 /* like errorf(), but no unwind is done */
802 void
803 warningf(bool fileline, const char *fmt, ...)
804 {
805 va_list va;
806
807 error_prefix(fileline);
808 va_start(va, fmt);
809 shf_vfprintf(shl_out, fmt, va);
810 va_end(va);
811 shf_putchar('\n', shl_out);
812 shf_flush(shl_out);
813 }
814
815 /* Used by built-in utilities to prefix shell and utility name to message
816 * (also unwinds environments for special builtins).
817 */
818 void
819 bi_errorf(const char *fmt, ...)
820 {
821 va_list va;
822
823 shl_stdout_ok = 0; /* debugging: note that stdout not valid */
824 exstat = 1;
825 if (*fmt) {
826 error_prefix(true);
827 /* not set when main() calls parse_args() */
828 if (builtin_argv0)
829 shf_fprintf(shl_out, "%s: ", builtin_argv0);
830 va_start(va, fmt);
831 shf_vfprintf(shl_out, fmt, va);
832 va_end(va);
833 shf_putchar('\n', shl_out);
834 }
835 shf_flush(shl_out);
836 /* POSIX special builtins and ksh special builtins cause
837 * non-interactive shells to exit.
838 * XXX odd use of KEEPASN; also may not want LERROR here
839 */
840 if (builtin_flag & SPEC_BI) {
841 builtin_argv0 = NULL;
842 unwind(LERROR);
843 }
844 }
845
846 /* Called when something that shouldn't happen does */
847 static void internal_verrorf(const char *, va_list)
848 __attribute__((format (printf, 1, 0)));
849 static void
850 internal_verrorf(const char *fmt, va_list ap)
851 {
852 shf_fprintf(shl_out, "internal error: ");
853 shf_vfprintf(shl_out, fmt, ap);
854 shf_putchar('\n', shl_out);
855 shf_flush(shl_out);
856 }
857
858 void
859 internal_errorf(const char *fmt, ...)
860 {
861 va_list va;
862
863 va_start(va, fmt);
864 internal_verrorf(fmt, va);
865 va_end(va);
866 unwind(LERROR);
867 }
868
869 void
870 internal_warningf(const char *fmt, ...)
871 {
872 va_list va;
873
874 va_start(va, fmt);
875 internal_verrorf(fmt, va);
876 va_end(va);
877 }
878
879 /* used by error reporting functions to print "ksh: .kshrc[25]: " */
880 void
881 error_prefix(bool fileline)
882 {
883 /* Avoid foo: foo[2]: ... */
884 if (!fileline || !source || !source->file ||
885 strcmp(source->file, kshname) != 0)
886 shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
887 if (fileline && source && source->file != NULL) {
888 shf_fprintf(shl_out, "%s[%d]: ", source->file,
889 source->errline > 0 ? source->errline : source->line);
890 source->errline = 0;
891 }
892 }
893
894 /* printf to shl_out (stderr) with flush */
895 void
896 shellf(const char *fmt, ...)
897 {
898 va_list va;
899
900 if (!initio_done) /* shl_out may not be set up yet... */
901 return;
902 va_start(va, fmt);
903 shf_vfprintf(shl_out, fmt, va);
904 va_end(va);
905 shf_flush(shl_out);
906 }
907
908 /* printf to shl_stdout (stdout) */
909 void
910 shprintf(const char *fmt, ...)
911 {
912 va_list va;
913
914 if (!shl_stdout_ok)
915 internal_errorf("shl_stdout not valid");
916 va_start(va, fmt);
917 shf_vfprintf(shl_stdout, fmt, va);
918 va_end(va);
919 }
920
921 /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
922 int
923 can_seek(int fd)
924 {
925 struct stat statb;
926
927 return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
928 SHF_UNBUF : 0;
929 }
930
931 struct shf shf_iob[3];
932
933 void
934 initio(void)
935 {
936 shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
937 shf_fdopen(2, SHF_WR, shl_out);
938 shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
939 initio_done = 1;
940 }
941
942 /* A dup2() with error checking */
943 int
944 ksh_dup2(int ofd, int nfd, int errok)
945 {
946 int ret = dup2(ofd, nfd);
947
948 if (ret < 0 && errno != EBADF && !errok)
949 errorf("too many files open in shell");
950
951 return ret;
952 }
953
954 /*
955 * move fd from user space (0<=fd<10) to shell space (fd>=10),
956 * set close-on-exec flag.
957 */
958 short
959 savefd(int fd)
960 {
961 int nfd = fd;
962
963 if (fd < FDBASE && (nfd = fcntl(fd, F_DUPFD, FDBASE)) < 0 &&
964 errno == EBADF)
965 return -1;
966 if (nfd < 0 || nfd > SHRT_MAX)
967 errorf("too many files open in shell");
968 fcntl(nfd, F_SETFD, FD_CLOEXEC);
969 return ((short)nfd);
970 }
971
972 void
973 restfd(int fd, int ofd)
974 {
975 if (fd == 2)
976 shf_flush(&shf_iob[fd]);
977 if (ofd < 0) /* original fd closed */
978 close(fd);
979 else if (fd != ofd) {
980 ksh_dup2(ofd, fd, true); /* XXX: what to do if this fails? */
981 close(ofd);
982 }
983 }
984
985 void
986 openpipe(int *pv)
987 {
988 int lpv[2];
989
990 if (pipe(lpv) < 0)
991 errorf("can't create pipe - try again");
992 pv[0] = savefd(lpv[0]);
993 if (pv[0] != lpv[0])
994 close(lpv[0]);
995 pv[1] = savefd(lpv[1]);
996 if (pv[1] != lpv[1])
997 close(lpv[1]);
998 }
999
1000 void
1001 closepipe(int *pv)
1002 {
1003 close(pv[0]);
1004 close(pv[1]);
1005 }
1006
1007 /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
1008 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
1009 */
1010 int
1011 check_fd(const char *name, int mode, const char **emsgp)
1012 {
1013 int fd, fl;
1014
1015 if (ksh_isdigit(name[0]) && !name[1]) {
1016 if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
1017 if (emsgp)
1018 *emsgp = "bad file descriptor";
1019 return -1;
1020 }
1021 fl &= O_ACCMODE;
1022 /* X_OK is a kludge to disable this check for dups (x<&1):
1023 * historical shells never did this check (XXX don't know what
1024 * posix has to say).
1025 */
1026 if (!(mode & X_OK) && fl != O_RDWR &&
1027 (((mode & R_OK) && fl != O_RDONLY) ||
1028 ((mode & W_OK) && fl != O_WRONLY))) {
1029 if (emsgp)
1030 *emsgp = (fl == O_WRONLY) ?
1031 "fd not open for reading" :
1032 "fd not open for writing";
1033 return -1;
1034 }
1035 return fd;
1036 } else if (name[0] == 'p' && !name[1])
1037 return coproc_getfd(mode, emsgp);
1038 if (emsgp)
1039 *emsgp = "illegal file descriptor name";
1040 return -1;
1041 }
1042
1043 /* Called once from main */
1044 void
1045 coproc_init(void)
1046 {
1047 coproc.read = coproc.readw = coproc.write = -1;
1048 coproc.njobs = 0;
1049 coproc.id = 0;
1050 }
1051
1052 /* Called by c_read() when eof is read - close fd if it is the co-process fd */
1053 void
1054 coproc_read_close(int fd)
1055 {
1056 if (coproc.read >= 0 && fd == coproc.read) {
1057 coproc_readw_close(fd);
1058 close(coproc.read);
1059 coproc.read = -1;
1060 }
1061 }
1062
1063 /* Called by c_read() and by iosetup() to close the other side of the
1064 * read pipe, so reads will actually terminate.
1065 */
1066 void
1067 coproc_readw_close(int fd)
1068 {
1069 if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
1070 close(coproc.readw);
1071 coproc.readw = -1;
1072 }
1073 }
1074
1075 /* Called by c_print when a write to a fd fails with EPIPE and by iosetup
1076 * when co-process input is dup'd
1077 */
1078 void
1079 coproc_write_close(int fd)
1080 {
1081 if (coproc.write >= 0 && fd == coproc.write) {
1082 close(coproc.write);
1083 coproc.write = -1;
1084 }
1085 }
1086
1087 /* Called to check for existence of/value of the co-process file descriptor.
1088 * (Used by check_fd() and by c_read/c_print to deal with -p option).
1089 */
1090 int
1091 coproc_getfd(int mode, const char **emsgp)
1092 {
1093 int fd = (mode & R_OK) ? coproc.read : coproc.write;
1094
1095 if (fd >= 0)
1096 return fd;
1097 if (emsgp)
1098 *emsgp = "no coprocess";
1099 return -1;
1100 }
1101
1102 /* called to close file descriptors related to the coprocess (if any)
1103 * Should be called with SIGCHLD blocked.
1104 */
1105 void
1106 coproc_cleanup(int reuse)
1107 {
1108 /* This to allow co-processes to share output pipe */
1109 if (!reuse || coproc.readw < 0 || coproc.read < 0) {
1110 if (coproc.read >= 0) {
1111 close(coproc.read);
1112 coproc.read = -1;
1113 }
1114 if (coproc.readw >= 0) {
1115 close(coproc.readw);
1116 coproc.readw = -1;
1117 }
1118 }
1119 if (coproc.write >= 0) {
1120 close(coproc.write);
1121 coproc.write = -1;
1122 }
1123 }
1124
1125 struct temp *
1126 maketemp(Area *ap, Temp_type type, struct temp **tlist)
1127 {
1128 struct temp *tp;
1129 int len;
1130 int fd;
1131 char *pathname;
1132 const char *dir;
1133
1134 dir = tmpdir ? tmpdir : "/tmp";
1135 len = strlen(dir) + 6 + 10 + 1;
1136 tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
1137 tp->name = pathname = (char *)&tp[1];
1138 tp->shf = NULL;
1139 tp->type = type;
1140 shf_snprintf(pathname, len, "%s/mksh.XXXXXXXXXX", dir);
1141 if ((fd = mkstemp(pathname)) >= 0)
1142 tp->shf = shf_fdopen(fd, SHF_WR, NULL);
1143 tp->pid = procpid;
1144
1145 tp->next = *tlist;
1146 *tlist = tp;
1147 return tp;
1148 }
1149
1150 #define INIT_TBLS 8 /* initial table size (power of 2) */
1151
1152 static void texpand(struct table *, int);
1153 static int tnamecmp(const void *, const void *);
1154
1155 unsigned int
1156 hash(const char *n)
1157 {
1158 unsigned int h = 0;
1159
1160 while (*n != '\0')
1161 h = 2*h + *n++;
1162 return h * 32821; /* scatter bits */
1163 }
1164
1165 void
1166 ktinit(struct table *tp, Area *ap, int tsize)
1167 {
1168 tp->areap = ap;
1169 tp->tbls = NULL;
1170 tp->size = tp->nfree = 0;
1171 if (tsize)
1172 texpand(tp, tsize);
1173 }
1174
1175 static void
1176 texpand(struct table *tp, int nsize)
1177 {
1178 int i;
1179 struct tbl *tblp, **p;
1180 struct tbl **ntblp, **otblp = tp->tbls;
1181 int osize = tp->size;
1182
1183 ntblp = (struct tbl **)alloc(sizeofN(struct tbl *, nsize), tp->areap);
1184 for (i = 0; i < nsize; i++)
1185 ntblp[i] = NULL;
1186 tp->size = nsize;
1187 tp->nfree = 8 * nsize / 10; /* table can get 80% full */
1188 tp->tbls = ntblp;
1189 if (otblp == NULL)
1190 return;
1191 for (i = 0; i < osize; i++)
1192 if ((tblp = otblp[i]) != NULL) {
1193 if ((tblp->flag & DEFINED)) {
1194 for (p = &ntblp[hash(tblp->name) &
1195 (tp->size - 1)]; *p != NULL; p--)
1196 if (p == ntblp) /* wrap */
1197 p += tp->size;
1198 *p = tblp;
1199 tp->nfree--;
1200 } else if (!(tblp->flag & FINUSE)) {
1201 afree((void *)tblp, tp->areap);
1202 }
1203 }
1204 afree((void *)otblp, tp->areap);
1205 }
1206
1207 /* table */
1208 /* name to enter */
1209 /* hash(n) */
1210 struct tbl *
1211 ktsearch(struct table *tp, const char *n, unsigned int h)
1212 {
1213 struct tbl **pp, *p;
1214
1215 if (tp->size == 0)
1216 return NULL;
1217
1218 /* search for name in hashed table */
1219 for (pp = &tp->tbls[h & (tp->size - 1)]; (p = *pp) != NULL; pp--) {
1220 if (*p->name == *n && strcmp(p->name, n) == 0 &&
1221 (p->flag & DEFINED))
1222 return p;
1223 if (pp == tp->tbls) /* wrap */
1224 pp += tp->size;
1225 }
1226
1227 return NULL;
1228 }
1229
1230 /* table */
1231 /* name to enter */
1232 /* hash(n) */
1233 struct tbl *
1234 ktenter(struct table *tp, const char *n, unsigned int h)
1235 {
1236 struct tbl **pp, *p;
1237 int len;
1238
1239 if (tp->size == 0)
1240 texpand(tp, INIT_TBLS);
1241 Search:
1242 /* search for name in hashed table */
1243 for (pp = &tp->tbls[h & (tp->size - 1)]; (p = *pp) != NULL; pp--) {
1244 if (*p->name == *n && strcmp(p->name, n) == 0)
1245 return p; /* found */
1246 if (pp == tp->tbls) /* wrap */
1247 pp += tp->size;
1248 }
1249
1250 if (tp->nfree <= 0) { /* too full */
1251 texpand(tp, 2 * tp->size);
1252 goto Search;
1253 }
1254 /* create new tbl entry */
1255 len = strlen(n) + 1;
1256 p = (struct tbl *)alloc(offsetof(struct tbl, name[0])+len,
1257 tp->areap);
1258 p->flag = 0;
1259 p->type = 0;
1260 p->areap = tp->areap;
1261 p->u2.field = 0;
1262 p->u.array = NULL;
1263 memcpy(p->name, n, len);
1264
1265 /* enter in tp->tbls */
1266 tp->nfree--;
1267 *pp = p;
1268 return p;
1269 }
1270
1271 void
1272 ktdelete(struct tbl *p)
1273 {
1274 p->flag = 0;
1275 }
1276
1277 void
1278 ktwalk(struct tstate *ts, struct table *tp)
1279 {
1280 ts->left = tp->size;
1281 ts->next = tp->tbls;
1282 }
1283
1284 struct tbl *
1285 ktnext(struct tstate *ts)
1286 {
1287 while (--ts->left >= 0) {
1288 struct tbl *p = *ts->next++;
1289 if (p != NULL && (p->flag & DEFINED))
1290 return p;
1291 }
1292 return NULL;
1293 }
1294
1295 static int
1296 tnamecmp(const void *p1, const void *p2)
1297 {
1298 const struct tbl *a = *((struct tbl * const *)p1);
1299 const struct tbl *b = *((struct tbl * const *)p2);
1300
1301 return (strcmp(a->name, b->name));
1302 }
1303
1304 struct tbl **
1305 ktsort(struct table *tp)
1306 {
1307 size_t i;
1308 struct tbl **p, **sp, **dp;
1309
1310 p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size + 1), ATEMP);
1311 sp = tp->tbls; /* source */
1312 dp = p; /* dest */
1313 for (i = 0; i < (size_t)tp->size; i++)
1314 if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
1315 ((*dp)->flag & ARRAY)))
1316 dp++;
1317 qsort(p, (i = dp - p), sizeof (void *), tnamecmp);
1318 p[i] = NULL;
1319 return p;
1320 }

Properties

Name Value
cvs2svn:cvs-rev 1.1.1.2