1 /* $OpenBSD: c_ksh.c,v 1.37 2015/09/10 22:48:58 nicm Exp $ */
2 /* $OpenBSD: c_sh.c,v 1.46 2015/07/20 20:46:24 guenther Exp $ */
3 /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */
4 /* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */
5
6 /*-
7 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
8 * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
9 * mirabilos <m@mirbsd.org>
10 *
11 * Provided that these terms and disclaimer and all copyright notices
12 * are retained or reproduced in an accompanying document, permission
13 * is granted to deal in this work without restriction, including un-
14 * limited rights to use, publicly perform, distribute, sell, modify,
15 * merge, give away, or sublicence.
16 *
17 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
18 * the utmost extent permitted by applicable law, neither express nor
19 * implied; without malicious intent or gross negligence. In no event
20 * may a licensor, author or contributor be held liable for indirect,
21 * direct, other damage, loss, or other issues arising in any way out
22 * of dealing in the work, even if advised of the possibility of such
23 * damage or existence of a defect, except proven that it results out
24 * of said person's immediate fault when using the work as intended.
25 */
26
27 #include "sh.h"
28
29 #if HAVE_SELECT
30 #if HAVE_SYS_BSDTYPES_H
31 #include <sys/bsdtypes.h>
32 #endif
33 #if HAVE_SYS_SELECT_H
34 #include <sys/select.h>
35 #endif
36 #if HAVE_BSTRING_H
37 #include <bstring.h>
38 #endif
39 #endif
40
41 __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.355 2018/10/20 21:04:28 tg Exp $");
42
43 #if HAVE_KILLPG
44 /*
45 * use killpg if < -1 since -1 does special things
46 * for some non-killpg-endowed kills
47 */
48 #define mksh_kill(p,s) ((p) < -1 ? killpg(-(p), (s)) : kill((p), (s)))
49 #else
50 /* cross fingers and hope kill is killpg-endowed */
51 #define mksh_kill kill
52 #endif
53
54 /* XXX conditions correct? */
55 #if !defined(RLIM_INFINITY) && !defined(MKSH_NO_LIMITS)
56 #define MKSH_NO_LIMITS 1
57 #endif
58
59 #ifdef MKSH_NO_LIMITS
60 #define c_ulimit c_true
61 #endif
62
63 #if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
64 static int c_suspend(const char **);
65 #endif
66
67 static int do_whence(const char **, int, bool, bool);
68
69 /* getn() that prints error */
70 static int
bi_getn(const char * as,int * ai)71 bi_getn(const char *as, int *ai)
72 {
73 int rv;
74
75 if (!(rv = getn(as, ai)))
76 bi_errorf(Tf_sD_s, Tbadnum, as);
77 return (rv);
78 }
79
80 static int
c_true(const char ** wp MKSH_A_UNUSED)81 c_true(const char **wp MKSH_A_UNUSED)
82 {
83 return (0);
84 }
85
86 static int
c_false(const char ** wp MKSH_A_UNUSED)87 c_false(const char **wp MKSH_A_UNUSED)
88 {
89 return (1);
90 }
91
92 /*
93 * A leading = means assignments before command are kept.
94 * A leading * means a POSIX special builtin.
95 * A leading ^ means declaration utility, - forwarder.
96 */
97 #ifndef MKSH_LESS_BUILDINS
98 const struct builtin mkshbuiltins[] = {
99 {Tsgdot, c_dot},
100 {"*=:", c_true},
101 {Tbracket, c_test},
102 /* no =: AT&T manual wrong */
103 {Talias, c_alias},
104 {Tsgbreak, c_brkcont},
105 {T__builtin, c_builtin},
106 {Tbuiltin, c_builtin},
107 {Tbcat, c_cat},
108 {Tcd, c_cd},
109 /* dash compatibility hack */
110 {"chdir", c_cd},
111 {T_command, c_command},
112 {Tsgcontinue, c_brkcont},
113 {"echo", c_print},
114 {"*=eval", c_eval},
115 {"*=exec", c_exec},
116 {"*=exit", c_exitreturn},
117 {Tdsgexport, c_typeset},
118 {Tfalse, c_false},
119 {"fc", c_fc},
120 {Tgetopts, c_getopts},
121 /* deprecated, replaced by typeset -g */
122 {"^=global", c_typeset},
123 {Tjobs, c_jobs},
124 {"kill", c_kill},
125 {"let", c_let},
126 {"print", c_print},
127 {"pwd", c_pwd},
128 {Tread, c_read},
129 {Tdsgreadonly, c_typeset},
130 {"!realpath", c_realpath},
131 {"~rename", c_rename},
132 {"*=return", c_exitreturn},
133 {Tsgset, c_set},
134 {"*=shift", c_shift},
135 {Tgsource, c_dot},
136 #if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
137 {Tsuspend, c_suspend},
138 #endif
139 {"test", c_test},
140 {"*=times", c_times},
141 {"*=trap", c_trap},
142 {Ttrue, c_true},
143 {Tdgtypeset, c_typeset},
144 {"ulimit", c_ulimit},
145 {"umask", c_umask},
146 {Tunalias, c_unalias},
147 {"*=unset", c_unset},
148 {"wait", c_wait},
149 {"whence", c_whence},
150 #ifndef MKSH_UNEMPLOYED
151 {Tbg, c_fgbg},
152 {Tfg, c_fgbg},
153 #endif
154 #ifndef MKSH_NO_CMDLINE_EDITING
155 {"bind", c_bind},
156 #endif
157 #if HAVE_MKNOD
158 {"mknod", c_mknod},
159 #endif
160 #ifdef MKSH_PRINTF_BUILTIN
161 {"~printf", c_printf},
162 #endif
163 #if HAVE_SELECT
164 {"sleep", c_sleep},
165 #endif
166 #ifdef __MirBSD__
167 /* alias to "true" for historical reasons */
168 {"domainname", c_true},
169 #endif
170 #ifdef __OS2__
171 {Textproc, c_true},
172 #endif
173 {NULL, (int (*)(const char **))NULL}
174 };
175 #else // MKSH_LESS_BUILDINS
176 const struct builtin mkshbuiltins[] = {
177 {Tsgdot, c_dot},
178 {Talias, c_alias},
179 {Tbcat, c_cat},
180 {Tcd, c_cd},
181 {"kill", c_kill},
182 /* dash compatibility hack */
183 {"chdir", c_cd},
184 {"echo", c_print},
185 {"*=exec", c_exec},
186 {"*=exit", c_exitreturn},
187 {"pwd", c_pwd},
188 {NULL, (int (*)(const char **))NULL}
189 };
190 #endif // MKSH_LESS_BUILDINS
191
192 struct kill_info {
193 int num_width;
194 int name_width;
195 };
196
197 static const struct t_op {
198 char op_text[4];
199 Test_op op_num;
200 } u_ops[] = {
201 {"-a", TO_FILAXST },
202 {"-b", TO_FILBDEV },
203 {"-c", TO_FILCDEV },
204 {"-d", TO_FILID },
205 {"-e", TO_FILEXST },
206 {"-f", TO_FILREG },
207 {"-G", TO_FILGID },
208 {"-g", TO_FILSETG },
209 {"-H", TO_FILCDF },
210 {"-h", TO_FILSYM },
211 {"-k", TO_FILSTCK },
212 {"-L", TO_FILSYM },
213 {"-n", TO_STNZE },
214 {"-O", TO_FILUID },
215 {"-o", TO_OPTION },
216 {"-p", TO_FILFIFO },
217 {"-r", TO_FILRD },
218 {"-S", TO_FILSOCK },
219 {"-s", TO_FILGZ },
220 {"-t", TO_FILTT },
221 {"-u", TO_FILSETU },
222 {"-v", TO_ISSET },
223 {"-w", TO_FILWR },
224 {"-x", TO_FILEX },
225 {"-z", TO_STZER },
226 {"", TO_NONOP }
227 };
228 static const struct t_op b_ops[] = {
229 {"=", TO_STEQL },
230 {"==", TO_STEQL },
231 {"!=", TO_STNEQ },
232 {"<", TO_STLT },
233 {">", TO_STGT },
234 {"-eq", TO_INTEQ },
235 {"-ne", TO_INTNE },
236 {"-gt", TO_INTGT },
237 {"-ge", TO_INTGE },
238 {"-lt", TO_INTLT },
239 {"-le", TO_INTLE },
240 {"-ef", TO_FILEQ },
241 {"-nt", TO_FILNT },
242 {"-ot", TO_FILOT },
243 {"", TO_NONOP }
244 };
245
246 static int test_oexpr(Test_env *, bool);
247 static int test_aexpr(Test_env *, bool);
248 static int test_nexpr(Test_env *, bool);
249 static int test_primary(Test_env *, bool);
250 static Test_op ptest_isa(Test_env *, Test_meta);
251 static const char *ptest_getopnd(Test_env *, Test_op, bool);
252 static void ptest_error(Test_env *, int, const char *);
253 static void kill_fmt_entry(char *, size_t, unsigned int, const void *);
254 static void p_time(struct shf *, bool, long, int, int,
255 const char *, const char *);
256
257 int
c_pwd(const char ** wp)258 c_pwd(const char **wp)
259 {
260 int optc;
261 bool physical = tobool(Flag(FPHYSICAL));
262 char *p, *allocd = NULL;
263
264 while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
265 switch (optc) {
266 case 'L':
267 physical = false;
268 break;
269 case 'P':
270 physical = true;
271 break;
272 case '?':
273 return (1);
274 }
275 wp += builtin_opt.optind;
276
277 if (wp[0]) {
278 bi_errorf(Ttoo_many_args);
279 return (1);
280 }
281 p = current_wd[0] ? (physical ? allocd = do_realpath(current_wd) :
282 current_wd) : NULL;
283 /* LINTED use of access */
284 if (p && access(p, R_OK) < 0)
285 p = NULL;
286 if (!p && !(p = allocd = ksh_get_wd())) {
287 bi_errorf(Tf_sD_s, "can't determine current directory",
288 cstrerror(errno));
289 return (1);
290 }
291 shprintf(Tf_sN, p);
292 afree(allocd, ATEMP);
293 return (0);
294 }
295
296 static const char *s_ptr;
297 static int s_get(void);
298 static void s_put(int);
299
300 int
c_print(const char ** wp)301 c_print(const char **wp)
302 {
303 int c;
304 const char *s;
305 char *xp;
306 XString xs;
307 struct {
308 /* storage for columnisation */
309 XPtrV words;
310 /* temporary storage for a wide character */
311 mksh_ari_t wc;
312 /* output file descriptor (if any) */
313 int fd;
314 /* temporary storage for a multibyte character */
315 char ts[4];
316 /* output word separator */
317 char ws;
318 /* output line separator */
319 char ls;
320 /* output a trailing line separator? */
321 bool nl;
322 /* expand backslash sequences? */
323 bool exp;
324 /* columnise output? */
325 bool col;
326 /* print to history instead of file descriptor / stdout? */
327 bool hist;
328 /* print words as wide characters? */
329 bool chars;
330 /* writing to a coprocess (SIGPIPE blocked)? */
331 bool coproc;
332 bool copipe;
333 } po;
334
335 memset(&po, 0, sizeof(po));
336 po.fd = 1;
337 po.ws = ' ';
338 po.ls = '\n';
339 po.nl = true;
340
341 if (wp[0][0] == 'e') {
342 /* "echo" builtin */
343 if (Flag(FPOSIX) ||
344 #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
345 Flag(FSH) ||
346 #endif
347 Flag(FAS_BUILTIN)) {
348 /* BSD "echo" cmd, Debian Policy 10.4 compliant */
349 ++wp;
350 bsd_echo:
351 if (*wp && !strcmp(*wp, "-n")) {
352 po.nl = false;
353 ++wp;
354 }
355 po.exp = false;
356 } else {
357 bool new_exp, new_nl = true;
358
359 /*-
360 * compromise between various historic echos: only
361 * recognise -Een if they appear in arguments with
362 * no illegal options; e.g. echo -nq outputs '-nq'
363 */
364 #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
365 /* MidnightBSD /bin/sh needs -e supported but off */
366 if (Flag(FSH))
367 new_exp = false;
368 else
369 #endif
370 /* otherwise compromise on -e enabled by default */
371 new_exp = true;
372 goto print_tradparse_beg;
373
374 print_tradparse_arg:
375 if ((s = *wp) && *s++ == '-' && *s) {
376 print_tradparse_ch:
377 switch ((c = *s++)) {
378 case 'E':
379 new_exp = false;
380 goto print_tradparse_ch;
381 case 'e':
382 new_exp = true;
383 goto print_tradparse_ch;
384 case 'n':
385 new_nl = false;
386 goto print_tradparse_ch;
387 case '\0':
388 print_tradparse_beg:
389 po.exp = new_exp;
390 po.nl = new_nl;
391 ++wp;
392 goto print_tradparse_arg;
393 }
394 }
395 }
396 } else {
397 /* "print" builtin */
398 const char *opts = "AcelNnpRrsu,";
399 const char *emsg;
400
401 po.exp = true;
402
403 while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
404 switch (c) {
405 case 'A':
406 po.chars = true;
407 break;
408 case 'c':
409 po.col = true;
410 break;
411 case 'e':
412 po.exp = true;
413 break;
414 case 'l':
415 po.ws = '\n';
416 break;
417 case 'N':
418 po.ws = '\0';
419 po.ls = '\0';
420 break;
421 case 'n':
422 po.nl = false;
423 break;
424 case 'p':
425 if ((po.fd = coproc_getfd(W_OK, &emsg)) < 0) {
426 bi_errorf(Tf_coproc, emsg);
427 return (1);
428 }
429 break;
430 case 'R':
431 /* fake BSD echo but don't reset other flags */
432 wp += builtin_opt.optind;
433 goto bsd_echo;
434 case 'r':
435 po.exp = false;
436 break;
437 case 's':
438 po.hist = true;
439 break;
440 case 'u':
441 if (!*(s = builtin_opt.optarg))
442 po.fd = 0;
443 else if ((po.fd = check_fd(s, W_OK, &emsg)) < 0) {
444 bi_errorf("-u%s: %s", s, emsg);
445 return (1);
446 }
447 break;
448 case '?':
449 return (1);
450 }
451
452 if (!(builtin_opt.info & GI_MINUSMINUS)) {
453 /* treat a lone "-" like "--" */
454 if (wp[builtin_opt.optind] &&
455 ksh_isdash(wp[builtin_opt.optind]))
456 builtin_opt.optind++;
457 }
458 wp += builtin_opt.optind;
459 }
460
461 if (po.col) {
462 if (*wp == NULL)
463 return (0);
464
465 XPinit(po.words, 16);
466 }
467
468 Xinit(xs, xp, 128, ATEMP);
469
470 if (*wp == NULL)
471 goto print_no_arg;
472 print_read_arg:
473 if (po.chars) {
474 while (*wp != NULL) {
475 s = *wp++;
476 if (*s == '\0')
477 break;
478 if (!evaluate(s, &po.wc, KSH_RETURN_ERROR, true))
479 return (1);
480 Xcheck(xs, xp);
481 if (UTFMODE) {
482 po.ts[utf_wctomb(po.ts, po.wc)] = 0;
483 c = 0;
484 do {
485 Xput(xs, xp, po.ts[c]);
486 } while (po.ts[++c]);
487 } else
488 Xput(xs, xp, po.wc & 0xFF);
489 }
490 } else {
491 s = *wp++;
492 while ((c = *s++) != '\0') {
493 Xcheck(xs, xp);
494 if (po.exp && c == '\\') {
495 s_ptr = s;
496 c = unbksl(false, s_get, s_put);
497 s = s_ptr;
498 if (c == -1) {
499 /* rejected by generic function */
500 switch ((c = *s++)) {
501 case 'c':
502 po.nl = false;
503 /* AT&T brain damage */
504 continue;
505 case '\0':
506 --s;
507 c = '\\';
508 break;
509 default:
510 Xput(xs, xp, '\\');
511 }
512 } else if ((unsigned int)c > 0xFF) {
513 /* generic function returned UCS */
514 po.ts[utf_wctomb(po.ts, c - 0x100)] = 0;
515 c = 0;
516 do {
517 Xput(xs, xp, po.ts[c]);
518 } while (po.ts[++c]);
519 continue;
520 }
521 }
522 Xput(xs, xp, c);
523 }
524 }
525 if (po.col) {
526 Xput(xs, xp, '\0');
527 XPput(po.words, Xclose(xs, xp));
528 Xinit(xs, xp, 128, ATEMP);
529 }
530 if (*wp != NULL) {
531 if (!po.col)
532 Xput(xs, xp, po.ws);
533 goto print_read_arg;
534 }
535 if (po.col) {
536 size_t w = XPsize(po.words);
537 struct columnise_opts co;
538
539 XPput(po.words, NULL);
540 co.shf = shf_sopen(NULL, 128, SHF_WR | SHF_DYNAMIC, NULL);
541 co.linesep = po.ls;
542 co.prefcol = co.do_last = false;
543 pr_list(&co, (char **)XPptrv(po.words));
544 while (w--)
545 afree(XPptrv(po.words)[w], ATEMP);
546 XPfree(po.words);
547 w = co.shf->wp - co.shf->buf;
548 XcheckN(xs, xp, w);
549 memcpy(xp, co.shf->buf, w);
550 xp += w;
551 shf_sclose(co.shf);
552 }
553 print_no_arg:
554 if (po.nl)
555 Xput(xs, xp, po.ls);
556
557 c = 0;
558 if (po.hist) {
559 Xput(xs, xp, '\0');
560 histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
561 } else {
562 size_t len = Xlength(xs, xp);
563
564 /*
565 * Ensure we aren't killed by a SIGPIPE while writing to
566 * a coprocess. AT&T ksh doesn't seem to do this (seems
567 * to just check that the co-process is alive which is
568 * not enough).
569 */
570 if (coproc.write >= 0 && coproc.write == po.fd) {
571 po.coproc = true;
572 po.copipe = block_pipe();
573 } else
574 po.coproc = po.copipe = false;
575
576 s = Xstring(xs, xp);
577 while (len > 0) {
578 ssize_t nwritten;
579
580 if ((nwritten = write(po.fd, s, len)) < 0) {
581 if (errno == EINTR) {
582 if (po.copipe)
583 restore_pipe();
584 /* give the user a chance to ^C out */
585 intrcheck();
586 /* interrupted, try again */
587 if (po.coproc)
588 po.copipe = block_pipe();
589 continue;
590 }
591 c = 1;
592 break;
593 }
594 s += nwritten;
595 len -= nwritten;
596 }
597 if (po.copipe)
598 restore_pipe();
599 }
600 Xfree(xs, xp);
601
602 return (c);
603 }
604
605 static int
s_get(void)606 s_get(void)
607 {
608 return (ord(*s_ptr++));
609 }
610
611 static void
s_put(int c MKSH_A_UNUSED)612 s_put(int c MKSH_A_UNUSED)
613 {
614 --s_ptr;
615 }
616
617 int
c_whence(const char ** wp)618 c_whence(const char **wp)
619 {
620 int optc;
621 bool pflag = false, vflag = false;
622
623 while ((optc = ksh_getopt(wp, &builtin_opt, Tpv)) != -1)
624 switch (optc) {
625 case 'p':
626 pflag = true;
627 break;
628 case 'v':
629 vflag = true;
630 break;
631 case '?':
632 return (1);
633 }
634 wp += builtin_opt.optind;
635
636 return (do_whence(wp, pflag ? FC_PATH :
637 FC_BI | FC_FUNC | FC_PATH | FC_WHENCE, vflag, false));
638 }
639
640 /* note: command without -vV is dealt with in comexec() */
641 int
c_command(const char ** wp)642 c_command(const char **wp)
643 {
644 int optc, fcflags = FC_BI | FC_FUNC | FC_PATH | FC_WHENCE;
645 bool vflag = false;
646
647 while ((optc = ksh_getopt(wp, &builtin_opt, TpVv)) != -1)
648 switch (optc) {
649 case 'p':
650 fcflags |= FC_DEFPATH;
651 break;
652 case 'V':
653 vflag = true;
654 break;
655 case 'v':
656 vflag = false;
657 break;
658 case '?':
659 return (1);
660 }
661 wp += builtin_opt.optind;
662
663 return (do_whence(wp, fcflags, vflag, true));
664 }
665
666 static int
do_whence(const char ** wp,int fcflags,bool vflag,bool iscommand)667 do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
668 {
669 uint32_t h;
670 int rv = 0;
671 struct tbl *tp;
672 const char *id;
673
674 while ((vflag || rv == 0) && (id = *wp++) != NULL) {
675 h = hash(id);
676 tp = NULL;
677
678 if (fcflags & FC_WHENCE)
679 tp = ktsearch(&keywords, id, h);
680 if (!tp && (fcflags & FC_WHENCE)) {
681 tp = ktsearch(&aliases, id, h);
682 if (tp && !(tp->flag & ISSET))
683 tp = NULL;
684 }
685 if (!tp)
686 tp = findcom(id, fcflags);
687
688 switch (tp->type) {
689 case CSHELL:
690 case CFUNC:
691 case CKEYWD:
692 shf_puts(id, shl_stdout);
693 break;
694 }
695
696 switch (tp->type) {
697 case CSHELL:
698 if (vflag)
699 shprintf(" is a %sshell %s",
700 (tp->flag & SPEC_BI) ? "special " : "",
701 Tbuiltin);
702 break;
703 case CFUNC:
704 if (vflag) {
705 shf_puts(" is a", shl_stdout);
706 if (tp->flag & EXPORT)
707 shf_puts("n exported", shl_stdout);
708 if (tp->flag & TRACE)
709 shf_puts(" traced", shl_stdout);
710 if (!(tp->flag & ISSET)) {
711 shf_puts(" undefined", shl_stdout);
712 if (tp->u.fpath)
713 shprintf(" (autoload from %s)",
714 tp->u.fpath);
715 }
716 shf_puts(T_function, shl_stdout);
717 }
718 break;
719 case CEXEC:
720 case CTALIAS:
721 if (tp->flag & ISSET) {
722 if (vflag) {
723 shprintf("%s is ", id);
724 if (tp->type == CTALIAS)
725 shprintf("a tracked %s%s for ",
726 (tp->flag & EXPORT) ?
727 "exported " : "",
728 Talias);
729 }
730 shf_puts(tp->val.s, shl_stdout);
731 } else {
732 if (vflag)
733 shprintf(Tnot_found_s, id);
734 rv = 1;
735 }
736 break;
737 case CALIAS:
738 if (vflag) {
739 shprintf("%s is an %s%s for ", id,
740 (tp->flag & EXPORT) ? "exported " : "",
741 Talias);
742 } else if (iscommand)
743 shprintf("%s %s=", Talias, id);
744 print_value_quoted(shl_stdout, tp->val.s);
745 break;
746 case CKEYWD:
747 if (vflag)
748 shf_puts(" is a reserved word", shl_stdout);
749 break;
750 #ifndef MKSH_SMALL
751 default:
752 bi_errorf(Tunexpected_type, id, Tcommand, tp->type);
753 return (1);
754 #endif
755 }
756 if (vflag || !rv)
757 shf_putc('\n', shl_stdout);
758 }
759 return (rv);
760 }
761
762 bool
valid_alias_name(const char * cp)763 valid_alias_name(const char *cp)
764 {
765 if (ord(*cp) == ORD('-'))
766 return (false);
767 if (ord(cp[0]) == ORD('[') && ord(cp[1]) == ORD('[') && !cp[2])
768 return (false);
769 while (*cp)
770 if (ctype(*cp, C_ALIAS))
771 ++cp;
772 else
773 return (false);
774 return (true);
775 }
776
777 int
c_alias(const char ** wp)778 c_alias(const char **wp)
779 {
780 struct table *t = &aliases;
781 int rv = 0, prefix = 0;
782 bool rflag = false, tflag, Uflag = false, pflag = false, chkalias;
783 uint32_t xflag = 0;
784 int optc;
785
786 builtin_opt.flags |= GF_PLUSOPT;
787 while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != -1) {
788 prefix = builtin_opt.info & GI_PLUS ? '+' : '-';
789 switch (optc) {
790 case 'd':
791 #ifdef MKSH_NOPWNAM
792 t = NULL; /* fix "alias -dt" */
793 #else
794 t = &homedirs;
795 #endif
796 break;
797 case 'p':
798 pflag = true;
799 break;
800 case 'r':
801 rflag = true;
802 break;
803 case 't':
804 t = &taliases;
805 break;
806 case 'U':
807 /*
808 * kludge for tracked alias initialization
809 * (don't do a path search, just make an entry)
810 */
811 Uflag = true;
812 break;
813 case 'x':
814 xflag = EXPORT;
815 break;
816 case '?':
817 return (1);
818 }
819 }
820 #ifdef MKSH_NOPWNAM
821 if (t == NULL)
822 return (0);
823 #endif
824 wp += builtin_opt.optind;
825
826 if (!(builtin_opt.info & GI_MINUSMINUS) && *wp &&
827 ctype(wp[0][0], C_MINUS | C_PLUS) && wp[0][1] == '\0') {
828 prefix = wp[0][0];
829 wp++;
830 }
831
832 tflag = t == &taliases;
833 chkalias = t == &aliases;
834
835 /* "hash -r" means reset all the tracked aliases.. */
836 if (rflag) {
837 static const char *args[] = {
838 Tunalias, "-ta", NULL
839 };
840
841 if (!tflag || *wp) {
842 shprintf("%s: -r flag can only be used with -t"
843 " and without arguments\n", Talias);
844 return (1);
845 }
846 ksh_getopt_reset(&builtin_opt, GF_ERROR);
847 return (c_unalias(args));
848 }
849
850 if (*wp == NULL) {
851 struct tbl *ap, **p;
852
853 for (p = ktsort(t); (ap = *p++) != NULL; )
854 if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) {
855 if (pflag)
856 shprintf(Tf_s_, Talias);
857 shf_puts(ap->name, shl_stdout);
858 if (prefix != '+') {
859 shf_putc('=', shl_stdout);
860 print_value_quoted(shl_stdout, ap->val.s);
861 }
862 shf_putc('\n', shl_stdout);
863 }
864 }
865
866 for (; *wp != NULL; wp++) {
867 const char *alias = *wp, *val, *newval;
868 char *xalias = NULL;
869 struct tbl *ap;
870 uint32_t h;
871
872 if ((val = cstrchr(alias, '='))) {
873 strndupx(xalias, alias, val++ - alias, ATEMP);
874 alias = xalias;
875 }
876 if (chkalias && !valid_alias_name(alias)) {
877 bi_errorf(Tinvname, alias, Talias);
878 afree(xalias, ATEMP);
879 return (1);
880 }
881 h = hash(alias);
882 if (val == NULL && !tflag && !xflag) {
883 ap = ktsearch(t, alias, h);
884 if (ap != NULL && (ap->flag&ISSET)) {
885 if (pflag)
886 shprintf(Tf_s_, Talias);
887 shf_puts(ap->name, shl_stdout);
888 if (prefix != '+') {
889 shf_putc('=', shl_stdout);
890 print_value_quoted(shl_stdout, ap->val.s);
891 }
892 shf_putc('\n', shl_stdout);
893 } else {
894 shprintf(Tf_s_s_sN, alias, Talias, Tnot_found);
895 rv = 1;
896 }
897 continue;
898 }
899 ap = ktenter(t, alias, h);
900 ap->type = tflag ? CTALIAS : CALIAS;
901 /* Are we setting the value or just some flags? */
902 if ((val && !tflag) || (!val && tflag && !Uflag)) {
903 if (ap->flag&ALLOC) {
904 ap->flag &= ~(ALLOC|ISSET);
905 afree(ap->val.s, APERM);
906 }
907 /* ignore values for -t (AT&T ksh does this) */
908 newval = tflag ?
909 search_path(alias, path, X_OK, NULL) :
910 val;
911 if (newval) {
912 strdupx(ap->val.s, newval, APERM);
913 ap->flag |= ALLOC|ISSET;
914 } else
915 ap->flag &= ~ISSET;
916 }
917 ap->flag |= DEFINED;
918 if (prefix == '+')
919 ap->flag &= ~xflag;
920 else
921 ap->flag |= xflag;
922 afree(xalias, ATEMP);
923 }
924
925 return (rv);
926 }
927
928 int
c_unalias(const char ** wp)929 c_unalias(const char **wp)
930 {
931 struct table *t = &aliases;
932 struct tbl *ap;
933 int optc, rv = 0;
934 bool all = false;
935
936 while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != -1)
937 switch (optc) {
938 case 'a':
939 all = true;
940 break;
941 case 'd':
942 #ifdef MKSH_NOPWNAM
943 /* fix "unalias -dt" */
944 t = NULL;
945 #else
946 t = &homedirs;
947 #endif
948 break;
949 case 't':
950 t = &taliases;
951 break;
952 case '?':
953 return (1);
954 }
955 #ifdef MKSH_NOPWNAM
956 if (t == NULL)
957 return (0);
958 #endif
959 wp += builtin_opt.optind;
960
961 for (; *wp != NULL; wp++) {
962 ap = ktsearch(t, *wp, hash(*wp));
963 if (ap == NULL) {
964 /* POSIX */
965 rv = 1;
966 continue;
967 }
968 if (ap->flag&ALLOC) {
969 ap->flag &= ~(ALLOC|ISSET);
970 afree(ap->val.s, APERM);
971 }
972 ap->flag &= ~(DEFINED|ISSET|EXPORT);
973 }
974
975 if (all) {
976 struct tstate ts;
977
978 for (ktwalk(&ts, t); (ap = ktnext(&ts)); ) {
979 if (ap->flag&ALLOC) {
980 ap->flag &= ~(ALLOC|ISSET);
981 afree(ap->val.s, APERM);
982 }
983 ap->flag &= ~(DEFINED|ISSET|EXPORT);
984 }
985 }
986
987 return (rv);
988 }
989
990 int
c_let(const char ** wp)991 c_let(const char **wp)
992 {
993 int rv = 1;
994 mksh_ari_t val;
995
996 if (wp[1] == NULL)
997 /* AT&T ksh does this */
998 bi_errorf(Tno_args);
999 else
1000 for (wp++; *wp; wp++)
1001 if (!evaluate(*wp, &val, KSH_RETURN_ERROR, true)) {
1002 /* distinguish error from zero result */
1003 rv = 2;
1004 break;
1005 } else
1006 rv = val == 0;
1007 return (rv);
1008 }
1009
1010 int
c_jobs(const char ** wp)1011 c_jobs(const char **wp)
1012 {
1013 int optc, flag = 0, nflag = 0, rv = 0;
1014
1015 while ((optc = ksh_getopt(wp, &builtin_opt, "lpnz")) != -1)
1016 switch (optc) {
1017 case 'l':
1018 flag = 1;
1019 break;
1020 case 'p':
1021 flag = 2;
1022 break;
1023 case 'n':
1024 nflag = 1;
1025 break;
1026 case 'z':
1027 /* debugging: print zombies */
1028 nflag = -1;
1029 break;
1030 case '?':
1031 return (1);
1032 }
1033 wp += builtin_opt.optind;
1034 if (!*wp) {
1035 if (j_jobs(NULL, flag, nflag))
1036 rv = 1;
1037 } else {
1038 for (; *wp; wp++)
1039 if (j_jobs(*wp, flag, nflag))
1040 rv = 1;
1041 }
1042 return (rv);
1043 }
1044
1045 #ifndef MKSH_UNEMPLOYED
1046 int
c_fgbg(const char ** wp)1047 c_fgbg(const char **wp)
1048 {
1049 bool bg = strcmp(*wp, Tbg) == 0;
1050 int rv = 0;
1051
1052 if (!Flag(FMONITOR)) {
1053 bi_errorf("job control not enabled");
1054 return (1);
1055 }
1056 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1057 return (1);
1058 wp += builtin_opt.optind;
1059 if (*wp)
1060 for (; *wp; wp++)
1061 rv = j_resume(*wp, bg);
1062 else
1063 rv = j_resume("%%", bg);
1064 /* fg returns $? of the job unless POSIX */
1065 return ((bg | Flag(FPOSIX)) ? 0 : rv);
1066 }
1067 #endif
1068
1069 /* format a single kill item */
1070 static void
kill_fmt_entry(char * buf,size_t buflen,unsigned int i,const void * arg)1071 kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
1072 {
1073 const struct kill_info *ki = (const struct kill_info *)arg;
1074
1075 i++;
1076 shf_snprintf(buf, buflen, "%*u %*s %s",
1077 ki->num_width, i,
1078 ki->name_width, sigtraps[i].name,
1079 sigtraps[i].mess);
1080 }
1081
1082 int
c_kill(const char ** wp)1083 c_kill(const char **wp)
1084 {
1085 Trap *t = NULL;
1086 const char *p;
1087 bool lflag = false;
1088 int i, n, rv, sig;
1089
1090 /* assume old style options if -digits or -UPPERCASE */
1091 if ((p = wp[1]) && *p == '-' && ctype(p[1], C_DIGIT | C_UPPER)) {
1092 if (!(t = gettrap(p + 1, false, false))) {
1093 bi_errorf(Tbad_sig_s, p + 1);
1094 return (1);
1095 }
1096 i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2;
1097 } else {
1098 int optc;
1099
1100 while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != -1)
1101 switch (optc) {
1102 case 'l':
1103 lflag = true;
1104 break;
1105 case 's':
1106 if (!(t = gettrap(builtin_opt.optarg,
1107 true, false))) {
1108 bi_errorf(Tbad_sig_s,
1109 builtin_opt.optarg);
1110 return (1);
1111 }
1112 break;
1113 case '?':
1114 return (1);
1115 }
1116 i = builtin_opt.optind;
1117 }
1118 if ((lflag && t) || (!wp[i] && !lflag)) {
1119 #ifndef MKSH_SMALL
1120 shf_puts("usage:\tkill [-s signame | -signum | -signame]"
1121 " { job | pid | pgrp } ...\n"
1122 "\tkill -l [exit_status ...]\n", shl_out);
1123 #endif
1124 bi_errorfz();
1125 return (1);
1126 }
1127
1128 if (lflag) {
1129 if (wp[i]) {
1130 for (; wp[i]; i++) {
1131 if (!bi_getn(wp[i], &n))
1132 return (1);
1133 #if (ksh_NSIG <= 128)
1134 if (n > 128 && n < 128 + ksh_NSIG)
1135 n -= 128;
1136 #endif
1137 if (n > 0 && n < ksh_NSIG)
1138 shprintf(Tf_sN, sigtraps[n].name);
1139 else
1140 shprintf(Tf_dN, n);
1141 }
1142 } else if (Flag(FPOSIX)) {
1143 n = 1;
1144 while (n < ksh_NSIG) {
1145 shf_puts(sigtraps[n].name, shl_stdout);
1146 shf_putc(++n == ksh_NSIG ? '\n' : ' ',
1147 shl_stdout);
1148 }
1149 } else {
1150 ssize_t w, mess_cols = 0, mess_octs = 0;
1151 int j = ksh_NSIG - 1;
1152 struct kill_info ki = { 0, 0 };
1153 struct columnise_opts co;
1154
1155 do {
1156 ki.num_width++;
1157 } while ((j /= 10));
1158
1159 for (j = 1; j < ksh_NSIG; j++) {
1160 w = strlen(sigtraps[j].name);
1161 if (w > ki.name_width)
1162 ki.name_width = w;
1163 w = strlen(sigtraps[j].mess);
1164 if (w > mess_octs)
1165 mess_octs = w;
1166 w = utf_mbswidth(sigtraps[j].mess);
1167 if (w > mess_cols)
1168 mess_cols = w;
1169 }
1170
1171 co.shf = shl_stdout;
1172 co.linesep = '\n';
1173 co.prefcol = co.do_last = true;
1174
1175 print_columns(&co, (unsigned int)(ksh_NSIG - 1),
1176 kill_fmt_entry, (void *)&ki,
1177 ki.num_width + 1 + ki.name_width + 1 + mess_octs,
1178 ki.num_width + 1 + ki.name_width + 1 + mess_cols);
1179 }
1180 return (0);
1181 }
1182 rv = 0;
1183 sig = t ? t->signal : SIGTERM;
1184 for (; (p = wp[i]); i++) {
1185 if (*p == '%') {
1186 if (j_kill(p, sig))
1187 rv = 1;
1188 } else if (!getn(p, &n)) {
1189 bi_errorf(Tf_sD_s, p,
1190 "arguments must be jobs or process IDs");
1191 rv = 1;
1192 } else {
1193 if (mksh_kill(n, sig) < 0) {
1194 bi_errorf(Tf_sD_s, p, cstrerror(errno));
1195 rv = 1;
1196 }
1197 }
1198 }
1199 return (rv);
1200 }
1201
1202 void
getopts_reset(int val)1203 getopts_reset(int val)
1204 {
1205 if (val >= 1) {
1206 ksh_getopt_reset(&user_opt, GF_NONAME |
1207 (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
1208 user_opt.optind = user_opt.uoptind = val;
1209 }
1210 }
1211
1212 int
c_getopts(const char ** wp)1213 c_getopts(const char **wp)
1214 {
1215 int argc, optc, rv;
1216 const char *opts, *var;
1217 char buf[3];
1218 struct tbl *vq, *voptarg;
1219
1220 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1221 return (1);
1222 wp += builtin_opt.optind;
1223
1224 opts = *wp++;
1225 if (!opts) {
1226 bi_errorf(Tf_sD_s, "options", Tno_args);
1227 return (1);
1228 }
1229
1230 var = *wp++;
1231 if (!var) {
1232 bi_errorf(Tf_sD_s, Tname, Tno_args);
1233 return (1);
1234 }
1235 if (!*var || *skip_varname(var, true)) {
1236 bi_errorf(Tf_sD_s, var, Tnot_ident);
1237 return (1);
1238 }
1239
1240 if (e->loc->next == NULL) {
1241 internal_warningf(Tf_sD_s, Tgetopts, Tno_args);
1242 return (1);
1243 }
1244 /* Which arguments are we parsing... */
1245 if (*wp == NULL)
1246 wp = e->loc->next->argv;
1247 else
1248 *--wp = e->loc->next->argv[0];
1249
1250 /* Check that our saved state won't cause a core dump... */
1251 for (argc = 0; wp[argc]; argc++)
1252 ;
1253 if (user_opt.optind > argc ||
1254 (user_opt.p != 0 &&
1255 user_opt.p > strlen(wp[user_opt.optind - 1]))) {
1256 bi_errorf("arguments changed since last call");
1257 return (1);
1258 }
1259
1260 user_opt.optarg = NULL;
1261 optc = ksh_getopt(wp, &user_opt, opts);
1262
1263 if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) {
1264 buf[0] = '+';
1265 buf[1] = optc;
1266 buf[2] = '\0';
1267 } else {
1268 /*
1269 * POSIX says var is set to ? at end-of-options, AT&T ksh
1270 * sets it to null - we go with POSIX...
1271 */
1272 buf[0] = optc < 0 ? '?' : optc;
1273 buf[1] = '\0';
1274 }
1275
1276 /* AT&T ksh93 in fact does change OPTIND for unknown options too */
1277 user_opt.uoptind = user_opt.optind;
1278
1279 voptarg = global("OPTARG");
1280 /* AT&T ksh clears ro and int */
1281 voptarg->flag &= ~RDONLY;
1282 /* Paranoia: ensure no bizarre results. */
1283 if (voptarg->flag & INTEGER)
1284 typeset("OPTARG", 0, INTEGER, 0, 0);
1285 if (user_opt.optarg == NULL)
1286 unset(voptarg, 1);
1287 else
1288 /* this can't fail (haing cleared readonly/integer) */
1289 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
1290
1291 rv = 0;
1292
1293 vq = global(var);
1294 /* Error message already printed (integer, readonly) */
1295 if (!setstr(vq, buf, KSH_RETURN_ERROR))
1296 rv = 2;
1297 if (Flag(FEXPORT))
1298 typeset(var, EXPORT, 0, 0, 0);
1299
1300 return (optc < 0 ? 1 : rv);
1301 }
1302
1303 #ifndef MKSH_NO_CMDLINE_EDITING
1304 int
c_bind(const char ** wp)1305 c_bind(const char **wp)
1306 {
1307 int optc, rv = 0;
1308 #ifndef MKSH_SMALL
1309 bool macro = false;
1310 #endif
1311 bool list = false;
1312 const char *cp;
1313 char *up;
1314
1315 while ((optc = ksh_getopt(wp, &builtin_opt,
1316 #ifndef MKSH_SMALL
1317 "lm"
1318 #else
1319 "l"
1320 #endif
1321 )) != -1)
1322 switch (optc) {
1323 case 'l':
1324 list = true;
1325 break;
1326 #ifndef MKSH_SMALL
1327 case 'm':
1328 macro = true;
1329 break;
1330 #endif
1331 case '?':
1332 return (1);
1333 }
1334 wp += builtin_opt.optind;
1335
1336 if (*wp == NULL)
1337 /* list all */
1338 rv = x_bind(NULL, NULL,
1339 #ifndef MKSH_SMALL
1340 false,
1341 #endif
1342 list);
1343
1344 for (; *wp != NULL; wp++) {
1345 if ((cp = cstrchr(*wp, '=')) == NULL)
1346 up = NULL;
1347 else {
1348 strdupx(up, *wp, ATEMP);
1349 up[cp++ - *wp] = '\0';
1350 }
1351 if (x_bind(up ? up : *wp, cp,
1352 #ifndef MKSH_SMALL
1353 macro,
1354 #endif
1355 false))
1356 rv = 1;
1357 afree(up, ATEMP);
1358 }
1359
1360 return (rv);
1361 }
1362 #endif
1363
1364 int
c_shift(const char ** wp)1365 c_shift(const char **wp)
1366 {
1367 struct block *l = e->loc;
1368 int n;
1369 mksh_ari_t val;
1370 const char *arg;
1371
1372 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1373 return (1);
1374 arg = wp[builtin_opt.optind];
1375
1376 if (!arg)
1377 n = 1;
1378 else if (!evaluate(arg, &val, KSH_RETURN_ERROR, false)) {
1379 /* error already printed */
1380 bi_errorfz();
1381 return (1);
1382 } else if (!(n = val)) {
1383 /* nothing to do */
1384 return (0);
1385 } else if (n < 0) {
1386 bi_errorf(Tf_sD_s, Tbadnum, arg);
1387 return (1);
1388 }
1389 if (l->argc < n) {
1390 bi_errorf("nothing to shift");
1391 return (1);
1392 }
1393 l->argv[n] = l->argv[0];
1394 l->argv += n;
1395 l->argc -= n;
1396 return (0);
1397 }
1398
1399 int
c_umask(const char ** wp)1400 c_umask(const char **wp)
1401 {
1402 int i, optc;
1403 const char *cp;
1404 bool symbolic = false;
1405 mode_t old_umask;
1406
1407 while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1)
1408 switch (optc) {
1409 case 'S':
1410 symbolic = true;
1411 break;
1412 case '?':
1413 return (1);
1414 }
1415 cp = wp[builtin_opt.optind];
1416 if (cp == NULL) {
1417 old_umask = umask((mode_t)0);
1418 umask(old_umask);
1419 if (symbolic) {
1420 char buf[18], *p;
1421 int j;
1422
1423 old_umask = ~old_umask;
1424 p = buf;
1425 for (i = 0; i < 3; i++) {
1426 *p++ = Tugo[i];
1427 *p++ = '=';
1428 for (j = 0; j < 3; j++)
1429 if (old_umask & (1 << (8 - (3*i + j))))
1430 *p++ = "rwx"[j];
1431 *p++ = ',';
1432 }
1433 p[-1] = '\0';
1434 shprintf(Tf_sN, buf);
1435 } else
1436 shprintf("%#3.3o\n", (unsigned int)old_umask);
1437 } else {
1438 mode_t new_umask;
1439
1440 if (ctype(*cp, C_DIGIT)) {
1441 new_umask = 0;
1442 while (ctype(*cp, C_OCTAL)) {
1443 new_umask = new_umask * 8 + ksh_numdig(*cp);
1444 ++cp;
1445 }
1446 if (*cp) {
1447 bi_errorf(Tbadnum);
1448 return (1);
1449 }
1450 } else {
1451 /* symbolic format */
1452 int positions, new_val;
1453 char op;
1454
1455 old_umask = umask((mode_t)0);
1456 /* in case of error */
1457 umask(old_umask);
1458 old_umask = ~old_umask;
1459 new_umask = old_umask;
1460 positions = 0;
1461 while (*cp) {
1462 while (*cp && vstrchr(Taugo, *cp))
1463 switch (*cp++) {
1464 case 'a':
1465 positions |= 0111;
1466 break;
1467 case 'u':
1468 positions |= 0100;
1469 break;
1470 case 'g':
1471 positions |= 0010;
1472 break;
1473 case 'o':
1474 positions |= 0001;
1475 break;
1476 }
1477 if (!positions)
1478 /* default is a */
1479 positions = 0111;
1480 if (!ctype((op = *cp), C_EQUAL | C_MINUS | C_PLUS))
1481 break;
1482 cp++;
1483 new_val = 0;
1484 while (*cp && vstrchr("rwxugoXs", *cp))
1485 switch (*cp++) {
1486 case 'r': new_val |= 04; break;
1487 case 'w': new_val |= 02; break;
1488 case 'x': new_val |= 01; break;
1489 case 'u':
1490 new_val |= old_umask >> 6;
1491 break;
1492 case 'g':
1493 new_val |= old_umask >> 3;
1494 break;
1495 case 'o':
1496 new_val |= old_umask >> 0;
1497 break;
1498 case 'X':
1499 if (old_umask & 0111)
1500 new_val |= 01;
1501 break;
1502 case 's':
1503 /* ignored */
1504 break;
1505 }
1506 new_val = (new_val & 07) * positions;
1507 switch (op) {
1508 case '-':
1509 new_umask &= ~new_val;
1510 break;
1511 case '=':
1512 new_umask = new_val |
1513 (new_umask & ~(positions * 07));
1514 break;
1515 case '+':
1516 new_umask |= new_val;
1517 }
1518 if (*cp == ',') {
1519 positions = 0;
1520 cp++;
1521 } else if (!ctype(*cp, C_EQUAL | C_MINUS | C_PLUS))
1522 break;
1523 }
1524 if (*cp) {
1525 bi_errorf("bad mask");
1526 return (1);
1527 }
1528 new_umask = ~new_umask;
1529 }
1530 umask(new_umask);
1531 }
1532 return (0);
1533 }
1534
1535 int
c_dot(const char ** wp)1536 c_dot(const char **wp)
1537 {
1538 const char *file, *cp, **argv;
1539 int argc, rv, errcode;
1540
1541 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1542 return (1);
1543
1544 if ((cp = wp[builtin_opt.optind]) == NULL) {
1545 bi_errorf(Tno_args);
1546 return (1);
1547 }
1548 file = search_path(cp, path, R_OK, &errcode);
1549 if (!file && errcode == ENOENT && wp[0][0] == 's' &&
1550 search_access(cp, R_OK) == 0)
1551 file = cp;
1552 if (!file) {
1553 bi_errorf(Tf_sD_s, cp, cstrerror(errcode));
1554 return (1);
1555 }
1556
1557 /* Set positional parameters? */
1558 if (wp[builtin_opt.optind + 1]) {
1559 argv = wp + builtin_opt.optind;
1560 /* preserve $0 */
1561 argv[0] = e->loc->argv[0];
1562 for (argc = 0; argv[argc + 1]; argc++)
1563 ;
1564 } else {
1565 argc = 0;
1566 argv = NULL;
1567 }
1568 /* SUSv4: OR with a high value never written otherwise */
1569 exstat |= 0x4000;
1570 if ((rv = include(file, argc, argv, false)) < 0) {
1571 /* should not happen */
1572 bi_errorf(Tf_sD_s, cp, cstrerror(errno));
1573 return (1);
1574 }
1575 if (exstat & 0x4000)
1576 /* detect old exstat, use 0 in that case */
1577 rv = 0;
1578 return (rv);
1579 }
1580
1581 int
c_wait(const char ** wp)1582 c_wait(const char **wp)
1583 {
1584 int rv = 0, sig;
1585
1586 if (ksh_getopt(wp, &builtin_opt, null) == '?')
1587 return (1);
1588 wp += builtin_opt.optind;
1589 if (*wp == NULL) {
1590 while (waitfor(NULL, &sig) >= 0)
1591 ;
1592 rv = sig;
1593 } else {
1594 for (; *wp; wp++)
1595 rv = waitfor(*wp, &sig);
1596 if (rv < 0)
1597 /* magic exit code: bad job-id */
1598 rv = sig ? sig : 127;
1599 }
1600 return (rv);
1601 }
1602
1603 static const char REPLY[] = "REPLY";
1604 int
c_read(const char ** wp)1605 c_read(const char **wp)
1606 {
1607 #define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
1608 int c, fd = 0, rv = 0;
1609 bool savehist = false, intoarray = false, aschars = false;
1610 bool rawmode = false, expanding = false;
1611 bool lastparmmode = false, lastparmused = false;
1612 enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
1613 char delim = '\n';
1614 size_t bytesleft = 128, bytesread;
1615 struct tbl *vp /* FU gcc */ = NULL, *vq = NULL;
1616 char *cp, *allocd = NULL, *xp;
1617 const char *ccp;
1618 XString xs;
1619 size_t xsave = 0;
1620 mksh_ttyst tios;
1621 bool restore_tios = false;
1622 /* to catch read -aN2 foo[i] */
1623 bool subarray = false;
1624 #if HAVE_SELECT
1625 bool hastimeout = false;
1626 struct timeval tv, tvlim;
1627 #define c_read_opts "Aad:N:n:prst:u,"
1628 #else
1629 #define c_read_opts "Aad:N:n:prsu,"
1630 #endif
1631 #if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1632 int saved_mode;
1633 int saved_errno;
1634 #endif
1635
1636 while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
1637 switch (c) {
1638 case 'a':
1639 aschars = true;
1640 /* FALLTHROUGH */
1641 case 'A':
1642 intoarray = true;
1643 break;
1644 case 'd':
1645 delim = builtin_opt.optarg[0];
1646 break;
1647 case 'N':
1648 case 'n':
1649 readmode = c == 'N' ? BYTES : UPTO;
1650 if (!bi_getn(builtin_opt.optarg, &c))
1651 return (2);
1652 if (c == -1) {
1653 readmode = readmode == BYTES ? READALL : UPTO;
1654 bytesleft = 1024;
1655 } else
1656 bytesleft = (unsigned int)c;
1657 break;
1658 case 'p':
1659 if ((fd = coproc_getfd(R_OK, &ccp)) < 0) {
1660 bi_errorf(Tf_coproc, ccp);
1661 return (2);
1662 }
1663 break;
1664 case 'r':
1665 rawmode = true;
1666 break;
1667 case 's':
1668 savehist = true;
1669 break;
1670 #if HAVE_SELECT
1671 case 't':
1672 if (parse_usec(builtin_opt.optarg, &tv)) {
1673 bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno),
1674 builtin_opt.optarg);
1675 return (2);
1676 }
1677 hastimeout = true;
1678 break;
1679 #endif
1680 case 'u':
1681 if (!builtin_opt.optarg[0])
1682 fd = 0;
1683 else if ((fd = check_fd(builtin_opt.optarg, R_OK, &ccp)) < 0) {
1684 bi_errorf(Tf_sD_sD_s, "-u", builtin_opt.optarg, ccp);
1685 return (2);
1686 }
1687 break;
1688 case '?':
1689 return (2);
1690 }
1691 wp += builtin_opt.optind;
1692 if (*wp == NULL)
1693 *--wp = REPLY;
1694
1695 if (intoarray && wp[1] != NULL) {
1696 bi_errorf(Ttoo_many_args);
1697 return (2);
1698 }
1699
1700 if ((ccp = cstrchr(*wp, '?')) != NULL) {
1701 strdupx(allocd, *wp, ATEMP);
1702 allocd[ccp - *wp] = '\0';
1703 *wp = allocd;
1704 if (isatty(fd)) {
1705 /*
1706 * AT&T ksh says it prints prompt on fd if it's open
1707 * for writing and is a tty, but it doesn't do it
1708 * (it also doesn't check the interactive flag,
1709 * as is indicated in the Korn Shell book).
1710 */
1711 shf_puts(ccp + 1, shl_out);
1712 shf_flush(shl_out);
1713 }
1714 }
1715
1716 Xinit(xs, xp, bytesleft, ATEMP);
1717
1718 if (readmode == LINES)
1719 bytesleft = 1;
1720 else if (isatty(fd)) {
1721 x_mkraw(fd, &tios, true);
1722 restore_tios = true;
1723 }
1724
1725 #if HAVE_SELECT
1726 if (hastimeout) {
1727 mksh_TIME(tvlim);
1728 timeradd(&tvlim, &tv, &tvlim);
1729 }
1730 #endif
1731
1732 c_read_readloop:
1733 #if HAVE_SELECT
1734 if (hastimeout) {
1735 fd_set fdset;
1736
1737 FD_ZERO(&fdset);
1738 FD_SET((unsigned int)fd, &fdset);
1739 mksh_TIME(tv);
1740 timersub(&tvlim, &tv, &tv);
1741 if (tv.tv_sec < 0) {
1742 /* timeout expired globally */
1743 rv = 3;
1744 goto c_read_out;
1745 }
1746
1747 switch (select(fd + 1, &fdset, NULL, NULL, &tv)) {
1748 case 1:
1749 break;
1750 case 0:
1751 /* timeout expired for this call */
1752 bytesread = 0;
1753 rv = 3;
1754 goto c_read_readdone;
1755 default:
1756 bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
1757 rv = 2;
1758 goto c_read_out;
1759 }
1760 }
1761 #endif
1762
1763 #if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1764 saved_mode = setmode(fd, O_TEXT);
1765 #endif
1766 if ((bytesread = blocking_read(fd, xp, bytesleft)) == (size_t)-1) {
1767 #if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1768 saved_errno = errno;
1769 setmode(fd, saved_mode);
1770 errno = saved_errno;
1771 #endif
1772 if (errno == EINTR) {
1773 /* check whether the signal would normally kill */
1774 if (!fatal_trap_check()) {
1775 /* no, just ignore the signal */
1776 goto c_read_readloop;
1777 }
1778 /* pretend the read was killed */
1779 } else {
1780 /* unexpected error */
1781 bi_errorf(Tf_s, cstrerror(errno));
1782 }
1783 rv = 2;
1784 goto c_read_out;
1785 }
1786 #if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1787 setmode(fd, saved_mode);
1788 #endif
1789
1790 switch (readmode) {
1791 case READALL:
1792 if (bytesread == 0) {
1793 /* end of file reached */
1794 rv = 1;
1795 goto c_read_readdone;
1796 }
1797 xp += bytesread;
1798 XcheckN(xs, xp, bytesleft);
1799 break;
1800
1801 case UPTO:
1802 if (bytesread == 0)
1803 /* end of file reached */
1804 rv = 1;
1805 xp += bytesread;
1806 goto c_read_readdone;
1807
1808 case BYTES:
1809 if (bytesread == 0) {
1810 /* end of file reached */
1811 rv = 1;
1812 /* may be partial read: $? = 1, but content */
1813 goto c_read_readdone;
1814 }
1815 xp += bytesread;
1816 if ((bytesleft -= bytesread) == 0)
1817 goto c_read_readdone;
1818 break;
1819 case LINES:
1820 if (bytesread == 0) {
1821 /* end of file reached */
1822 rv = 1;
1823 goto c_read_readdone;
1824 }
1825 if ((c = *xp) == '\0' && !aschars && delim != '\0') {
1826 /* skip any read NULs unless delimiter */
1827 break;
1828 }
1829 if (expanding) {
1830 expanding = false;
1831 if (c == delim) {
1832 if (Flag(FTALKING_I) && isatty(fd)) {
1833 /*
1834 * set prompt in case this is
1835 * called from .profile or $ENV
1836 */
1837 set_prompt(PS2, NULL);
1838 pprompt(prompt, 0);
1839 }
1840 /* drop the backslash */
1841 --xp;
1842 /* and the delimiter */
1843 break;
1844 }
1845 } else if (c == delim) {
1846 goto c_read_readdone;
1847 } else if (!rawmode && c == '\\') {
1848 expanding = true;
1849 }
1850 Xcheck(xs, xp);
1851 ++xp;
1852 break;
1853 }
1854 goto c_read_readloop;
1855
1856 c_read_readdone:
1857 bytesread = Xlength(xs, xp);
1858 Xput(xs, xp, '\0');
1859
1860 /*-
1861 * state: we finished reading the input and NUL terminated it
1862 * Xstring(xs, xp) -> xp-1 = input string without trailing delim
1863 * rv = 3 if timeout, 1 if EOF, 0 otherwise (errors handled already)
1864 */
1865
1866 if (rv) {
1867 /* clean up coprocess if needed, on EOF/error/timeout */
1868 coproc_read_close(fd);
1869 if (readmode == READALL && (rv == 1 || (rv == 3 && bytesread)))
1870 /* EOF is no error here */
1871 rv = 0;
1872 }
1873
1874 if (savehist)
1875 histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
1876
1877 ccp = cp = Xclose(xs, xp);
1878 expanding = false;
1879 XinitN(xs, 128, ATEMP);
1880 if (intoarray) {
1881 vp = global(*wp);
1882 subarray = last_lookup_was_array;
1883 if (vp->flag & RDONLY) {
1884 c_read_splitro:
1885 bi_errorf(Tf_ro, *wp);
1886 c_read_spliterr:
1887 rv = 2;
1888 afree(cp, ATEMP);
1889 goto c_read_out;
1890 }
1891 /* counter for array index */
1892 c = subarray ? arrayindex(vp) : 0;
1893 /* exporting an array is currently pointless */
1894 unset(vp, subarray ? 0 : 1);
1895 }
1896 if (!aschars) {
1897 /* skip initial IFS whitespace */
1898 while (bytesread && is_ifsws(*ccp)) {
1899 ++ccp;
1900 --bytesread;
1901 }
1902 /* trim trailing IFS whitespace */
1903 while (bytesread && is_ifsws(ccp[bytesread - 1])) {
1904 --bytesread;
1905 }
1906 }
1907 c_read_splitloop:
1908 xp = Xstring(xs, xp);
1909 /* generate next word */
1910 if (!bytesread) {
1911 /* no more input */
1912 if (intoarray)
1913 goto c_read_splitdone;
1914 /* zero out next parameters */
1915 goto c_read_gotword;
1916 }
1917 if (aschars) {
1918 Xput(xs, xp, '1');
1919 Xput(xs, xp, '#');
1920 bytesleft = utf_ptradj(ccp);
1921 while (bytesleft && bytesread) {
1922 *xp++ = *ccp++;
1923 --bytesleft;
1924 --bytesread;
1925 }
1926 if (xp[-1] == '\0') {
1927 xp[-1] = '0';
1928 xp[-3] = '2';
1929 }
1930 goto c_read_gotword;
1931 }
1932
1933 if (!intoarray && wp[1] == NULL)
1934 lastparmmode = true;
1935
1936 c_read_splitlast:
1937 /* copy until IFS character */
1938 while (bytesread) {
1939 char ch;
1940
1941 ch = *ccp;
1942 if (expanding) {
1943 expanding = false;
1944 goto c_read_splitcopy;
1945 } else if (ctype(ch, C_IFS)) {
1946 break;
1947 } else if (!rawmode && ch == '\\') {
1948 expanding = true;
1949 } else {
1950 c_read_splitcopy:
1951 Xcheck(xs, xp);
1952 Xput(xs, xp, ch);
1953 }
1954 ++ccp;
1955 --bytesread;
1956 }
1957 xsave = Xsavepos(xs, xp);
1958 /* copy word delimiter: IFSWS+IFS,IFSWS */
1959 expanding = false;
1960 while (bytesread) {
1961 char ch;
1962
1963 ch = *ccp;
1964 if (!ctype(ch, C_IFS))
1965 break;
1966 if (lastparmmode && !expanding && !rawmode && ch == '\\') {
1967 expanding = true;
1968 } else {
1969 Xcheck(xs, xp);
1970 Xput(xs, xp, ch);
1971 }
1972 ++ccp;
1973 --bytesread;
1974 if (expanding)
1975 continue;
1976 if (!ctype(ch, C_IFSWS))
1977 break;
1978 }
1979 while (bytesread && is_ifsws(*ccp)) {
1980 Xcheck(xs, xp);
1981 Xput(xs, xp, *ccp);
1982 ++ccp;
1983 --bytesread;
1984 }
1985 /* if no more parameters, rinse and repeat */
1986 if (lastparmmode && bytesread) {
1987 lastparmused = true;
1988 goto c_read_splitlast;
1989 }
1990 /* get rid of the delimiter unless we pack the rest */
1991 if (!lastparmused)
1992 xp = Xrestpos(xs, xp, xsave);
1993 c_read_gotword:
1994 Xput(xs, xp, '\0');
1995 if (intoarray) {
1996 if (subarray) {
1997 /* array element passed, accept first read */
1998 if (vq) {
1999 bi_errorf("nested arrays not yet supported");
2000 goto c_read_spliterr;
2001 }
2002 vq = vp;
2003 if (c)
2004 /* [0] doesn't */
2005 vq->flag |= AINDEX;
2006 } else
2007 vq = arraysearch(vp, c++);
2008 } else {
2009 vq = global(*wp);
2010 /* must be checked before exporting */
2011 if (vq->flag & RDONLY)
2012 goto c_read_splitro;
2013 if (Flag(FEXPORT))
2014 typeset(*wp, EXPORT, 0, 0, 0);
2015 }
2016 if (!setstr(vq, Xstring(xs, xp), KSH_RETURN_ERROR))
2017 goto c_read_spliterr;
2018 if (aschars) {
2019 setint_v(vq, vq, false);
2020 /* protect from UTFMODE changes */
2021 vq->type = 0;
2022 }
2023 if (intoarray || *++wp != NULL)
2024 goto c_read_splitloop;
2025
2026 c_read_splitdone:
2027 /* free up */
2028 afree(cp, ATEMP);
2029
2030 c_read_out:
2031 afree(allocd, ATEMP);
2032 Xfree(xs, xp);
2033 if (restore_tios)
2034 mksh_tcset(fd, &tios);
2035 return (rv == 3 ? ksh_sigmask(SIGALRM) : rv);
2036 #undef is_ifsws
2037 }
2038
2039 int
c_eval(const char ** wp)2040 c_eval(const char **wp)
2041 {
2042 struct source *s, *saves = source;
2043 unsigned char savef;
2044 int rv;
2045
2046 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2047 return (1);
2048 s = pushs(SWORDS, ATEMP);
2049 s->u.strv = wp + builtin_opt.optind;
2050 s->line = current_lineno;
2051
2052 /*-
2053 * The following code handles the case where the command is
2054 * empty due to failed command substitution, for example by
2055 * eval "$(false)"
2056 * This has historically returned 1 by AT&T ksh88. In this
2057 * case, shell() will not set or change exstat because the
2058 * compiled tree is empty, so it will use the value we pass
2059 * from subst_exstat, which is cleared in execute(), so it
2060 * should have been 0 if there were no substitutions.
2061 *
2062 * POSIX however says we don't do this, even though it is
2063 * traditionally done. AT&T ksh93 agrees with POSIX, so we
2064 * do. The following is an excerpt from SUSv4 [1003.2-2008]:
2065 *
2066 * 2.9.1: Simple Commands
2067 * ... If there is a command name, execution shall
2068 * continue as described in 2.9.1.1 [Command Search
2069 * and Execution]. If there is no command name, but
2070 * the command contained a command substitution, the
2071 * command shall complete with the exit status of the
2072 * last command substitution performed.
2073 * 2.9.1.1: Command Search and Execution
2074 * (1) a. If the command name matches the name of a
2075 * special built-in utility, that special built-in
2076 * utility shall be invoked.
2077 * 2.14.5: eval
2078 * If there are no arguments, or only null arguments,
2079 * eval shall return a zero exit status; ...
2080 */
2081 /* AT&T ksh88: use subst_exstat */
2082 /* exstat = subst_exstat; */
2083 /* SUSv4: OR with a high value never written otherwise */
2084 exstat |= 0x4000;
2085
2086 savef = Flag(FERREXIT);
2087 Flag(FERREXIT) |= 0x80;
2088 rv = shell(s, 2);
2089 Flag(FERREXIT) = savef;
2090 source = saves;
2091 afree(s, ATEMP);
2092 if (exstat & 0x4000)
2093 /* detect old exstat, use 0 in that case */
2094 rv = 0;
2095 return (rv);
2096 }
2097
2098 int
c_trap(const char ** wp)2099 c_trap(const char **wp)
2100 {
2101 Trap *p = sigtraps;
2102 int i = ksh_NSIG;
2103 const char *s;
2104
2105 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2106 return (1);
2107 wp += builtin_opt.optind;
2108
2109 if (*wp == NULL) {
2110 do {
2111 if (p->trap) {
2112 shf_puts("trap -- ", shl_stdout);
2113 print_value_quoted(shl_stdout, p->trap);
2114 shprintf(Tf__sN, p->name);
2115 }
2116 ++p;
2117 } while (i--);
2118 return (0);
2119 }
2120
2121 if (getn(*wp, &i)) {
2122 /* first argument is a signal number, reset them all */
2123 s = NULL;
2124 } else {
2125 /* first argument must be a command, then */
2126 s = *wp++;
2127 /* reset traps? */
2128 if (ksh_isdash(s))
2129 s = NULL;
2130 }
2131
2132 /* set/clear the traps */
2133 i = 0;
2134 while (*wp)
2135 if (!(p = gettrap(*wp++, true, true))) {
2136 warningf(true, Tbad_sig_ss, builtin_argv0, wp[-1]);
2137 i = 1;
2138 } else
2139 settrap(p, s);
2140 return (i);
2141 }
2142
2143 int
c_exitreturn(const char ** wp)2144 c_exitreturn(const char **wp)
2145 {
2146 int n, how = LEXIT;
2147
2148 if (wp[1]) {
2149 if (wp[2])
2150 goto c_exitreturn_err;
2151 exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1;
2152 } else if (trap_exstat != -1)
2153 exstat = trap_exstat;
2154
2155 if (wp[0][0] == 'r') {
2156 /* return */
2157 struct env *ep;
2158
2159 /*
2160 * need to tell if this is exit or return so trap exit will
2161 * work right (POSIX)
2162 */
2163 for (ep = e; ep; ep = ep->oenv)
2164 if (STOP_RETURN(ep->type)) {
2165 how = LRETURN;
2166 break;
2167 }
2168 }
2169
2170 if (how == LEXIT && !really_exit && j_stopped_running()) {
2171 really_exit = true;
2172 how = LSHELL;
2173 }
2174
2175 /* get rid of any I/O redirections */
2176 quitenv(NULL);
2177 unwind(how);
2178 /* NOTREACHED */
2179
2180 c_exitreturn_err:
2181 bi_errorf(Ttoo_many_args);
2182 return (1);
2183 }
2184
2185 int
c_brkcont(const char ** wp)2186 c_brkcont(const char **wp)
2187 {
2188 unsigned int quit;
2189 int n;
2190 struct env *ep, *last_ep = NULL;
2191 const char *arg;
2192
2193 if (ksh_getopt(wp, &builtin_opt, null) == '?')
2194 goto c_brkcont_err;
2195 arg = wp[builtin_opt.optind];
2196
2197 if (!arg)
2198 n = 1;
2199 else if (!bi_getn(arg, &n))
2200 goto c_brkcont_err;
2201 if (n <= 0) {
2202 /* AT&T ksh does this for non-interactive shells only - weird */
2203 bi_errorf("%s: bad value", arg);
2204 goto c_brkcont_err;
2205 }
2206 quit = (unsigned int)n;
2207
2208 /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
2209 for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
2210 if (ep->type == E_LOOP) {
2211 if (--quit == 0)
2212 break;
2213 ep->flags |= EF_BRKCONT_PASS;
2214 last_ep = ep;
2215 }
2216
2217 if (quit) {
2218 /*
2219 * AT&T ksh doesn't print a message - just does what it
2220 * can. We print a message 'cause it helps in debugging
2221 * scripts, but don't generate an error (ie, keep going).
2222 */
2223 if ((unsigned int)n == quit) {
2224 warningf(true, Tf_cant_s, wp[0], wp[0]);
2225 return (0);
2226 }
2227 /*
2228 * POSIX says if n is too big, the last enclosing loop
2229 * shall be used. Doesn't say to print an error but we
2230 * do anyway 'cause the user messed up.
2231 */
2232 if (last_ep)
2233 last_ep->flags &= ~EF_BRKCONT_PASS;
2234 warningf(true, "%s: can only %s %u level(s)",
2235 wp[0], wp[0], (unsigned int)n - quit);
2236 }
2237
2238 unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
2239 /* NOTREACHED */
2240
2241 c_brkcont_err:
2242 return (1);
2243 }
2244
2245 int
c_set(const char ** wp)2246 c_set(const char **wp)
2247 {
2248 int argi;
2249 bool setargs;
2250 struct block *l = e->loc;
2251 const char **owp;
2252
2253 if (wp[1] == NULL) {
2254 static const char *args[] = { Tset, "-", NULL };
2255 return (c_typeset(args));
2256 }
2257
2258 if ((argi = parse_args(wp, OF_SET, &setargs)) < 0)
2259 return (2);
2260 /* set $# and $* */
2261 if (setargs) {
2262 wp += argi - 1;
2263 owp = wp;
2264 /* save $0 */
2265 wp[0] = l->argv[0];
2266 while (*++wp != NULL)
2267 strdupx(*wp, *wp, &l->area);
2268 l->argc = wp - owp - 1;
2269 l->argv = alloc2(l->argc + 2, sizeof(char *), &l->area);
2270 for (wp = l->argv; (*wp++ = *owp++) != NULL; )
2271 ;
2272 }
2273 /*-
2274 * POSIX says set exit status is 0, but old scripts that use
2275 * getopt(1) use the construct
2276 * set -- $(getopt ab:c "$@")
2277 * which assumes the exit value set will be that of the $()
2278 * (subst_exstat is cleared in execute() so that it will be 0
2279 * if there are no command substitutions).
2280 */
2281 #ifdef MKSH_LEGACY_MODE
2282 /* traditional behaviour, unless set -o posix */
2283 return (Flag(FPOSIX) ? 0 : subst_exstat);
2284 #else
2285 /* conformant behaviour, unless set -o sh +o posix */
2286 return (Flag(FSH) && !Flag(FPOSIX) ? subst_exstat : 0);
2287 #endif
2288 }
2289
2290 int
c_unset(const char ** wp)2291 c_unset(const char **wp)
2292 {
2293 const char *id;
2294 int optc, rv = 0;
2295 bool unset_var = true;
2296
2297 while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1)
2298 switch (optc) {
2299 case 'f':
2300 unset_var = false;
2301 break;
2302 case 'v':
2303 unset_var = true;
2304 break;
2305 case '?':
2306 /*XXX not reached due to GF_ERROR */
2307 return (2);
2308 }
2309 wp += builtin_opt.optind;
2310 for (; (id = *wp) != NULL; wp++)
2311 if (unset_var) {
2312 /* unset variable */
2313 struct tbl *vp;
2314 char *cp = NULL;
2315 size_t n;
2316
2317 n = strlen(id);
2318 if (n > 3 && ord(id[n - 3]) == ORD('[') &&
2319 ord(id[n - 2]) == ORD('*') &&
2320 ord(id[n - 1]) == ORD(']')) {
2321 strndupx(cp, id, n - 3, ATEMP);
2322 id = cp;
2323 optc = 3;
2324 } else
2325 optc = vstrchr(id, '[') ? 0 : 1;
2326
2327 vp = global(id);
2328 afree(cp, ATEMP);
2329
2330 if ((vp->flag&RDONLY)) {
2331 warningf(true, Tf_ro, vp->name);
2332 rv = 1;
2333 } else
2334 unset(vp, optc);
2335 } else
2336 /* unset function */
2337 define(id, NULL);
2338 return (rv);
2339 }
2340
2341 static void
p_time(struct shf * shf,bool posix,long tv_sec,int tv_usec,int width,const char * prefix,const char * suffix)2342 p_time(struct shf *shf, bool posix, long tv_sec, int tv_usec, int width,
2343 const char *prefix, const char *suffix)
2344 {
2345 tv_usec /= 10000;
2346 if (posix)
2347 shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width,
2348 tv_sec, tv_usec, suffix);
2349 else
2350 shf_fprintf(shf, "%s%*ldm%02d.%02ds%s", prefix, width,
2351 tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix);
2352 }
2353
2354 int
c_times(const char ** wp MKSH_A_UNUSED)2355 c_times(const char **wp MKSH_A_UNUSED)
2356 {
2357 struct rusage usage;
2358
2359 getrusage(RUSAGE_SELF, &usage);
2360 p_time(shl_stdout, false, usage.ru_utime.tv_sec,
2361 usage.ru_utime.tv_usec, 0, null, T1space);
2362 p_time(shl_stdout, false, usage.ru_stime.tv_sec,
2363 usage.ru_stime.tv_usec, 0, null, "\n");
2364
2365 getrusage(RUSAGE_CHILDREN, &usage);
2366 p_time(shl_stdout, false, usage.ru_utime.tv_sec,
2367 usage.ru_utime.tv_usec, 0, null, T1space);
2368 p_time(shl_stdout, false, usage.ru_stime.tv_sec,
2369 usage.ru_stime.tv_usec, 0, null, "\n");
2370
2371 return (0);
2372 }
2373
2374 /*
2375 * time pipeline (really a statement, not a built-in command)
2376 */
2377 int
timex(struct op * t,int f,volatile int * xerrok)2378 timex(struct op *t, int f, volatile int *xerrok)
2379 {
2380 #define TF_NOARGS BIT(0)
2381 #define TF_NOREAL BIT(1) /* don't report real time */
2382 #define TF_POSIX BIT(2) /* report in POSIX format */
2383 int rv = 0, tf = 0;
2384 struct rusage ru0, ru1, cru0, cru1;
2385 struct timeval usrtime, systime, tv0, tv1;
2386
2387 mksh_TIME(tv0);
2388 getrusage(RUSAGE_SELF, &ru0);
2389 getrusage(RUSAGE_CHILDREN, &cru0);
2390 if (t->left) {
2391 /*
2392 * Two ways of getting cpu usage of a command: just use t0
2393 * and t1 (which will get cpu usage from other jobs that
2394 * finish while we are executing t->left), or get the
2395 * cpu usage of t->left. AT&T ksh does the former, while
2396 * pdksh tries to do the later (the j_usrtime hack doesn't
2397 * really work as it only counts the last job).
2398 */
2399 timerclear(&j_usrtime);
2400 timerclear(&j_systime);
2401 rv = execute(t->left, f | XTIME, xerrok);
2402 if (t->left->type == TCOM)
2403 tf |= t->left->str[0];
2404 mksh_TIME(tv1);
2405 getrusage(RUSAGE_SELF, &ru1);
2406 getrusage(RUSAGE_CHILDREN, &cru1);
2407 } else
2408 tf = TF_NOARGS;
2409
2410 if (tf & TF_NOARGS) {
2411 /* ksh93 - report shell times (shell+kids) */
2412 tf |= TF_NOREAL;
2413 timeradd(&ru0.ru_utime, &cru0.ru_utime, &usrtime);
2414 timeradd(&ru0.ru_stime, &cru0.ru_stime, &systime);
2415 } else {
2416 timersub(&ru1.ru_utime, &ru0.ru_utime, &usrtime);
2417 timeradd(&usrtime, &j_usrtime, &usrtime);
2418 timersub(&ru1.ru_stime, &ru0.ru_stime, &systime);
2419 timeradd(&systime, &j_systime, &systime);
2420 }
2421
2422 if (!(tf & TF_NOREAL)) {
2423 timersub(&tv1, &tv0, &tv1);
2424 if (tf & TF_POSIX)
2425 p_time(shl_out, true, tv1.tv_sec, tv1.tv_usec,
2426 5, Treal_sp1, "\n");
2427 else
2428 p_time(shl_out, false, tv1.tv_sec, tv1.tv_usec,
2429 5, null, Treal_sp2);
2430 }
2431 if (tf & TF_POSIX)
2432 p_time(shl_out, true, usrtime.tv_sec, usrtime.tv_usec,
2433 5, Tuser_sp1, "\n");
2434 else
2435 p_time(shl_out, false, usrtime.tv_sec, usrtime.tv_usec,
2436 5, null, Tuser_sp2);
2437 if (tf & TF_POSIX)
2438 p_time(shl_out, true, systime.tv_sec, systime.tv_usec,
2439 5, "sys ", "\n");
2440 else
2441 p_time(shl_out, false, systime.tv_sec, systime.tv_usec,
2442 5, null, " system\n");
2443 shf_flush(shl_out);
2444
2445 return (rv);
2446 }
2447
2448 void
timex_hook(struct op * t,char ** volatile * app)2449 timex_hook(struct op *t, char **volatile *app)
2450 {
2451 char **wp = *app;
2452 int optc, i, j;
2453 Getopt opt;
2454
2455 ksh_getopt_reset(&opt, 0);
2456 /* start at the start */
2457 opt.optind = 0;
2458 while ((optc = ksh_getopt((const char **)wp, &opt, ":p")) != -1)
2459 switch (optc) {
2460 case 'p':
2461 t->str[0] |= TF_POSIX;
2462 break;
2463 case '?':
2464 errorf(Tf_optfoo, Ttime, Tcolsp,
2465 opt.optarg[0], Tunknown_option);
2466 case ':':
2467 errorf(Tf_optfoo, Ttime, Tcolsp,
2468 opt.optarg[0], Treq_arg);
2469 }
2470 /* Copy command words down over options. */
2471 if (opt.optind != 0) {
2472 for (i = 0; i < opt.optind; i++)
2473 afree(wp[i], ATEMP);
2474 for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
2475 ;
2476 }
2477 if (!wp[0])
2478 t->str[0] |= TF_NOARGS;
2479 *app = wp;
2480 }
2481
2482 /* exec with no args - args case is taken care of in comexec() */
2483 int
c_exec(const char ** wp MKSH_A_UNUSED)2484 c_exec(const char **wp MKSH_A_UNUSED)
2485 {
2486 int i;
2487
2488 /* make sure redirects stay in place */
2489 if (e->savefd != NULL) {
2490 for (i = 0; i < NUFILE; i++) {
2491 if (e->savefd[i] > 0)
2492 close(e->savefd[i]);
2493 /*
2494 * keep all file descriptors > 2 private for ksh,
2495 * but not for POSIX or legacy/kludge sh
2496 */
2497 if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 &&
2498 e->savefd[i])
2499 fcntl(i, F_SETFD, FD_CLOEXEC);
2500 }
2501 e->savefd = NULL;
2502 }
2503 return (0);
2504 }
2505
2506 #if HAVE_MKNOD && !defined(__OS2__)
2507 int
c_mknod(const char ** wp)2508 c_mknod(const char **wp)
2509 {
2510 int argc, optc, rv = 0;
2511 bool ismkfifo = false;
2512 const char **argv;
2513 void *set = NULL;
2514 mode_t mode = 0, oldmode = 0;
2515
2516 while ((optc = ksh_getopt(wp, &builtin_opt, "m:")) != -1) {
2517 switch (optc) {
2518 case 'm':
2519 set = setmode(builtin_opt.optarg);
2520 if (set == NULL) {
2521 bi_errorf("invalid file mode");
2522 return (1);
2523 }
2524 mode = getmode(set, (mode_t)(DEFFILEMODE));
2525 free_ossetmode(set);
2526 break;
2527 default:
2528 goto c_mknod_usage;
2529 }
2530 }
2531 argv = &wp[builtin_opt.optind];
2532 if (argv[0] == NULL)
2533 goto c_mknod_usage;
2534 for (argc = 0; argv[argc]; argc++)
2535 ;
2536 if (argc == 2 && argv[1][0] == 'p')
2537 ismkfifo = true;
2538 else if (argc != 4 || (argv[1][0] != 'b' && argv[1][0] != 'c'))
2539 goto c_mknod_usage;
2540
2541 if (set != NULL)
2542 oldmode = umask((mode_t)0);
2543 else
2544 mode = DEFFILEMODE;
2545
2546 mode |= (argv[1][0] == 'b') ? S_IFBLK :
2547 (argv[1][0] == 'c') ? S_IFCHR : 0;
2548
2549 if (!ismkfifo) {
2550 unsigned long majnum, minnum;
2551 dev_t dv;
2552 char *c;
2553
2554 majnum = strtoul(argv[2], &c, 0);
2555 if ((c == argv[2]) || (*c != '\0')) {
2556 bi_errorf(Tf_nonnum, "device", "major", argv[2]);
2557 goto c_mknod_err;
2558 }
2559 minnum = strtoul(argv[3], &c, 0);
2560 if ((c == argv[3]) || (*c != '\0')) {
2561 bi_errorf(Tf_nonnum, "device", "minor", argv[3]);
2562 goto c_mknod_err;
2563 }
2564 dv = makedev(majnum, minnum);
2565 if ((unsigned long)(major(dv)) != majnum) {
2566 bi_errorf(Tf_toolarge, "device", "major", majnum);
2567 goto c_mknod_err;
2568 }
2569 if ((unsigned long)(minor(dv)) != minnum) {
2570 bi_errorf(Tf_toolarge, "device", "minor", minnum);
2571 goto c_mknod_err;
2572 }
2573 if (mknod(argv[0], mode, dv))
2574 goto c_mknod_failed;
2575 } else if (mkfifo(argv[0], mode)) {
2576 c_mknod_failed:
2577 bi_errorf(Tf_sD_s, argv[0], cstrerror(errno));
2578 c_mknod_err:
2579 rv = 1;
2580 }
2581
2582 if (set)
2583 umask(oldmode);
2584 return (rv);
2585 c_mknod_usage:
2586 bi_errorf("usage: mknod [-m mode] name %s", "b|c major minor");
2587 bi_errorf("usage: mknod [-m mode] name %s", "p");
2588 return (1);
2589 }
2590 #endif
2591
2592 /*-
2593 test(1) roughly accepts the following grammar:
2594 oexpr ::= aexpr | aexpr "-o" oexpr ;
2595 aexpr ::= nexpr | nexpr "-a" aexpr ;
2596 nexpr ::= primary | "!" nexpr ;
2597 primary ::= unary-operator operand
2598 | operand binary-operator operand
2599 | operand
2600 | "(" oexpr ")"
2601 ;
2602
2603 unary-operator ::= "-a"|"-b"|"-c"|"-d"|"-e"|"-f"|"-G"|"-g"|"-H"|"-h"|
2604 "-k"|"-L"|"-n"|"-O"|"-o"|"-p"|"-r"|"-S"|"-s"|"-t"|
2605 "-u"|"-v"|"-w"|"-x"|"-z";
2606
2607 binary-operator ::= "="|"=="|"!="|"<"|">"|"-eq"|"-ne"|"-gt"|"-ge"|
2608 "-lt"|"-le"|"-ef"|"-nt"|"-ot";
2609
2610 operand ::= <anything>
2611 */
2612
2613 /* POSIX says > 1 for errors */
2614 #define T_ERR_EXIT 2
2615
2616 int
c_test(const char ** wp)2617 c_test(const char **wp)
2618 {
2619 int argc, rv, invert = 0;
2620 Test_env te;
2621 Test_op op;
2622 Test_meta tm;
2623 const char *lhs, **swp;
2624
2625 te.flags = 0;
2626 te.isa = ptest_isa;
2627 te.getopnd = ptest_getopnd;
2628 te.eval = test_eval;
2629 te.error = ptest_error;
2630
2631 for (argc = 0; wp[argc]; argc++)
2632 ;
2633
2634 if (strcmp(wp[0], Tbracket) == 0) {
2635 if (strcmp(wp[--argc], "]") != 0) {
2636 bi_errorf("missing ]");
2637 return (T_ERR_EXIT);
2638 }
2639 }
2640
2641 te.pos.wp = wp + 1;
2642 te.wp_end = wp + argc;
2643
2644 /*
2645 * Attempt to conform to POSIX special cases. This is pretty
2646 * dumb code straight-forward from the 2008 spec, but unlike
2647 * the old pdksh code doesn't live from so many assumptions.
2648 * It does, though, inline some calls to '(*te.funcname)()'.
2649 */
2650 switch (argc - 1) {
2651 case 0:
2652 return (1);
2653 case 1:
2654 ptest_one:
2655 op = TO_STNZE;
2656 goto ptest_unary;
2657 case 2:
2658 ptest_two:
2659 if (ptest_isa(&te, TM_NOT)) {
2660 ++invert;
2661 goto ptest_one;
2662 }
2663 if ((op = ptest_isa(&te, TM_UNOP))) {
2664 ptest_unary:
2665 rv = test_eval(&te, op, *te.pos.wp++, NULL, true);
2666 ptest_out:
2667 if (te.flags & TEF_ERROR)
2668 return (T_ERR_EXIT);
2669 return ((invert & 1) ? rv : !rv);
2670 }
2671 /* let the parser deal with anything else */
2672 break;
2673 case 3:
2674 ptest_three:
2675 swp = te.pos.wp;
2676 /* use inside knowledge of ptest_getopnd inlined below */
2677 lhs = *te.pos.wp++;
2678 if ((op = ptest_isa(&te, TM_BINOP))) {
2679 /* test lhs op rhs */
2680 rv = test_eval(&te, op, lhs, *te.pos.wp++, true);
2681 goto ptest_out;
2682 }
2683 if (ptest_isa(&te, tm = TM_AND) || ptest_isa(&te, tm = TM_OR)) {
2684 /* XSI */
2685 argc = test_eval(&te, TO_STNZE, lhs, NULL, true);
2686 rv = test_eval(&te, TO_STNZE, *te.pos.wp++, NULL, true);
2687 if (tm == TM_AND)
2688 rv = argc && rv;
2689 else
2690 rv = argc || rv;
2691 goto ptest_out;
2692 }
2693 /* back up to lhs */
2694 te.pos.wp = swp;
2695 if (ptest_isa(&te, TM_NOT)) {
2696 ++invert;
2697 goto ptest_two;
2698 }
2699 if (ptest_isa(&te, TM_OPAREN)) {
2700 swp = te.pos.wp;
2701 /* skip operand, without evaluation */
2702 te.pos.wp++;
2703 /* check for closing parenthesis */
2704 op = ptest_isa(&te, TM_CPAREN);
2705 /* back up to operand */
2706 te.pos.wp = swp;
2707 /* if there was a closing paren, handle it */
2708 if (op)
2709 goto ptest_one;
2710 /* backing up is done before calling the parser */
2711 }
2712 /* let the parser deal with it */
2713 break;
2714 case 4:
2715 if (ptest_isa(&te, TM_NOT)) {
2716 ++invert;
2717 goto ptest_three;
2718 }
2719 if (ptest_isa(&te, TM_OPAREN)) {
2720 swp = te.pos.wp;
2721 /* skip two operands, without evaluation */
2722 te.pos.wp++;
2723 te.pos.wp++;
2724 /* check for closing parenthesis */
2725 op = ptest_isa(&te, TM_CPAREN);
2726 /* back up to first operand */
2727 te.pos.wp = swp;
2728 /* if there was a closing paren, handle it */
2729 if (op)
2730 goto ptest_two;
2731 /* backing up is done before calling the parser */
2732 }
2733 /* defer this to the parser */
2734 break;
2735 }
2736
2737 /* "The results are unspecified." */
2738 te.pos.wp = wp + 1;
2739 return (test_parse(&te));
2740 }
2741
2742 /*
2743 * Generic test routines.
2744 */
2745
2746 Test_op
test_isop(Test_meta meta,const char * s)2747 test_isop(Test_meta meta, const char *s)
2748 {
2749 char sc1;
2750 const struct t_op *tbl;
2751
2752 tbl = meta == TM_UNOP ? u_ops : b_ops;
2753 if (*s) {
2754 sc1 = s[1];
2755 for (; tbl->op_text[0]; tbl++)
2756 if (sc1 == tbl->op_text[1] && !strcmp(s, tbl->op_text))
2757 return (tbl->op_num);
2758 }
2759 return (TO_NONOP);
2760 }
2761
2762 #ifdef __OS2__
2763 #define test_access(name, mode) access_ex(access, (name), (mode))
2764 #define test_stat(name, buffer) stat_ex((name), (buffer))
2765 #else
2766 #define test_access(name, mode) access((name), (mode))
2767 #define test_stat(name, buffer) stat((name), (buffer))
2768 #endif
2769
2770 int
test_eval(Test_env * te,Test_op op,const char * opnd1,const char * opnd2,bool do_eval)2771 test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
2772 bool do_eval)
2773 {
2774 int i, s;
2775 size_t k;
2776 struct stat b1, b2;
2777 mksh_ari_t v1, v2;
2778 struct tbl *vp;
2779
2780 if (!do_eval)
2781 return (0);
2782
2783 #ifdef DEBUG
2784 switch (op) {
2785 /* Binary operators */
2786 case TO_STEQL:
2787 case TO_STNEQ:
2788 case TO_STLT:
2789 case TO_STGT:
2790 case TO_INTEQ:
2791 case TO_INTNE:
2792 case TO_INTGT:
2793 case TO_INTGE:
2794 case TO_INTLT:
2795 case TO_INTLE:
2796 case TO_FILEQ:
2797 case TO_FILNT:
2798 case TO_FILOT:
2799 /* consistency check, but does not happen in practice */
2800 if (!opnd2) {
2801 te->flags |= TEF_ERROR;
2802 return (1);
2803 }
2804 break;
2805 default:
2806 /* for completeness of switch */
2807 break;
2808 }
2809 #endif
2810
2811 switch (op) {
2812
2813 /*
2814 * Unary Operators
2815 */
2816
2817 /* -n */
2818 case TO_STNZE:
2819 return (*opnd1 != '\0');
2820
2821 /* -z */
2822 case TO_STZER:
2823 return (*opnd1 == '\0');
2824
2825 /* -v */
2826 case TO_ISSET:
2827 return ((vp = isglobal(opnd1, false)) && (vp->flag & ISSET));
2828
2829 /* -o */
2830 case TO_OPTION:
2831 if ((i = *opnd1) == '!' || i == '?')
2832 opnd1++;
2833 if ((k = option(opnd1)) == (size_t)-1)
2834 return (0);
2835 return (i == '?' ? 1 : i == '!' ? !Flag(k) : Flag(k));
2836
2837 /* -r */
2838 case TO_FILRD:
2839 /* LINTED use of access */
2840 return (test_access(opnd1, R_OK) == 0);
2841
2842 /* -w */
2843 case TO_FILWR:
2844 /* LINTED use of access */
2845 return (test_access(opnd1, W_OK) == 0);
2846
2847 /* -x */
2848 case TO_FILEX:
2849 return (ksh_access(opnd1, X_OK) == 0);
2850
2851 /* -a */
2852 case TO_FILAXST:
2853 /* -e */
2854 case TO_FILEXST:
2855 return (test_stat(opnd1, &b1) == 0);
2856
2857 /* -f */
2858 case TO_FILREG:
2859 return (test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
2860
2861 /* -d */
2862 case TO_FILID:
2863 return (stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode));
2864
2865 /* -c */
2866 case TO_FILCDEV:
2867 return (stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode));
2868
2869 /* -b */
2870 case TO_FILBDEV:
2871 return (stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode));
2872
2873 /* -p */
2874 case TO_FILFIFO:
2875 return (stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode));
2876
2877 /* -h or -L */
2878 case TO_FILSYM:
2879 #ifdef MKSH__NO_SYMLINK
2880 return (0);
2881 #else
2882 return (lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode));
2883 #endif
2884
2885 /* -S */
2886 case TO_FILSOCK:
2887 return (stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode));
2888
2889 /* -H => HP context dependent files (directories) */
2890 case TO_FILCDF:
2891 #ifdef S_ISCDF
2892 {
2893 char *nv;
2894
2895 /*
2896 * Append a + to filename and check to see if result is
2897 * a setuid directory. CDF stuff in general is hookey,
2898 * since it breaks for, e.g., the following sequence:
2899 * echo hi >foo+; mkdir foo; echo bye >foo/default;
2900 * chmod u+s foo (foo+ refers to the file with hi in it,
2901 * there is no way to get at the file with bye in it;
2902 * please correct me if I'm wrong about this).
2903 */
2904
2905 nv = shf_smprintf("%s+", opnd1);
2906 i = (stat(nv, &b1) == 0 && S_ISCDF(b1.st_mode));
2907 afree(nv, ATEMP);
2908 return (i);
2909 }
2910 #else
2911 return (0);
2912 #endif
2913
2914 /* -u */
2915 case TO_FILSETU:
2916 return (stat(opnd1, &b1) == 0 &&
2917 (b1.st_mode & S_ISUID) == S_ISUID);
2918
2919 /* -g */
2920 case TO_FILSETG:
2921 return (stat(opnd1, &b1) == 0 &&
2922 (b1.st_mode & S_ISGID) == S_ISGID);
2923
2924 /* -k */
2925 case TO_FILSTCK:
2926 #ifdef S_ISVTX
2927 return (stat(opnd1, &b1) == 0 &&
2928 (b1.st_mode & S_ISVTX) == S_ISVTX);
2929 #else
2930 return (0);
2931 #endif
2932
2933 /* -s */
2934 case TO_FILGZ:
2935 return (stat(opnd1, &b1) == 0 && (off_t)b1.st_size > (off_t)0);
2936
2937 /* -t */
2938 case TO_FILTT:
2939 if (opnd1 && !bi_getn(opnd1, &i)) {
2940 te->flags |= TEF_ERROR;
2941 i = 0;
2942 } else
2943 i = isatty(opnd1 ? i : 0);
2944 return (i);
2945
2946 /* -O */
2947 case TO_FILUID:
2948 return (stat(opnd1, &b1) == 0 && (uid_t)b1.st_uid == ksheuid);
2949
2950 /* -G */
2951 case TO_FILGID:
2952 return (stat(opnd1, &b1) == 0 && (gid_t)b1.st_gid == getegid());
2953
2954 /*
2955 * Binary Operators
2956 */
2957
2958 /* =, == */
2959 case TO_STEQL:
2960 if (te->flags & TEF_DBRACKET) {
2961 if ((i = gmatchx(opnd1, opnd2, false)))
2962 record_match(opnd1);
2963 return (i);
2964 }
2965 return (strcmp(opnd1, opnd2) == 0);
2966
2967 /* != */
2968 case TO_STNEQ:
2969 if (te->flags & TEF_DBRACKET) {
2970 if ((i = gmatchx(opnd1, opnd2, false)))
2971 record_match(opnd1);
2972 return (!i);
2973 }
2974 return (strcmp(opnd1, opnd2) != 0);
2975
2976 /* < */
2977 case TO_STLT:
2978 return (strcmp(opnd1, opnd2) < 0);
2979
2980 /* > */
2981 case TO_STGT:
2982 return (strcmp(opnd1, opnd2) > 0);
2983
2984 /* -nt */
2985 case TO_FILNT:
2986 /*
2987 * ksh88/ksh93 succeed if file2 can't be stated
2988 * (subtly different from 'does not exist').
2989 */
2990 return (stat(opnd1, &b1) == 0 &&
2991 (((s = stat(opnd2, &b2)) == 0 &&
2992 b1.st_mtime > b2.st_mtime) || s < 0));
2993
2994 /* -ot */
2995 case TO_FILOT:
2996 /*
2997 * ksh88/ksh93 succeed if file1 can't be stated
2998 * (subtly different from 'does not exist').
2999 */
3000 return (stat(opnd2, &b2) == 0 &&
3001 (((s = stat(opnd1, &b1)) == 0 &&
3002 b1.st_mtime < b2.st_mtime) || s < 0));
3003
3004 /* -ef */
3005 case TO_FILEQ:
3006 return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 &&
3007 b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
3008
3009 /* all other cases */
3010 case TO_NONOP:
3011 case TO_NONNULL:
3012 /* throw the error */
3013 break;
3014
3015 /* -eq */
3016 case TO_INTEQ:
3017 /* -ne */
3018 case TO_INTNE:
3019 /* -ge */
3020 case TO_INTGE:
3021 /* -gt */
3022 case TO_INTGT:
3023 /* -le */
3024 case TO_INTLE:
3025 /* -lt */
3026 case TO_INTLT:
3027 if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) ||
3028 !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) {
3029 /* error already printed.. */
3030 te->flags |= TEF_ERROR;
3031 return (1);
3032 }
3033 switch (op) {
3034 case TO_INTEQ:
3035 return (v1 == v2);
3036 case TO_INTNE:
3037 return (v1 != v2);
3038 case TO_INTGE:
3039 return (v1 >= v2);
3040 case TO_INTGT:
3041 return (v1 > v2);
3042 case TO_INTLE:
3043 return (v1 <= v2);
3044 case TO_INTLT:
3045 return (v1 < v2);
3046 default:
3047 /* NOTREACHED */
3048 break;
3049 }
3050 /* NOTREACHED */
3051 }
3052 (*te->error)(te, 0, "internal error: unknown op");
3053 return (1);
3054 }
3055
3056 int
test_parse(Test_env * te)3057 test_parse(Test_env *te)
3058 {
3059 int rv;
3060
3061 rv = test_oexpr(te, 1);
3062
3063 if (!(te->flags & TEF_ERROR) && !(*te->isa)(te, TM_END))
3064 (*te->error)(te, 0, "unexpected operator/operand");
3065
3066 return ((te->flags & TEF_ERROR) ? T_ERR_EXIT : !rv);
3067 }
3068
3069 static int
test_oexpr(Test_env * te,bool do_eval)3070 test_oexpr(Test_env *te, bool do_eval)
3071 {
3072 int rv;
3073
3074 if ((rv = test_aexpr(te, do_eval)))
3075 do_eval = false;
3076 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_OR))
3077 return (test_oexpr(te, do_eval) || rv);
3078 return (rv);
3079 }
3080
3081 static int
test_aexpr(Test_env * te,bool do_eval)3082 test_aexpr(Test_env *te, bool do_eval)
3083 {
3084 int rv;
3085
3086 if (!(rv = test_nexpr(te, do_eval)))
3087 do_eval = false;
3088 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_AND))
3089 return (test_aexpr(te, do_eval) && rv);
3090 return (rv);
3091 }
3092
3093 static int
test_nexpr(Test_env * te,bool do_eval)3094 test_nexpr(Test_env *te, bool do_eval)
3095 {
3096 if (!(te->flags & TEF_ERROR) && (*te->isa)(te, TM_NOT))
3097 return (!test_nexpr(te, do_eval));
3098 return (test_primary(te, do_eval));
3099 }
3100
3101 static int
test_primary(Test_env * te,bool do_eval)3102 test_primary(Test_env *te, bool do_eval)
3103 {
3104 const char *opnd1, *opnd2;
3105 int rv;
3106 Test_op op;
3107
3108 if (te->flags & TEF_ERROR)
3109 return (0);
3110 if ((*te->isa)(te, TM_OPAREN)) {
3111 rv = test_oexpr(te, do_eval);
3112 if (te->flags & TEF_ERROR)
3113 return (0);
3114 if (!(*te->isa)(te, TM_CPAREN)) {
3115 (*te->error)(te, 0, "missing )");
3116 return (0);
3117 }
3118 return (rv);
3119 }
3120 /*
3121 * Binary should have precedence over unary in this case
3122 * so that something like test \( -f = -f \) is accepted
3123 */
3124 if ((te->flags & TEF_DBRACKET) || (&te->pos.wp[1] < te->wp_end &&
3125 !test_isop(TM_BINOP, te->pos.wp[1]))) {
3126 if ((op = (*te->isa)(te, TM_UNOP))) {
3127 /* unary expression */
3128 opnd1 = (*te->getopnd)(te, op, do_eval);
3129 if (!opnd1) {
3130 (*te->error)(te, -1, Tno_args);
3131 return (0);
3132 }
3133
3134 return ((*te->eval)(te, op, opnd1, NULL, do_eval));
3135 }
3136 }
3137 opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval);
3138 if (!opnd1) {
3139 (*te->error)(te, 0, "expression expected");
3140 return (0);
3141 }
3142 if ((op = (*te->isa)(te, TM_BINOP))) {
3143 /* binary expression */
3144 opnd2 = (*te->getopnd)(te, op, do_eval);
3145 if (!opnd2) {
3146 (*te->error)(te, -1, "missing second argument");
3147 return (0);
3148 }
3149
3150 return ((*te->eval)(te, op, opnd1, opnd2, do_eval));
3151 }
3152 return ((*te->eval)(te, TO_STNZE, opnd1, NULL, do_eval));
3153 }
3154
3155 /*
3156 * Plain test (test and [ .. ]) specific routines.
3157 */
3158
3159 /*
3160 * Test if the current token is a whatever. Accepts the current token if
3161 * it is. Returns 0 if it is not, non-zero if it is (in the case of
3162 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
3163 */
3164 static Test_op
ptest_isa(Test_env * te,Test_meta meta)3165 ptest_isa(Test_env *te, Test_meta meta)
3166 {
3167 /* Order important - indexed by Test_meta values */
3168 static const char * const tokens[] = {
3169 "-o", "-a", "!", "(", ")"
3170 };
3171 Test_op rv;
3172
3173 if (te->pos.wp >= te->wp_end)
3174 return (meta == TM_END ? TO_NONNULL : TO_NONOP);
3175
3176 if (meta == TM_UNOP || meta == TM_BINOP)
3177 rv = test_isop(meta, *te->pos.wp);
3178 else if (meta == TM_END)
3179 rv = TO_NONOP;
3180 else
3181 rv = !strcmp(*te->pos.wp, tokens[(int)meta]) ?
3182 TO_NONNULL : TO_NONOP;
3183
3184 /* Accept the token? */
3185 if (rv != TO_NONOP)
3186 te->pos.wp++;
3187
3188 return (rv);
3189 }
3190
3191 static const char *
ptest_getopnd(Test_env * te,Test_op op,bool do_eval MKSH_A_UNUSED)3192 ptest_getopnd(Test_env *te, Test_op op, bool do_eval MKSH_A_UNUSED)
3193 {
3194 if (te->pos.wp >= te->wp_end)
3195 return (op == TO_FILTT ? "1" : NULL);
3196 return (*te->pos.wp++);
3197 }
3198
3199 static void
ptest_error(Test_env * te,int ofs,const char * msg)3200 ptest_error(Test_env *te, int ofs, const char *msg)
3201 {
3202 const char *op;
3203
3204 te->flags |= TEF_ERROR;
3205 if ((op = te->pos.wp + ofs >= te->wp_end ? NULL : te->pos.wp[ofs]))
3206 bi_errorf(Tf_sD_s, op, msg);
3207 else
3208 bi_errorf(Tf_s, msg);
3209 }
3210
3211 #ifndef MKSH_NO_LIMITS
3212 #define SOFT 0x1
3213 #define HARD 0x2
3214
3215 /* Magic to divine the 'm' and 'v' limits */
3216
3217 #ifdef RLIMIT_AS
3218 #if !defined(RLIMIT_VMEM) || (RLIMIT_VMEM == RLIMIT_AS) || \
3219 !defined(RLIMIT_RSS) || (RLIMIT_VMEM == RLIMIT_RSS)
3220 #define ULIMIT_V_IS_AS
3221 #elif defined(RLIMIT_VMEM)
3222 #if !defined(RLIMIT_RSS) || (RLIMIT_RSS == RLIMIT_AS)
3223 #define ULIMIT_V_IS_AS
3224 #else
3225 #define ULIMIT_V_IS_VMEM
3226 #endif
3227 #endif
3228 #endif
3229
3230 #ifdef RLIMIT_RSS
3231 #ifdef ULIMIT_V_IS_VMEM
3232 #define ULIMIT_M_IS_RSS
3233 #elif defined(RLIMIT_VMEM) && (RLIMIT_VMEM == RLIMIT_RSS)
3234 #define ULIMIT_M_IS_VMEM
3235 #else
3236 #define ULIMIT_M_IS_RSS
3237 #endif
3238 #if defined(ULIMIT_M_IS_RSS) && defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)
3239 #undef ULIMIT_M_IS_RSS
3240 #endif
3241 #endif
3242
3243 #if !defined(RLIMIT_AS) && !defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_VMEM)
3244 #define ULIMIT_V_IS_VMEM
3245 #endif
3246
3247 #if !defined(ULIMIT_V_IS_VMEM) && defined(RLIMIT_VMEM) && \
3248 (!defined(RLIMIT_RSS) || (defined(RLIMIT_AS) && (RLIMIT_RSS == RLIMIT_AS)))
3249 #define ULIMIT_M_IS_VMEM
3250 #endif
3251
3252 #if defined(ULIMIT_M_IS_VMEM) && defined(RLIMIT_AS) && \
3253 (RLIMIT_VMEM == RLIMIT_AS)
3254 #undef ULIMIT_M_IS_VMEM
3255 #endif
3256
3257 #if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
3258 # error nonsensical m ulimit
3259 #endif
3260
3261 #if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
3262 # error nonsensical v ulimit
3263 #endif
3264
3265 struct limits {
3266 /* limit resource */
3267 int resource;
3268 /* multiply by to get rlim_{cur,max} values */
3269 unsigned int factor;
3270 /* getopts char */
3271 char optchar;
3272 /* limit name */
3273 char name[1];
3274 };
3275
3276 #define RLIMITS_DEFNS
3277 #define FN(lname,lid,lfac,lopt) \
3278 static const struct { \
3279 int resource; \
3280 unsigned int factor; \
3281 char optchar; \
3282 char name[sizeof(lname)]; \
3283 } rlimits_ ## lid = { \
3284 lid, lfac, lopt, lname \
3285 };
3286 #include "rlimits.gen"
3287
3288 static void print_ulimit(const struct limits *, int);
3289 static int set_ulimit(const struct limits *, const char *, int);
3290
3291 static const struct limits * const rlimits[] = {
3292 #define RLIMITS_ITEMS
3293 #include "rlimits.gen"
3294 };
3295
3296 static const char rlimits_opts[] =
3297 #define RLIMITS_OPTCS
3298 #include "rlimits.gen"
3299 ;
3300
3301 int
c_ulimit(const char ** wp)3302 c_ulimit(const char **wp)
3303 {
3304 size_t i = 0;
3305 int how = SOFT | HARD, optc, what = 'f';
3306 bool all = false;
3307
3308 while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
3309 switch (optc) {
3310 case 'H':
3311 how = HARD;
3312 break;
3313 case 'S':
3314 how = SOFT;
3315 break;
3316 case 'a':
3317 all = true;
3318 break;
3319 case '?':
3320 bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
3321 return (1);
3322 default:
3323 what = optc;
3324 }
3325
3326 while (i < NELEM(rlimits)) {
3327 if (rlimits[i]->optchar == what)
3328 goto found;
3329 ++i;
3330 }
3331 internal_warningf("ulimit: %c", what);
3332 return (1);
3333 found:
3334 if (wp[builtin_opt.optind]) {
3335 if (all || wp[builtin_opt.optind + 1]) {
3336 bi_errorf(Ttoo_many_args);
3337 return (1);
3338 }
3339 return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
3340 }
3341 if (!all)
3342 print_ulimit(rlimits[i], how);
3343 else for (i = 0; i < NELEM(rlimits); ++i) {
3344 shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name);
3345 print_ulimit(rlimits[i], how);
3346 }
3347 return (0);
3348 }
3349
3350 static int
set_ulimit(const struct limits * l,const char * v,int how)3351 set_ulimit(const struct limits *l, const char *v, int how)
3352 {
3353 rlim_t val = (rlim_t)0;
3354 struct rlimit limit;
3355
3356 if (strcmp(v, "unlimited") == 0)
3357 val = (rlim_t)RLIM_INFINITY;
3358 else {
3359 mksh_uari_t rval;
3360
3361 if (!evaluate(v, (mksh_ari_t *)&rval, KSH_RETURN_ERROR, false))
3362 return (1);
3363 /*
3364 * Avoid problems caused by typos that evaluate misses due
3365 * to evaluating unset parameters to 0...
3366 * If this causes problems, will have to add parameter to
3367 * evaluate() to control if unset params are 0 or an error.
3368 */
3369 if (!rval && !ctype(v[0], C_DIGIT)) {
3370 bi_errorf("invalid %s limit: %s", l->name, v);
3371 return (1);
3372 }
3373 val = (rlim_t)((rlim_t)rval * l->factor);
3374 }
3375
3376 if (getrlimit(l->resource, &limit) < 0) {
3377 #ifndef MKSH_SMALL
3378 bi_errorf("limit %s could not be read, contact the mksh developers: %s",
3379 l->name, cstrerror(errno));
3380 #endif
3381 /* some can't be read */
3382 limit.rlim_cur = RLIM_INFINITY;
3383 limit.rlim_max = RLIM_INFINITY;
3384 }
3385 if (how & SOFT)
3386 limit.rlim_cur = val;
3387 if (how & HARD)
3388 limit.rlim_max = val;
3389 if (!setrlimit(l->resource, &limit))
3390 return (0);
3391 if (errno == EPERM)
3392 bi_errorf("%s exceeds allowable %s limit", v, l->name);
3393 else
3394 bi_errorf("bad %s limit: %s", l->name, cstrerror(errno));
3395 return (1);
3396 }
3397
3398 static void
print_ulimit(const struct limits * l,int how)3399 print_ulimit(const struct limits *l, int how)
3400 {
3401 rlim_t val = (rlim_t)0;
3402 struct rlimit limit;
3403
3404 if (getrlimit(l->resource, &limit)) {
3405 shf_puts("unknown\n", shl_stdout);
3406 return;
3407 }
3408 if (how & SOFT)
3409 val = limit.rlim_cur;
3410 else if (how & HARD)
3411 val = limit.rlim_max;
3412 if (val == (rlim_t)RLIM_INFINITY)
3413 shf_puts("unlimited\n", shl_stdout);
3414 else
3415 shprintf("%lu\n", (unsigned long)(val / l->factor));
3416 }
3417 #endif
3418
3419 int
c_rename(const char ** wp)3420 c_rename(const char **wp)
3421 {
3422 int rv = 1;
3423
3424 /* skip argv[0] */
3425 ++wp;
3426 if (wp[0] && !strcmp(wp[0], "--"))
3427 /* skip "--" (options separator) */
3428 ++wp;
3429
3430 /* check for exactly two arguments */
3431 if (wp[0] == NULL /* first argument */ ||
3432 wp[1] == NULL /* second argument */ ||
3433 wp[2] != NULL /* no further args please */)
3434 bi_errorf(Tsynerr);
3435 else if ((rv = rename(wp[0], wp[1])) != 0) {
3436 rv = errno;
3437 bi_errorf(Tf_sD_s, "failed", cstrerror(rv));
3438 }
3439
3440 return (rv);
3441 }
3442
3443 int
c_realpath(const char ** wp)3444 c_realpath(const char **wp)
3445 {
3446 int rv = 1;
3447 char *buf;
3448
3449 /* skip argv[0] */
3450 ++wp;
3451 if (wp[0] && !strcmp(wp[0], "--"))
3452 /* skip "--" (options separator) */
3453 ++wp;
3454
3455 /* check for exactly one argument */
3456 if (wp[0] == NULL || wp[1] != NULL)
3457 bi_errorf(Tsynerr);
3458 else if ((buf = do_realpath(wp[0])) == NULL) {
3459 rv = errno;
3460 bi_errorf(Tf_sD_s, wp[0], cstrerror(rv));
3461 if ((unsigned int)rv > 255)
3462 rv = 255;
3463 } else {
3464 shprintf(Tf_sN, buf);
3465 afree(buf, ATEMP);
3466 rv = 0;
3467 }
3468
3469 return (rv);
3470 }
3471
3472 int
c_cat(const char ** wp)3473 c_cat(const char **wp)
3474 {
3475 int fd = STDIN_FILENO, rv;
3476 ssize_t n, w;
3477 const char *fn = "<stdin>";
3478 char *buf, *cp;
3479 bool opipe;
3480 #define MKSH_CAT_BUFSIZ 4096
3481
3482 /* parse options: POSIX demands we support "-u" as no-op */
3483 while ((rv = ksh_getopt(wp, &builtin_opt, "u")) != -1) {
3484 switch (rv) {
3485 case 'u':
3486 /* we already operate unbuffered */
3487 break;
3488 default:
3489 bi_errorf(Tsynerr);
3490 return (1);
3491 }
3492 }
3493 wp += builtin_opt.optind;
3494 rv = 0;
3495
3496 if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
3497 bi_errorf(Toomem, (size_t)MKSH_CAT_BUFSIZ);
3498 return (1);
3499 }
3500
3501 /* catch SIGPIPE */
3502 opipe = block_pipe();
3503
3504 do {
3505 if (*wp) {
3506 fn = *wp++;
3507 if (ksh_isdash(fn))
3508 fd = STDIN_FILENO;
3509 else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
3510 bi_errorf(Tf_sD_s, fn, cstrerror(errno));
3511 rv = 1;
3512 continue;
3513 }
3514 }
3515 while (/* CONSTCOND */ 1) {
3516 if ((n = blocking_read(fd, (cp = buf),
3517 MKSH_CAT_BUFSIZ)) == -1) {
3518 if (errno == EINTR) {
3519 if (opipe)
3520 restore_pipe();
3521 /* give the user a chance to ^C out */
3522 intrcheck();
3523 /* interrupted, try again */
3524 opipe = block_pipe();
3525 continue;
3526 }
3527 /* an error occured during reading */
3528 bi_errorf(Tf_sD_s, fn, cstrerror(errno));
3529 rv = 1;
3530 break;
3531 } else if (n == 0)
3532 /* end of file reached */
3533 break;
3534 while (n) {
3535 if (intrsig)
3536 goto has_intrsig;
3537 if ((w = write(STDOUT_FILENO, cp, n)) != -1) {
3538 n -= w;
3539 cp += w;
3540 continue;
3541 }
3542 if (errno == EINTR) {
3543 has_intrsig:
3544 if (opipe)
3545 restore_pipe();
3546 /* give the user a chance to ^C out */
3547 intrcheck();
3548 /* interrupted, try again */
3549 opipe = block_pipe();
3550 continue;
3551 }
3552 if (errno == EPIPE) {
3553 /* fake receiving signal */
3554 rv = ksh_sigmask(SIGPIPE);
3555 } else {
3556 /* an error occured during writing */
3557 bi_errorf(Tf_sD_s, "<stdout>",
3558 cstrerror(errno));
3559 rv = 1;
3560 }
3561 if (fd != STDIN_FILENO)
3562 close(fd);
3563 goto out;
3564 }
3565 }
3566 if (fd != STDIN_FILENO)
3567 close(fd);
3568 } while (*wp);
3569
3570 out:
3571 if (opipe)
3572 restore_pipe();
3573 free_osfunc(buf);
3574 return (rv);
3575 }
3576
3577 #if HAVE_SELECT
3578 int
c_sleep(const char ** wp)3579 c_sleep(const char **wp)
3580 {
3581 struct timeval tv;
3582 int rv = 1;
3583
3584 /* skip argv[0] */
3585 ++wp;
3586 if (wp[0] && !strcmp(wp[0], "--"))
3587 /* skip "--" (options separator) */
3588 ++wp;
3589
3590 if (!wp[0] || wp[1])
3591 bi_errorf(Tsynerr);
3592 else if (parse_usec(wp[0], &tv))
3593 bi_errorf(Tf_sD_s_qs, Tsynerr, cstrerror(errno), wp[0]);
3594 else {
3595 #ifndef MKSH_NOPROSPECTOFWORK
3596 sigset_t omask, bmask;
3597
3598 /* block a number of signals from interrupting us, though */
3599 (void)sigemptyset(&bmask);
3600 (void)sigaddset(&bmask, SIGPIPE);
3601 (void)sigaddset(&bmask, SIGCHLD);
3602 #ifdef SIGWINCH
3603 (void)sigaddset(&bmask, SIGWINCH);
3604 #endif
3605 #ifdef SIGINFO
3606 (void)sigaddset(&bmask, SIGINFO);
3607 #endif
3608 #ifdef SIGUSR1
3609 (void)sigaddset(&bmask, SIGUSR1);
3610 #endif
3611 #ifdef SIGUSR2
3612 (void)sigaddset(&bmask, SIGUSR2);
3613 #endif
3614 sigprocmask(SIG_BLOCK, &bmask, &omask);
3615 #endif
3616 if (select(1, NULL, NULL, NULL, &tv) == 0 || errno == EINTR)
3617 /*
3618 * strictly speaking only for SIGALRM, but the
3619 * execution may be interrupted by other signals
3620 */
3621 rv = 0;
3622 else
3623 bi_errorf(Tf_sD_s, Tselect, cstrerror(errno));
3624 #ifndef MKSH_NOPROSPECTOFWORK
3625 /* this will re-schedule signal delivery */
3626 sigprocmask(SIG_SETMASK, &omask, NULL);
3627 #endif
3628 }
3629 return (rv);
3630 }
3631 #endif
3632
3633 #if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
3634 static int
c_suspend(const char ** wp)3635 c_suspend(const char **wp)
3636 {
3637 if (wp[1] != NULL) {
3638 bi_errorf(Ttoo_many_args);
3639 return (1);
3640 }
3641 if (Flag(FLOGIN)) {
3642 /* Can't suspend an orphaned process group. */
3643 if (getpgid(kshppid) == getpgid(0) ||
3644 getsid(kshppid) != getsid(0)) {
3645 bi_errorf("can't suspend a login shell");
3646 return (1);
3647 }
3648 }
3649 j_suspend();
3650 return (0);
3651 }
3652 #endif
3653