1 /* $OpenBSD: c_ksh.c,v 1.61 2018/05/18 13:25:20 benno Exp $ */
4 * built-in Korn commands: c_*
20 int physical
= Flag(FPHYSICAL
);
21 int cdnode
; /* was a node from cdpath added in? */
22 int printpath
= 0; /* print where we cd'd? */
24 struct tbl
*pwd_s
, *oldpwd_s
;
27 char *dir
, *try, *pwd
;
32 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "LP")) != -1)
43 wp
+= builtin_opt
.optind
;
45 if (Flag(FRESTRICTED
)) {
46 bi_errorf("restricted shell - can't cd");
50 pwd_s
= global("PWD");
51 oldpwd_s
= global("OLDPWD");
54 /* No arguments - go home */
55 if ((dir
= str_val(global("HOME"))) == null
) {
56 bi_errorf("no home directory (HOME not set)");
60 /* One argument: - or dir */
62 if (strcmp(dir
, "-") == 0) {
63 dir
= str_val(oldpwd_s
);
65 bi_errorf("no OLDPWD");
71 /* Two arguments - substitute arg1 in PWD for arg2 */
72 int ilen
, olen
, nlen
, elen
;
76 bi_errorf("don't know current directory");
79 /* substitute arg1 for arg2 in current path.
80 * if the first substitution fails because the cd fails
81 * we could try to find another substitution. For now
84 if ((cp
= strstr(current_wd
, wp
[0])) == NULL
) {
85 bi_errorf("bad substitution");
88 ilen
= cp
- current_wd
;
91 elen
= strlen(current_wd
+ ilen
+ olen
) + 1;
92 fdir
= dir
= alloc(ilen
+ nlen
+ elen
, ATEMP
);
93 memcpy(dir
, current_wd
, ilen
);
94 memcpy(dir
+ ilen
, wp
[1], nlen
);
95 memcpy(dir
+ ilen
+ nlen
, current_wd
+ ilen
+ olen
, elen
);
98 bi_errorf("too many arguments");
102 Xinit(xs
, xp
, PATH_MAX
, ATEMP
);
103 /* xp will have a bogus value after make_path() - set it to 0
104 * so that if it's used, it will cause a dump
108 cdpath
= str_val(global("CDPATH"));
110 cdnode
= make_path(current_wd
, dir
, &cdpath
, &xs
, &phys_path
);
112 rval
= chdir(try = Xstring(xs
, xp
) + phys_path
);
114 simplify_path(Xstring(xs
, xp
));
115 rval
= chdir(try = Xstring(xs
, xp
));
117 } while (rval
< 0 && cdpath
!= NULL
);
121 bi_errorf("%s: bad directory", dir
);
123 bi_errorf("%s - %s", try, strerror(errno
));
128 /* Clear out tracked aliases with relative paths */
131 /* Set OLDPWD (note: unsetting OLDPWD does not disable this
132 * setting in at&t ksh)
135 /* Ignore failure (happens if readonly or integer) */
136 setstr(oldpwd_s
, current_wd
, KSH_RETURN_ERROR
);
138 if (Xstring(xs
, xp
)[0] != '/') {
141 if (!physical
|| !(pwd
= get_phys_path(Xstring(xs
, xp
))))
142 pwd
= Xstring(xs
, xp
);
147 set_current_wd(ptmp
);
148 /* Ignore failure (happens if readonly or integer) */
149 setstr(pwd_s
, ptmp
, KSH_RETURN_ERROR
);
151 set_current_wd(null
);
152 pwd
= Xstring(xs
, xp
);
153 /* XXX unset $PWD? */
155 if (printpath
|| cdnode
)
156 shprintf("%s\n", pwd
);
167 int physical
= Flag(FPHYSICAL
);
168 char *p
, *freep
= NULL
;
170 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "LP")) != -1)
181 wp
+= builtin_opt
.optind
;
184 bi_errorf("too many arguments");
187 p
= current_wd
[0] ? (physical
? get_phys_path(current_wd
) : current_wd
) :
189 if (p
&& access(p
, R_OK
) < 0)
192 freep
= p
= ksh_get_wd(NULL
, 0);
194 bi_errorf("can't get current directory - %s",
207 #define PO_NL BIT(0) /* print newline */
208 #define PO_EXPAND BIT(1) /* expand backslash sequences */
209 #define PO_PMINUSMINUS BIT(2) /* print a -- argument */
210 #define PO_HIST BIT(3) /* print to history instead of stdout */
211 #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
213 int flags
= PO_EXPAND
|PO_NL
;
219 if (wp
[0][0] == 'e') { /* echo command */
222 /* A compromise between sysV and BSD echo commands:
223 * escape sequences are enabled by default, and
224 * -n, -e and -E are recognized if they appear
225 * in arguments with no illegal options (ie, echo -nq
227 * Different from sysV echo since options are recognized,
228 * different from BSD echo since escape sequences are enabled
233 if (*wp
&& strcmp(*wp
, "-n") == 0) {
238 while ((s
= *wp
) && *s
== '-' && s
[1]) {
245 nflags
&= ~PO_EXPAND
;
247 /* bad option: don't use
248 * nflags, print argument
259 const char *options
= "Rnprsu,";
260 while ((optc
= ksh_getopt(wp
, &builtin_opt
, options
)) != -1)
262 case 'R': /* fake BSD echo command */
263 flags
|= PO_PMINUSMINUS
;
274 if ((fd
= coproc_getfd(W_OK
, &emsg
)) < 0) {
275 bi_errorf("-p: %s", emsg
);
286 if (!*(s
= builtin_opt
.optarg
))
288 else if ((fd
= check_fd(s
, W_OK
, &emsg
)) < 0) {
289 bi_errorf("-u: %s: %s", s
, emsg
);
296 if (!(builtin_opt
.info
& GI_MINUSMINUS
)) {
297 /* treat a lone - like -- */
298 if (wp
[builtin_opt
.optind
] &&
299 strcmp(wp
[builtin_opt
.optind
], "-") == 0)
300 builtin_opt
.optind
++;
301 } else if (flags
& PO_PMINUSMINUS
)
302 builtin_opt
.optind
--;
303 wp
+= builtin_opt
.optind
;
306 Xinit(xs
, xp
, 128, ATEMP
);
308 while (*wp
!= NULL
) {
311 while ((c
= *s
++) != '\0') {
313 if ((flags
& PO_EXPAND
) && c
== '\\') {
316 switch ((c
= *s
++)) {
317 /* Oddly enough, \007 seems more portable than
318 * \a (due to HP-UX cc, Ultrix cc, old pcc's,
321 case 'a': c
= '\007'; break;
322 case 'b': c
= '\b'; break;
323 case 'c': flags
&= ~PO_NL
;
324 continue; /* AT&T brain damage */
325 case 'f': c
= '\f'; break;
326 case 'n': c
= '\n'; break;
327 case 'r': c
= '\r'; break;
328 case 't': c
= '\t'; break;
329 case 'v': c
= 0x0B; break;
331 /* Look for an octal number: can have
332 * three digits (not counting the
333 * leading 0). Truly burnt.
336 for (i
= 0; i
< 3; i
++) {
337 if (*s
>= '0' && *s
<= '7')
338 c
= c
*8 + *s
++ - '0';
343 case '\0': s
--; c
= '\\'; break;
357 if (flags
& PO_HIST
) {
360 histsave(source
->line
, Xstring(xs
, xp
), 1);
363 int n
, len
= Xlength(xs
, xp
);
366 /* Ensure we aren't killed by a SIGPIPE while writing to
367 * a coprocess. at&t ksh doesn't seem to do this (seems
368 * to just check that the co-process is alive, which is
371 if (coproc
.write
>= 0 && coproc
.write
== fd
) {
373 opipe
= block_pipe();
375 for (s
= Xstring(xs
, xp
); len
> 0; ) {
376 n
= write(fd
, s
, len
);
378 if (flags
& PO_COPROC
)
380 if (errno
== EINTR
) {
381 /* allow user to ^C out */
383 if (flags
& PO_COPROC
)
384 opipe
= block_pipe();
387 /* This doesn't really make sense - could
388 * break scripts (print -p generates
391 * coproc_write_close(fd);
398 if (flags
& PO_COPROC
)
410 int pflag
= 0, vflag
= 0, Vflag
= 0;
418 case 'c': /* command */
425 case 'w': /* whence */
430 bi_errorf("builtin not handled by %s", __func__
);
434 while ((optc
= ksh_getopt(wp
, &builtin_opt
, options
)) != -1)
448 wp
+= builtin_opt
.optind
;
450 fcflags
= FC_BI
| FC_PATH
| FC_FUNC
;
452 /* Note that -p on its own is dealt with in comexec() */
454 fcflags
|= FC_DEFPATH
;
455 /* Convert command options to whence options. Note that
456 * command -pV and command -pv use a different path search
457 * than whence -v or whence -pv. This should be considered
462 fcflags
&= ~(FC_BI
| FC_FUNC
);
464 while ((vflag
|| ret
== 0) && (id
= *wp
++) != NULL
) {
466 if (!iam_whence
|| !pflag
)
467 tp
= ktsearch(&keywords
, id
, hash(id
));
468 if (!tp
&& (!iam_whence
|| !pflag
)) {
469 tp
= ktsearch(&aliases
, id
, hash(id
));
470 if (tp
&& !(tp
->flag
& ISSET
))
474 tp
= findcom(id
, fcflags
);
475 if (vflag
|| (tp
->type
!= CALIAS
&& tp
->type
!= CEXEC
&&
476 tp
->type
!= CTALIAS
))
481 shprintf(" is a reserved word");
485 shprintf(" is an %salias for ",
486 (tp
->flag
& EXPORT
) ? "exported " : "");
487 if (!iam_whence
&& !vflag
)
488 shprintf("alias %s=", id
);
489 print_value_quoted(tp
->val
.s
);
494 if (tp
->flag
& EXPORT
)
495 shprintf("n exported");
496 if (tp
->flag
& TRACE
)
498 if (!(tp
->flag
& ISSET
)) {
499 shprintf(" undefined");
501 shprintf(" (autoload from %s)",
504 shprintf(" function");
509 shprintf(" is a%s shell builtin",
510 (tp
->flag
& SPEC_BI
) ? " special" : "");
514 if (tp
->flag
& ISSET
) {
517 if (tp
->type
== CTALIAS
)
518 shprintf("a tracked %salias for ",
519 (tp
->flag
& EXPORT
) ?
522 shprintf("%s", tp
->val
.s
);
525 shprintf(" not found");
530 shprintf("%s is *GOK*", id
);
539 /* Deal with command -vV - command -p dealt with in comexec() */
543 /* Let c_whence do the work. Note that c_command() must be
544 * a distinct function from c_whence() (tested in comexec()).
552 /* Let c_whence do the work. type = command -V = whence -v */
556 /* typeset, export, and readonly */
562 int fset
= 0, fclr
= 0, thing
= 0, func
= 0, local
= 0, pflag
= 0;
563 const char *options
= "L#R#UZ#fi#lprtux"; /* see comment below */
564 char *fieldstr
, *basestr
;
565 int field
, base
, optc
, flag
;
568 case 'e': /* export */
572 case 'r': /* readonly */
577 /* called with 'typeset -' */
579 case 't': /* typeset */
584 fieldstr
= basestr
= NULL
;
585 builtin_opt
.flags
|= GF_PLUSOPT
;
586 /* at&t ksh seems to have 0-9 as options, which are multiplied
587 * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
588 * sets right justify in a field of 12). This allows options
589 * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
590 * does not allow the number to be specified as a separate argument
591 * Here, the number must follow the RLZi option, but is optional
592 * (see the # kludge in ksh_getopt()).
594 while ((optc
= ksh_getopt(wp
, &builtin_opt
, options
)) != -1) {
599 fieldstr
= builtin_opt
.optarg
;
603 fieldstr
= builtin_opt
.optarg
;
606 /* at&t ksh uses u, but this conflicts with
607 * upper/lower case. If this option is changed,
608 * need to change the -U below as well
614 fieldstr
= builtin_opt
.optarg
;
621 basestr
= builtin_opt
.optarg
;
627 /* posix export/readonly -p flag.
628 * typeset -p is the same as typeset (in pdksh);
629 * here for compatibility with ksh93.
640 flag
= UCASEV_AL
; /* upper case / autoload */
648 if (builtin_opt
.info
& GI_PLUS
) {
660 if (fieldstr
&& !bi_getn(fieldstr
, &field
))
663 if (basestr
&& !bi_getn(basestr
, &base
))
666 if (!(builtin_opt
.info
& GI_MINUSMINUS
) && wp
[builtin_opt
.optind
] &&
667 (wp
[builtin_opt
.optind
][0] == '-' ||
668 wp
[builtin_opt
.optind
][0] == '+') &&
669 wp
[builtin_opt
.optind
][1] == '\0') {
670 thing
= wp
[builtin_opt
.optind
][0];
671 builtin_opt
.optind
++;
674 if (func
&& ((fset
|fclr
) & ~(TRACE
|UCASEV_AL
|EXPORT
))) {
675 bi_errorf("only -t, -u and -x options may be used with -f");
678 if (wp
[builtin_opt
.optind
]) {
679 /* Take care of exclusions.
680 * At this point, flags in fset are cleared in fclr and vise
681 * versa. This property should be preserved.
683 if (fset
& LCASEV
) /* LCASEV has priority over UCASEV_AL */
685 if (fset
& LJUST
) /* LJUST has priority over RJUST */
687 if ((fset
& (ZEROFIL
|LJUST
)) == ZEROFIL
) { /* -Z implies -ZR */
691 /* Setting these attributes clears the others, unless they
692 * are also set in this command
694 if (fset
& (LJUST
| RJUST
| ZEROFIL
| UCASEV_AL
| LCASEV
|
695 INTEGER
| INT_U
| INT_L
))
696 fclr
|= ~fset
& (LJUST
| RJUST
| ZEROFIL
| UCASEV_AL
|
697 LCASEV
| INTEGER
| INT_U
| INT_L
);
700 /* set variables and attributes */
701 if (wp
[builtin_opt
.optind
]) {
708 for (i
= builtin_opt
.optind
; wp
[i
]; i
++) {
710 f
= findfunc(wp
[i
], hash(wp
[i
]),
711 (fset
&UCASEV_AL
) ? true : false);
713 /* at&t ksh does ++rval: bogus */
721 fptreef(shl_stdout
, 0,
724 "%s() %T\n", wp
[i
], f
->val
.t
);
725 } else if (!typeset(wp
[i
], fset
, fclr
, field
, base
)) {
726 bi_errorf("%s: not identifier", wp
[i
]);
733 /* list variables and attributes */
734 flag
= fset
| fclr
; /* no difference at this point.. */
736 for (l
= genv
->loc
; l
; l
= l
->next
) {
737 for (p
= ktsort(&l
->funs
); (vp
= *p
++); ) {
738 if (flag
&& (vp
->flag
& flag
) == 0)
741 fptreef(shl_stdout
, 0, vp
->flag
& FKSH
?
742 "function %s %T\n" : "%s() %T\n",
743 vp
->name
, vp
->val
.t
);
745 shprintf("%s\n", vp
->name
);
749 for (l
= genv
->loc
; l
; l
= l
->next
) {
750 for (p
= ktsort(&l
->vars
); (vp
= *p
++); ) {
754 * See if the parameter is set (for arrays, if any
757 for (tvp
= vp
; tvp
; tvp
= tvp
->u
.array
)
758 if (tvp
->flag
& ISSET
) {
764 * Check attributes - note that all array elements
765 * have (should have?) the same attributes, so checking
766 * the first is sufficient.
768 * Report an unset param only if the user has
769 * explicitly given it some attribute (like export);
770 * otherwise, after "echo $FOO", we would report FOO...
772 if (!any_set
&& !(vp
->flag
& USERATTRIB
))
774 if (flag
&& (vp
->flag
& flag
) == 0)
776 for (; vp
; vp
= vp
->u
.array
) {
777 /* Ignore array elements that aren't
778 * set unless there are no set elements,
779 * in which case the first is reported on */
780 if ((vp
->flag
&ARRAY
) && any_set
&&
784 if (thing
== 0 && flag
== 0) {
785 /* at&t ksh prints things
786 * like export, integer,
787 * leftadj, zerofill, etc.,
788 * but POSIX says must
789 * be suitable for re-entry...
791 shprintf("typeset ");
792 if ((vp
->flag
&INTEGER
))
794 if ((vp
->flag
&EXPORT
))
796 if ((vp
->flag
&RDONLY
))
798 if ((vp
->flag
&TRACE
))
800 if ((vp
->flag
&LJUST
))
801 shprintf("-L%d ", vp
->u2
.field
);
802 if ((vp
->flag
&RJUST
))
803 shprintf("-R%d ", vp
->u2
.field
);
804 if ((vp
->flag
&ZEROFIL
))
806 if ((vp
->flag
&LCASEV
))
808 if ((vp
->flag
&UCASEV_AL
))
810 if ((vp
->flag
&INT_U
))
812 shprintf("%s\n", vp
->name
);
819 "export" : "readonly");
820 if ((vp
->flag
&ARRAY
) && any_set
)
822 vp
->name
, vp
->index
);
824 shprintf("%s", vp
->name
);
825 if (thing
== '-' && (vp
->flag
&ISSET
)) {
826 char *s
= str_val(vp
);
829 /* at&t ksh can't have
830 * justified integers.. */
832 (INTEGER
|LJUST
|RJUST
)) ==
836 print_value_quoted(s
);
840 /* Only report first `element' of an array with
855 struct table
*t
= &aliases
;
856 int rv
= 0, rflag
= 0, tflag
, Uflag
= 0, pflag
= 0, prefix
= 0;
860 builtin_opt
.flags
|= GF_PLUSOPT
;
861 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "dprtUx")) != -1) {
862 prefix
= builtin_opt
.info
& GI_PLUS
? '+' : '-';
878 * kludge for tracked alias initialization
879 * (don't do a path search, just make an entry)
890 wp
+= builtin_opt
.optind
;
892 if (!(builtin_opt
.info
& GI_MINUSMINUS
) && *wp
&&
893 (wp
[0][0] == '-' || wp
[0][0] == '+') && wp
[0][1] == '\0') {
898 tflag
= t
== &taliases
;
900 /* "hash -r" means reset all the tracked aliases.. */
902 static const char *const args
[] = {
903 "unalias", "-ta", NULL
907 shprintf("alias: -r flag can only be used with -t"
908 " and without arguments\n");
911 ksh_getopt_reset(&builtin_opt
, GF_ERROR
);
912 return c_unalias((char **) args
);
918 for (p
= ktsort(t
); (ap
= *p
++) != NULL
; )
919 if ((ap
->flag
& (ISSET
|xflag
)) == (ISSET
|xflag
)) {
921 shf_puts("alias ", shl_stdout
);
922 shf_puts(ap
->name
, shl_stdout
);
924 shf_putc('=', shl_stdout
);
925 print_value_quoted(ap
->val
.s
);
931 for (; *wp
!= NULL
; wp
++) {
933 char *val
= strchr(alias
, '=');
939 alias
= str_nsave(alias
, val
++ - alias
, ATEMP
);
941 if (val
== NULL
&& !tflag
&& !xflag
) {
942 ap
= ktsearch(t
, alias
, h
);
943 if (ap
!= NULL
&& (ap
->flag
&ISSET
)) {
945 shf_puts("alias ", shl_stdout
);
946 shf_puts(ap
->name
, shl_stdout
);
948 shf_putc('=', shl_stdout
);
949 print_value_quoted(ap
->val
.s
);
953 shprintf("%s alias not found\n", alias
);
958 ap
= ktenter(t
, alias
, h
);
959 ap
->type
= tflag
? CTALIAS
: CALIAS
;
960 /* Are we setting the value or just some flags? */
961 if ((val
&& !tflag
) || (!val
&& tflag
&& !Uflag
)) {
962 if (ap
->flag
&ALLOC
) {
963 ap
->flag
&= ~(ALLOC
|ISSET
);
964 afree(ap
->val
.s
, APERM
);
966 /* ignore values for -t (at&t ksh does this) */
967 newval
= tflag
? search(alias
, search_path
, X_OK
, NULL
)
970 ap
->val
.s
= str_save(newval
, APERM
);
971 ap
->flag
|= ALLOC
|ISSET
;
990 struct table
*t
= &aliases
;
995 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "adt")) != -1)
1009 wp
+= builtin_opt
.optind
;
1011 for (; *wp
!= NULL
; wp
++) {
1012 ap
= ktsearch(t
, *wp
, hash(*wp
));
1017 if (ap
->flag
&ALLOC
) {
1018 ap
->flag
&= ~(ALLOC
|ISSET
);
1019 afree(ap
->val
.s
, APERM
);
1021 ap
->flag
&= ~(DEFINED
|ISSET
|EXPORT
);
1027 for (ktwalk(&ts
, t
); (ap
= ktnext(&ts
)); ) {
1028 if (ap
->flag
&ALLOC
) {
1029 ap
->flag
&= ~(ALLOC
|ISSET
);
1030 afree(ap
->val
.s
, APERM
);
1032 ap
->flag
&= ~(DEFINED
|ISSET
|EXPORT
);
1045 if (wp
[1] == NULL
) /* at&t ksh does this */
1046 bi_errorf("no arguments");
1048 for (wp
++; *wp
; wp
++)
1049 if (!evaluate(*wp
, &val
, KSH_RETURN_ERROR
, true)) {
1050 rv
= 2; /* distinguish error from zero result */
1065 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "lpnz")) != -1)
1076 case 'z': /* debugging: print zombies */
1082 wp
+= builtin_opt
.optind
;
1084 if (j_jobs(NULL
, flag
, nflag
))
1088 if (j_jobs(*wp
, flag
, nflag
))
1097 int bg
= strcmp(*wp
, "bg") == 0;
1100 if (!Flag(FMONITOR
)) {
1101 bi_errorf("job control not enabled");
1104 if (ksh_getopt(wp
, &builtin_opt
, null
) == '?')
1106 wp
+= builtin_opt
.optind
;
1109 rv
= j_resume(*wp
, bg
);
1111 rv
= j_resume("%%", bg
);
1112 /* POSIX says fg shall return 0 (unless an error occurs).
1113 * at&t ksh returns the exit value of the job...
1115 return (bg
|| Flag(FPOSIX
)) ? 0 : rv
;
1122 static char *kill_fmt_entry(void *arg
, int i
, char *buf
, int buflen
);
1124 /* format a single kill item */
1126 kill_fmt_entry(void *arg
, int i
, char *buf
, int buflen
)
1128 struct kill_info
*ki
= (struct kill_info
*) arg
;
1131 if (sigtraps
[i
].name
)
1132 shf_snprintf(buf
, buflen
, "%*d %*s %s",
1134 ki
->name_width
, sigtraps
[i
].name
,
1137 shf_snprintf(buf
, buflen
, "%*d %*d %s",
1139 ki
->name_width
, sigtraps
[i
].signal
,
1153 /* assume old style options if -digits or -UPPERCASE */
1154 if ((p
= wp
[1]) && *p
== '-' &&
1155 (digit(p
[1]) || isupper((unsigned char)p
[1]))) {
1156 if (!(t
= gettrap(p
+ 1, true))) {
1157 bi_errorf("bad signal `%s'", p
+ 1);
1160 i
= (wp
[2] && strcmp(wp
[2], "--") == 0) ? 3 : 2;
1164 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "ls:")) != -1)
1170 if (!(t
= gettrap(builtin_opt
.optarg
, true))) {
1171 bi_errorf("bad signal `%s'",
1172 builtin_opt
.optarg
);
1179 i
= builtin_opt
.optind
;
1181 if ((lflag
&& t
) || (!wp
[i
] && !lflag
)) {
1182 shf_fprintf(shl_out
,
1183 "usage: kill [-s signame | -signum | -signame] { job | pid | pgrp } ...\n"
1184 " kill -l [exit_status ...]\n");
1191 for (; wp
[i
]; i
++) {
1192 if (!bi_getn(wp
[i
], &n
))
1194 if (n
> 128 && n
< 128 + NSIG
)
1196 if (n
> 0 && n
< NSIG
&& sigtraps
[n
].name
)
1197 shprintf("%s\n", sigtraps
[n
].name
);
1199 shprintf("%d\n", n
);
1201 } else if (Flag(FPOSIX
)) {
1203 for (i
= 1; i
< NSIG
; i
++, p
= " ")
1204 if (sigtraps
[i
].name
)
1205 shprintf("%s%s", p
, sigtraps
[i
].name
);
1208 int mess_width
= 0, w
;
1209 struct kill_info ki
= {
1214 for (i
= NSIG
; i
>= 10; i
/= 10)
1217 for (i
= 0; i
< NSIG
; i
++) {
1218 w
= sigtraps
[i
].name
?
1219 (int)strlen(sigtraps
[i
].name
) :
1221 if (w
> ki
.name_width
)
1223 w
= strlen(sigtraps
[i
].mess
);
1228 print_columns(shl_stdout
, NSIG
- 1,
1229 kill_fmt_entry
, (void *) &ki
,
1230 ki
.num_width
+ ki
.name_width
+ mess_width
+ 3, 1);
1235 sig
= t
? t
->signal
: SIGTERM
;
1236 for (; (p
= wp
[i
]); i
++) {
1240 } else if (!getn(p
, &n
)) {
1241 bi_errorf("%s: arguments must be jobs or process IDs",
1245 /* use killpg if < -1 since -1 does special things for
1246 * some non-killpg-endowed kills
1248 if ((n
< -1 ? killpg(-n
, sig
) : kill(n
, sig
)) < 0) {
1249 bi_errorf("%s: %s", p
, strerror(errno
));
1258 getopts_reset(int val
)
1261 ksh_getopt_reset(&user_opt
,
1262 GF_NONAME
| (Flag(FPOSIX
) ? 0 : GF_PLUSOPT
));
1263 user_opt
.optind
= user_opt
.uoptind
= val
;
1268 c_getopts(char **wp
)
1271 const char *options
;
1276 struct tbl
*vq
, *voptarg
;
1278 if (ksh_getopt(wp
, &builtin_opt
, null
) == '?')
1280 wp
+= builtin_opt
.optind
;
1284 bi_errorf("missing options argument");
1290 bi_errorf("missing name argument");
1293 if (!*var
|| *skip_varname(var
, true)) {
1294 bi_errorf("%s: is not an identifier", var
);
1298 if (genv
->loc
->next
== NULL
) {
1299 internal_warningf("%s: no argv", __func__
);
1302 /* Which arguments are we parsing... */
1304 wp
= genv
->loc
->next
->argv
;
1306 *--wp
= genv
->loc
->next
->argv
[0];
1308 /* Check that our saved state won't cause a core dump... */
1309 for (argc
= 0; wp
[argc
]; argc
++)
1311 if (user_opt
.optind
> argc
||
1313 user_opt
.p
> strlen(wp
[user_opt
.optind
- 1]))) {
1314 bi_errorf("arguments changed since last call");
1318 user_opt
.optarg
= NULL
;
1319 optc
= ksh_getopt(wp
, &user_opt
, options
);
1321 if (optc
>= 0 && optc
!= '?' && (user_opt
.info
& GI_PLUS
)) {
1326 /* POSIX says var is set to ? at end-of-options, at&t ksh
1327 * sets it to null - we go with POSIX...
1329 buf
[0] = optc
< 0 ? '?' : optc
;
1333 /* at&t ksh does not change OPTIND if it was an unknown option.
1334 * Scripts counting on this are prone to break... (ie, don't count
1338 user_opt
.uoptind
= user_opt
.optind
;
1341 voptarg
= global("OPTARG");
1342 voptarg
->flag
&= ~RDONLY
; /* at&t ksh clears ro and int */
1343 /* Paranoia: ensure no bizarre results. */
1344 if (voptarg
->flag
& INTEGER
)
1345 typeset("OPTARG", 0, INTEGER
, 0, 0);
1346 if (user_opt
.optarg
== NULL
)
1349 /* This can't fail (have cleared readonly/integer) */
1350 setstr(voptarg
, user_opt
.optarg
, KSH_RETURN_ERROR
);
1355 /* Error message already printed (integer, readonly) */
1356 if (!setstr(vq
, buf
, KSH_RETURN_ERROR
))
1359 typeset(var
, EXPORT
, 0, 0, 0);
1361 return optc
< 0 ? 1 : ret
;
1368 int optc
, rv
= 0, macro
= 0, list
= 0;
1371 while ((optc
= ksh_getopt(wp
, &builtin_opt
, "lm")) != -1)
1382 wp
+= builtin_opt
.optind
;
1384 if (*wp
== NULL
) /* list all */
1385 rv
= x_bind(NULL
, NULL
, 0, list
);
1387 for (; *wp
!= NULL
; wp
++) {
1388 cp
= strchr(*wp
, '=');
1391 if (x_bind(*wp
, cp
, macro
, 0))
1399 /* A leading = means assignments before command are kept;
1400 * a leading * means a POSIX special builtin;
1401 * a leading + means a POSIX regular builtin
1402 * (* and + should not be combined).
1404 const struct builtin kshbuiltins
[] = {
1405 {"+alias", c_alias
}, /* no =: at&t manual wrong */
1407 {"+command", c_command
},
1409 {"*=export", c_typeset
},
1411 {"+getopts", c_getopts
},
1417 {"*=readonly", c_typeset
},
1419 {"=typeset", c_typeset
},
1420 {"+unalias", c_unalias
},
1421 {"whence", c_whence
},