1 1.30 christos /* $NetBSD: c_ksh.c,v 1.30 2021/09/16 19:43:33 christos Exp $ */ 2 1.2 tls 3 1.1 jtc /* 4 1.1 jtc * built-in Korn commands: c_* 5 1.1 jtc */ 6 1.8 agc #include <sys/cdefs.h> 7 1.8 agc 8 1.8 agc #ifndef lint 9 1.30 christos __RCSID("$NetBSD: c_ksh.c,v 1.30 2021/09/16 19:43:33 christos Exp $"); 10 1.8 agc #endif 11 1.1 jtc 12 1.25 kamil #include <sys/stat.h> 13 1.25 kamil #include <ctype.h> 14 1.25 kamil 15 1.1 jtc #include "sh.h" 16 1.1 jtc 17 1.1 jtc int 18 1.1 jtc c_cd(wp) 19 1.1 jtc char **wp; 20 1.1 jtc { 21 1.1 jtc int optc; 22 1.1 jtc int physical = Flag(FPHYSICAL); 23 1.1 jtc int cdnode; /* was a node from cdpath added in? */ 24 1.1 jtc int printpath = 0; /* print where we cd'd? */ 25 1.1 jtc int rval; 26 1.1 jtc struct tbl *pwd_s, *oldpwd_s; 27 1.1 jtc XString xs; 28 1.1 jtc char *xp; 29 1.1 jtc char *dir, *try, *pwd; 30 1.1 jtc int phys_path; 31 1.1 jtc char *cdpath; 32 1.14 christos char *fdir = NULL; 33 1.1 jtc 34 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF) 35 1.1 jtc switch (optc) { 36 1.1 jtc case 'L': 37 1.1 jtc physical = 0; 38 1.1 jtc break; 39 1.1 jtc case 'P': 40 1.1 jtc physical = 1; 41 1.1 jtc break; 42 1.1 jtc case '?': 43 1.1 jtc return 1; 44 1.1 jtc } 45 1.1 jtc wp += builtin_opt.optind; 46 1.1 jtc 47 1.1 jtc if (Flag(FRESTRICTED)) { 48 1.1 jtc bi_errorf("restricted shell - can't cd"); 49 1.1 jtc return 1; 50 1.1 jtc } 51 1.1 jtc 52 1.1 jtc pwd_s = global("PWD"); 53 1.1 jtc oldpwd_s = global("OLDPWD"); 54 1.1 jtc 55 1.1 jtc if (!wp[0]) { 56 1.1 jtc /* No arguments - go home */ 57 1.1 jtc if ((dir = str_val(global("HOME"))) == null) { 58 1.1 jtc bi_errorf("no home directory (HOME not set)"); 59 1.1 jtc return 1; 60 1.1 jtc } 61 1.1 jtc } else if (!wp[1]) { 62 1.1 jtc /* One argument: - or dir */ 63 1.1 jtc dir = wp[0]; 64 1.1 jtc if (strcmp(dir, "-") == 0) { 65 1.1 jtc dir = str_val(oldpwd_s); 66 1.1 jtc if (dir == null) { 67 1.1 jtc bi_errorf("no OLDPWD"); 68 1.1 jtc return 1; 69 1.1 jtc } 70 1.1 jtc printpath++; 71 1.1 jtc } 72 1.1 jtc } else if (!wp[2]) { 73 1.1 jtc /* Two arguments - substitute arg1 in PWD for arg2 */ 74 1.1 jtc int ilen, olen, nlen, elen; 75 1.1 jtc char *cp; 76 1.1 jtc 77 1.1 jtc if (!current_wd[0]) { 78 1.1 jtc bi_errorf("don't know current directory"); 79 1.1 jtc return 1; 80 1.1 jtc } 81 1.11 mycroft /* substitute arg1 for arg2 in current path. 82 1.1 jtc * if the first substitution fails because the cd fails 83 1.1 jtc * we could try to find another substitution. For now 84 1.1 jtc * we don't 85 1.1 jtc */ 86 1.1 jtc if ((cp = strstr(current_wd, wp[0])) == (char *) 0) { 87 1.1 jtc bi_errorf("bad substitution"); 88 1.1 jtc return 1; 89 1.1 jtc } 90 1.1 jtc ilen = cp - current_wd; 91 1.1 jtc olen = strlen(wp[0]); 92 1.1 jtc nlen = strlen(wp[1]); 93 1.1 jtc elen = strlen(current_wd + ilen + olen) + 1; 94 1.14 christos fdir = dir = alloc(ilen + nlen + elen, ATEMP); 95 1.1 jtc memcpy(dir, current_wd, ilen); 96 1.1 jtc memcpy(dir + ilen, wp[1], nlen); 97 1.1 jtc memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen); 98 1.1 jtc printpath++; 99 1.1 jtc } else { 100 1.1 jtc bi_errorf("too many arguments"); 101 1.1 jtc return 1; 102 1.1 jtc } 103 1.1 jtc 104 1.1 jtc Xinit(xs, xp, PATH, ATEMP); 105 1.1 jtc /* xp will have a bogus value after make_path() - set it to 0 106 1.1 jtc * so that if it's used, it will cause a dump 107 1.1 jtc */ 108 1.1 jtc xp = (char *) 0; 109 1.1 jtc 110 1.1 jtc cdpath = str_val(global("CDPATH")); 111 1.1 jtc do { 112 1.1 jtc cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path); 113 1.1 jtc #ifdef S_ISLNK 114 1.1 jtc if (physical) 115 1.1 jtc rval = chdir(try = Xstring(xs, xp) + phys_path); 116 1.1 jtc else 117 1.1 jtc #endif /* S_ISLNK */ 118 1.1 jtc { 119 1.1 jtc simplify_path(Xstring(xs, xp)); 120 1.1 jtc rval = chdir(try = Xstring(xs, xp)); 121 1.1 jtc } 122 1.1 jtc } while (rval < 0 && cdpath != (char *) 0); 123 1.1 jtc 124 1.1 jtc if (rval < 0) { 125 1.1 jtc if (cdnode) 126 1.1 jtc bi_errorf("%s: bad directory", dir); 127 1.1 jtc else 128 1.1 jtc bi_errorf("%s - %s", try, strerror(errno)); 129 1.14 christos if (fdir) 130 1.14 christos afree(fdir, ATEMP); 131 1.1 jtc return 1; 132 1.1 jtc } 133 1.1 jtc 134 1.1 jtc /* Clear out tracked aliases with relative paths */ 135 1.1 jtc flushcom(0); 136 1.1 jtc 137 1.5 hubertf /* Set OLDPWD (note: unsetting OLDPWD does not disable this 138 1.5 hubertf * setting in at&t ksh) 139 1.5 hubertf */ 140 1.1 jtc if (current_wd[0]) 141 1.5 hubertf /* Ignore failure (happens if readonly or integer) */ 142 1.5 hubertf setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR); 143 1.1 jtc 144 1.1 jtc if (!ISABSPATH(Xstring(xs, xp))) { 145 1.1 jtc pwd = (char *) 0; 146 1.1 jtc } else 147 1.1 jtc #ifdef S_ISLNK 148 1.1 jtc if (!physical || !(pwd = get_phys_path(Xstring(xs, xp)))) 149 1.1 jtc #endif /* S_ISLNK */ 150 1.1 jtc pwd = Xstring(xs, xp); 151 1.1 jtc 152 1.1 jtc /* Set PWD */ 153 1.1 jtc if (pwd) { 154 1.5 hubertf char *ptmp = pwd; 155 1.5 hubertf set_current_wd(ptmp); 156 1.5 hubertf /* Ignore failure (happens if readonly or integer) */ 157 1.5 hubertf setstr(pwd_s, ptmp, KSH_RETURN_ERROR); 158 1.1 jtc } else { 159 1.1 jtc set_current_wd(null); 160 1.1 jtc pwd = Xstring(xs, xp); 161 1.1 jtc /* XXX unset $PWD? */ 162 1.1 jtc } 163 1.1 jtc if (printpath || cdnode) 164 1.1 jtc shprintf("%s\n", pwd); 165 1.1 jtc 166 1.14 christos if (fdir) 167 1.14 christos afree(fdir, ATEMP); 168 1.14 christos 169 1.1 jtc return 0; 170 1.1 jtc } 171 1.1 jtc 172 1.1 jtc int 173 1.1 jtc c_pwd(wp) 174 1.1 jtc char **wp; 175 1.1 jtc { 176 1.1 jtc int optc; 177 1.1 jtc int physical = Flag(FPHYSICAL); 178 1.15 christos char *p, *freep = NULL; 179 1.1 jtc 180 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != EOF) 181 1.1 jtc switch (optc) { 182 1.1 jtc case 'L': 183 1.1 jtc physical = 0; 184 1.1 jtc break; 185 1.1 jtc case 'P': 186 1.1 jtc physical = 1; 187 1.1 jtc break; 188 1.1 jtc case '?': 189 1.1 jtc return 1; 190 1.1 jtc } 191 1.1 jtc wp += builtin_opt.optind; 192 1.1 jtc 193 1.1 jtc if (wp[0]) { 194 1.1 jtc bi_errorf("too many arguments"); 195 1.1 jtc return 1; 196 1.1 jtc } 197 1.1 jtc #ifdef S_ISLNK 198 1.1 jtc p = current_wd[0] ? (physical ? get_phys_path(current_wd) : current_wd) 199 1.1 jtc : (char *) 0; 200 1.1 jtc #else /* S_ISLNK */ 201 1.1 jtc p = current_wd[0] ? current_wd : (char *) 0; 202 1.1 jtc #endif /* S_ISLNK */ 203 1.1 jtc if (p && eaccess(p, R_OK) < 0) 204 1.1 jtc p = (char *) 0; 205 1.1 jtc if (!p) { 206 1.15 christos freep = p = ksh_get_wd((char *) 0, 0); 207 1.1 jtc if (!p) { 208 1.1 jtc bi_errorf("can't get current directory - %s", 209 1.1 jtc strerror(errno)); 210 1.1 jtc return 1; 211 1.1 jtc } 212 1.1 jtc } 213 1.1 jtc shprintf("%s\n", p); 214 1.15 christos if (freep) 215 1.15 christos afree(freep, ATEMP); 216 1.1 jtc return 0; 217 1.1 jtc } 218 1.1 jtc 219 1.1 jtc int 220 1.1 jtc c_print(wp) 221 1.1 jtc char **wp; 222 1.1 jtc { 223 1.1 jtc #define PO_NL BIT(0) /* print newline */ 224 1.1 jtc #define PO_EXPAND BIT(1) /* expand backslash sequences */ 225 1.1 jtc #define PO_PMINUSMINUS BIT(2) /* print a -- argument */ 226 1.1 jtc #define PO_HIST BIT(3) /* print to history instead of stdout */ 227 1.1 jtc #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ 228 1.1 jtc int fd = 1; 229 1.1 jtc int flags = PO_EXPAND|PO_NL; 230 1.1 jtc char *s; 231 1.1 jtc const char *emsg; 232 1.1 jtc XString xs; 233 1.1 jtc char *xp; 234 1.1 jtc 235 1.1 jtc if (wp[0][0] == 'e') { /* echo command */ 236 1.1 jtc int nflags = flags; 237 1.1 jtc 238 1.1 jtc /* A compromise between sysV and BSD echo commands: 239 1.1 jtc * escape sequences are enabled by default, and 240 1.1 jtc * -n, -e and -E are recognized if they appear 241 1.1 jtc * in arguments with no illegal options (ie, echo -nq 242 1.1 jtc * will print -nq). 243 1.1 jtc * Different from sysV echo since options are recognized, 244 1.1 jtc * different from BSD echo since escape sequences are enabled 245 1.1 jtc * by default. 246 1.1 jtc */ 247 1.1 jtc wp += 1; 248 1.1 jtc while ((s = *wp) && *s == '-' && s[1]) { 249 1.1 jtc while (*++s) 250 1.1 jtc if (*s == 'n') 251 1.1 jtc nflags &= ~PO_NL; 252 1.1 jtc else if (*s == 'e') 253 1.1 jtc nflags |= PO_EXPAND; 254 1.1 jtc else if (*s == 'E') 255 1.1 jtc nflags &= ~PO_EXPAND; 256 1.1 jtc else 257 1.1 jtc /* bad option: don't use nflags, print 258 1.1 jtc * argument 259 1.1 jtc */ 260 1.1 jtc break; 261 1.1 jtc if (*s) 262 1.1 jtc break; 263 1.1 jtc wp++; 264 1.1 jtc flags = nflags; 265 1.1 jtc } 266 1.1 jtc } else { 267 1.1 jtc int optc; 268 1.1 jtc const char *options = "Rnprsu,"; 269 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) 270 1.1 jtc switch (optc) { 271 1.1 jtc case 'R': /* fake BSD echo command */ 272 1.1 jtc flags |= PO_PMINUSMINUS; 273 1.1 jtc flags &= ~PO_EXPAND; 274 1.1 jtc options = "ne"; 275 1.1 jtc break; 276 1.1 jtc case 'e': 277 1.1 jtc flags |= PO_EXPAND; 278 1.1 jtc break; 279 1.1 jtc case 'n': 280 1.1 jtc flags &= ~PO_NL; 281 1.1 jtc break; 282 1.1 jtc #ifdef KSH 283 1.1 jtc case 'p': 284 1.1 jtc if ((fd = coproc_getfd(W_OK, &emsg)) < 0) { 285 1.1 jtc bi_errorf("-p: %s", emsg); 286 1.1 jtc return 1; 287 1.1 jtc } 288 1.1 jtc break; 289 1.1 jtc #endif /* KSH */ 290 1.1 jtc case 'r': 291 1.1 jtc flags &= ~PO_EXPAND; 292 1.1 jtc break; 293 1.1 jtc case 's': 294 1.1 jtc flags |= PO_HIST; 295 1.1 jtc break; 296 1.1 jtc case 'u': 297 1.1 jtc if (!*(s = builtin_opt.optarg)) 298 1.1 jtc fd = 0; 299 1.1 jtc else if ((fd = check_fd(s, W_OK, &emsg)) < 0) { 300 1.1 jtc bi_errorf("-u: %s: %s", s, emsg); 301 1.1 jtc return 1; 302 1.1 jtc } 303 1.1 jtc break; 304 1.1 jtc case '?': 305 1.1 jtc return 1; 306 1.1 jtc } 307 1.1 jtc if (!(builtin_opt.info & GI_MINUSMINUS)) { 308 1.1 jtc /* treat a lone - like -- */ 309 1.1 jtc if (wp[builtin_opt.optind] 310 1.1 jtc && strcmp(wp[builtin_opt.optind], "-") == 0) 311 1.1 jtc builtin_opt.optind++; 312 1.1 jtc } else if (flags & PO_PMINUSMINUS) 313 1.1 jtc builtin_opt.optind--; 314 1.1 jtc wp += builtin_opt.optind; 315 1.1 jtc } 316 1.1 jtc 317 1.1 jtc Xinit(xs, xp, 128, ATEMP); 318 1.1 jtc 319 1.1 jtc while (*wp != NULL) { 320 1.28 kamil int c; 321 1.1 jtc s = *wp; 322 1.1 jtc while ((c = *s++) != '\0') { 323 1.1 jtc Xcheck(xs, xp); 324 1.1 jtc if ((flags & PO_EXPAND) && c == '\\') { 325 1.1 jtc int i; 326 1.1 jtc 327 1.1 jtc switch ((c = *s++)) { 328 1.1 jtc /* Oddly enough, \007 seems more portable than 329 1.24 kamil * \a (due to old pcc's, 330 1.1 jtc * etc.). 331 1.1 jtc */ 332 1.1 jtc case 'a': c = '\007'; break; 333 1.1 jtc case 'b': c = '\b'; break; 334 1.1 jtc case 'c': flags &= ~PO_NL; 335 1.1 jtc continue; /* AT&T brain damage */ 336 1.1 jtc case 'f': c = '\f'; break; 337 1.1 jtc case 'n': c = '\n'; break; 338 1.1 jtc case 'r': c = '\r'; break; 339 1.1 jtc case 't': c = '\t'; break; 340 1.1 jtc case 'v': c = 0x0B; break; 341 1.1 jtc case '0': 342 1.1 jtc /* Look for an octal number: can have 343 1.1 jtc * three digits (not counting the 344 1.11 mycroft * leading 0). Truly burnt. 345 1.1 jtc */ 346 1.1 jtc c = 0; 347 1.1 jtc for (i = 0; i < 3; i++) { 348 1.1 jtc if (*s >= '0' && *s <= '7') 349 1.1 jtc c = c*8 + *s++ - '0'; 350 1.1 jtc else 351 1.1 jtc break; 352 1.1 jtc } 353 1.1 jtc break; 354 1.1 jtc case '\0': s--; c = '\\'; break; 355 1.1 jtc case '\\': break; 356 1.1 jtc default: 357 1.1 jtc Xput(xs, xp, '\\'); 358 1.1 jtc } 359 1.1 jtc } 360 1.1 jtc Xput(xs, xp, c); 361 1.1 jtc } 362 1.1 jtc if (*++wp != NULL) 363 1.1 jtc Xput(xs, xp, ' '); 364 1.1 jtc } 365 1.1 jtc if (flags & PO_NL) 366 1.1 jtc Xput(xs, xp, '\n'); 367 1.1 jtc 368 1.1 jtc if (flags & PO_HIST) { 369 1.1 jtc Xput(xs, xp, '\0'); 370 1.1 jtc source->line++; 371 1.1 jtc histsave(source->line, Xstring(xs, xp), 1); 372 1.1 jtc Xfree(xs, xp); 373 1.1 jtc } else { 374 1.1 jtc int n, len = Xlength(xs, xp); 375 1.11 mycroft int UNINITIALIZED(opipe); 376 1.1 jtc #ifdef KSH 377 1.1 jtc 378 1.1 jtc /* Ensure we aren't killed by a SIGPIPE while writing to 379 1.1 jtc * a coprocess. at&t ksh doesn't seem to do this (seems 380 1.1 jtc * to just check that the co-process is alive, which is 381 1.1 jtc * not enough). 382 1.1 jtc */ 383 1.1 jtc if (coproc.write >= 0 && coproc.write == fd) { 384 1.1 jtc flags |= PO_COPROC; 385 1.1 jtc opipe = block_pipe(); 386 1.1 jtc } 387 1.1 jtc #endif /* KSH */ 388 1.1 jtc for (s = Xstring(xs, xp); len > 0; ) { 389 1.1 jtc n = write(fd, s, len); 390 1.1 jtc if (n < 0) { 391 1.2 tls #ifdef KSH 392 1.1 jtc if (flags & PO_COPROC) 393 1.1 jtc restore_pipe(opipe); 394 1.2 tls #endif /* KSH */ 395 1.1 jtc if (errno == EINTR) { 396 1.1 jtc /* allow user to ^C out */ 397 1.1 jtc intrcheck(); 398 1.2 tls #ifdef KSH 399 1.1 jtc if (flags & PO_COPROC) 400 1.1 jtc opipe = block_pipe(); 401 1.2 tls #endif /* KSH */ 402 1.1 jtc continue; 403 1.1 jtc } 404 1.1 jtc #ifdef KSH 405 1.1 jtc /* This doesn't really make sense - could 406 1.1 jtc * break scripts (print -p generates 407 1.1 jtc * error message). 408 1.1 jtc *if (errno == EPIPE) 409 1.1 jtc * coproc_write_close(fd); 410 1.1 jtc */ 411 1.1 jtc #endif /* KSH */ 412 1.1 jtc return 1; 413 1.1 jtc } 414 1.1 jtc s += n; 415 1.1 jtc len -= n; 416 1.1 jtc } 417 1.1 jtc #ifdef KSH 418 1.1 jtc if (flags & PO_COPROC) 419 1.1 jtc restore_pipe(opipe); 420 1.1 jtc #endif /* KSH */ 421 1.1 jtc } 422 1.1 jtc 423 1.1 jtc return 0; 424 1.1 jtc } 425 1.1 jtc 426 1.1 jtc int 427 1.1 jtc c_whence(wp) 428 1.1 jtc char **wp; 429 1.1 jtc { 430 1.1 jtc struct tbl *tp; 431 1.1 jtc char *id; 432 1.1 jtc int pflag = 0, vflag = 0, Vflag = 0; 433 1.1 jtc int ret = 0; 434 1.1 jtc int optc; 435 1.1 jtc int iam_whence = wp[0][0] == 'w'; 436 1.1 jtc int fcflags; 437 1.1 jtc const char *options = iam_whence ? "pv" : "pvV"; 438 1.1 jtc 439 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) 440 1.1 jtc switch (optc) { 441 1.1 jtc case 'p': 442 1.1 jtc pflag = 1; 443 1.1 jtc break; 444 1.1 jtc case 'v': 445 1.1 jtc vflag = 1; 446 1.1 jtc break; 447 1.1 jtc case 'V': 448 1.1 jtc Vflag = 1; 449 1.1 jtc break; 450 1.1 jtc case '?': 451 1.1 jtc return 1; 452 1.1 jtc } 453 1.1 jtc wp += builtin_opt.optind; 454 1.1 jtc 455 1.1 jtc 456 1.1 jtc fcflags = FC_BI | FC_PATH | FC_FUNC; 457 1.1 jtc if (!iam_whence) { 458 1.1 jtc /* Note that -p on its own is deal with in comexec() */ 459 1.1 jtc if (pflag) 460 1.1 jtc fcflags |= FC_DEFPATH; 461 1.1 jtc /* Convert command options to whence options - note that 462 1.1 jtc * command -pV uses a different path search than whence -v 463 1.1 jtc * or whence -pv. This should be considered a feature. 464 1.1 jtc */ 465 1.1 jtc vflag = Vflag; 466 1.1 jtc } 467 1.1 jtc if (pflag) 468 1.1 jtc fcflags &= ~(FC_BI | FC_FUNC); 469 1.1 jtc 470 1.1 jtc while ((vflag || ret == 0) && (id = *wp++) != NULL) { 471 1.1 jtc tp = NULL; 472 1.1 jtc if ((iam_whence || vflag) && !pflag) 473 1.27 kamil tp = mytsearch(&keywords, id, hash(id)); 474 1.1 jtc if (!tp && !pflag) { 475 1.27 kamil tp = mytsearch(&aliases, id, hash(id)); 476 1.1 jtc if (tp && !(tp->flag & ISSET)) 477 1.1 jtc tp = NULL; 478 1.1 jtc } 479 1.1 jtc if (!tp) 480 1.1 jtc tp = findcom(id, fcflags); 481 1.1 jtc if (vflag || (tp->type != CALIAS && tp->type != CEXEC 482 1.1 jtc && tp->type != CTALIAS)) 483 1.1 jtc shprintf("%s", id); 484 1.1 jtc switch (tp->type) { 485 1.1 jtc case CKEYWD: 486 1.1 jtc if (vflag) 487 1.1 jtc shprintf(" is a reserved word"); 488 1.1 jtc break; 489 1.1 jtc case CALIAS: 490 1.1 jtc if (vflag) 491 1.1 jtc shprintf(" is an %salias for ", 492 1.1 jtc (tp->flag & EXPORT) ? "exported " 493 1.1 jtc : null); 494 1.1 jtc if (!iam_whence && !vflag) 495 1.1 jtc shprintf("alias %s=", id); 496 1.1 jtc print_value_quoted(tp->val.s); 497 1.1 jtc break; 498 1.1 jtc case CFUNC: 499 1.1 jtc if (vflag) { 500 1.1 jtc shprintf(" is a"); 501 1.1 jtc if (tp->flag & EXPORT) 502 1.1 jtc shprintf("n exported"); 503 1.1 jtc if (tp->flag & TRACE) 504 1.1 jtc shprintf(" traced"); 505 1.1 jtc if (!(tp->flag & ISSET)) { 506 1.1 jtc shprintf(" undefined"); 507 1.1 jtc if (tp->u.fpath) 508 1.1 jtc shprintf(" (autoload from %s)", 509 1.1 jtc tp->u.fpath); 510 1.1 jtc } 511 1.1 jtc shprintf(" function"); 512 1.1 jtc } 513 1.1 jtc break; 514 1.1 jtc case CSHELL: 515 1.1 jtc if (vflag) 516 1.1 jtc shprintf(" is a%s shell builtin", 517 1.1 jtc (tp->flag & SPEC_BI) ? " special" : null); 518 1.1 jtc break; 519 1.1 jtc case CTALIAS: 520 1.1 jtc case CEXEC: 521 1.1 jtc if (tp->flag & ISSET) { 522 1.1 jtc if (vflag) { 523 1.1 jtc shprintf(" is "); 524 1.1 jtc if (tp->type == CTALIAS) 525 1.1 jtc shprintf( 526 1.1 jtc "a tracked %salias for ", 527 1.1 jtc (tp->flag & EXPORT) ? 528 1.1 jtc "exported " 529 1.1 jtc : null); 530 1.1 jtc } 531 1.1 jtc shprintf("%s", tp->val.s); 532 1.1 jtc } else { 533 1.1 jtc if (vflag) 534 1.1 jtc shprintf(" not found"); 535 1.1 jtc ret = 1; 536 1.1 jtc } 537 1.1 jtc break; 538 1.1 jtc default: 539 1.1 jtc shprintf("%s is *GOK*", id); 540 1.1 jtc break; 541 1.1 jtc } 542 1.1 jtc if (vflag || !ret) 543 1.18 joerg shprintf("%s", newline); 544 1.1 jtc } 545 1.1 jtc return ret; 546 1.1 jtc } 547 1.1 jtc 548 1.1 jtc /* Deal with command -vV - command -p dealt with in comexec() */ 549 1.1 jtc int 550 1.1 jtc c_command(wp) 551 1.1 jtc char **wp; 552 1.1 jtc { 553 1.1 jtc /* Let c_whence do the work. Note that c_command() must be 554 1.1 jtc * a distinct function from c_whence() (tested in comexec()). 555 1.1 jtc */ 556 1.1 jtc return c_whence(wp); 557 1.1 jtc } 558 1.1 jtc 559 1.1 jtc /* typeset, export, and readonly */ 560 1.1 jtc int 561 1.1 jtc c_typeset(wp) 562 1.1 jtc char **wp; 563 1.1 jtc { 564 1.1 jtc struct block *l = e->loc; 565 1.1 jtc struct tbl *vp, **p; 566 1.1 jtc Tflag fset = 0, fclr = 0; 567 1.13 christos int thing = 0, func = 0, localv = 0; 568 1.5 hubertf const char *options = "L#R#UZ#fi#lprtux"; /* see comment below */ 569 1.1 jtc char *fieldstr, *basestr; 570 1.1 jtc int field, base; 571 1.1 jtc int optc; 572 1.1 jtc Tflag flag; 573 1.1 jtc int pflag = 0; 574 1.1 jtc 575 1.1 jtc switch (**wp) { 576 1.1 jtc case 'e': /* export */ 577 1.1 jtc fset |= EXPORT; 578 1.1 jtc options = "p"; 579 1.1 jtc break; 580 1.1 jtc case 'r': /* readonly */ 581 1.1 jtc fset |= RDONLY; 582 1.1 jtc options = "p"; 583 1.1 jtc break; 584 1.1 jtc case 's': /* set */ 585 1.1 jtc /* called with 'typeset -' */ 586 1.1 jtc break; 587 1.1 jtc case 't': /* typeset */ 588 1.13 christos localv = 1; 589 1.1 jtc break; 590 1.1 jtc } 591 1.11 mycroft 592 1.1 jtc fieldstr = basestr = (char *) 0; 593 1.1 jtc builtin_opt.flags |= GF_PLUSOPT; 594 1.1 jtc /* at&t ksh seems to have 0-9 as options, which are multiplied 595 1.1 jtc * to get a number that is used with -L, -R, -Z or -i (eg, -1R2 596 1.1 jtc * sets right justify in a field of 12). This allows options 597 1.1 jtc * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and 598 1.5 hubertf * does not allow the number to be specified as a separate argument 599 1.1 jtc * Here, the number must follow the RLZi option, but is optional 600 1.1 jtc * (see the # kludge in ksh_getopt()). 601 1.1 jtc */ 602 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) { 603 1.1 jtc flag = 0; 604 1.1 jtc switch (optc) { 605 1.1 jtc case 'L': 606 1.5 hubertf flag = LJUST; 607 1.1 jtc fieldstr = builtin_opt.optarg; 608 1.1 jtc break; 609 1.1 jtc case 'R': 610 1.5 hubertf flag = RJUST; 611 1.1 jtc fieldstr = builtin_opt.optarg; 612 1.1 jtc break; 613 1.1 jtc case 'U': 614 1.1 jtc /* at&t ksh uses u, but this conflicts with 615 1.1 jtc * upper/lower case. If this option is changed, 616 1.1 jtc * need to change the -U below as well 617 1.1 jtc */ 618 1.5 hubertf flag = INT_U; 619 1.1 jtc break; 620 1.1 jtc case 'Z': 621 1.5 hubertf flag = ZEROFIL; 622 1.1 jtc fieldstr = builtin_opt.optarg; 623 1.1 jtc break; 624 1.1 jtc case 'f': 625 1.1 jtc func = 1; 626 1.1 jtc break; 627 1.1 jtc case 'i': 628 1.5 hubertf flag = INTEGER; 629 1.1 jtc basestr = builtin_opt.optarg; 630 1.1 jtc break; 631 1.1 jtc case 'l': 632 1.5 hubertf flag = LCASEV; 633 1.1 jtc break; 634 1.5 hubertf case 'p': /* posix export/readonly -p flag. 635 1.11 mycroft * typeset -p is the same as typeset (in pdksh); 636 1.6 wiz * here for compatibility with ksh93. 637 1.5 hubertf */ 638 1.1 jtc pflag = 1; 639 1.1 jtc break; 640 1.1 jtc case 'r': 641 1.5 hubertf flag = RDONLY; 642 1.1 jtc break; 643 1.1 jtc case 't': 644 1.5 hubertf flag = TRACE; 645 1.1 jtc break; 646 1.1 jtc case 'u': 647 1.5 hubertf flag = UCASEV_AL; /* upper case / autoload */ 648 1.1 jtc break; 649 1.1 jtc case 'x': 650 1.5 hubertf flag = EXPORT; 651 1.1 jtc break; 652 1.1 jtc case '?': 653 1.1 jtc return 1; 654 1.1 jtc } 655 1.1 jtc if (builtin_opt.info & GI_PLUS) { 656 1.1 jtc fclr |= flag; 657 1.1 jtc fset &= ~flag; 658 1.1 jtc thing = '+'; 659 1.1 jtc } else { 660 1.1 jtc fset |= flag; 661 1.1 jtc fclr &= ~flag; 662 1.1 jtc thing = '-'; 663 1.1 jtc } 664 1.1 jtc } 665 1.1 jtc 666 1.1 jtc field = 0; 667 1.1 jtc if (fieldstr && !bi_getn(fieldstr, &field)) 668 1.1 jtc return 1; 669 1.1 jtc base = 0; 670 1.1 jtc if (basestr && !bi_getn(basestr, &base)) 671 1.1 jtc return 1; 672 1.1 jtc 673 1.1 jtc if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] 674 1.1 jtc && (wp[builtin_opt.optind][0] == '-' 675 1.1 jtc || wp[builtin_opt.optind][0] == '+') 676 1.1 jtc && wp[builtin_opt.optind][1] == '\0') 677 1.1 jtc { 678 1.1 jtc thing = wp[builtin_opt.optind][0]; 679 1.1 jtc builtin_opt.optind++; 680 1.1 jtc } 681 1.1 jtc 682 1.1 jtc if (func && ((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT))) { 683 1.1 jtc bi_errorf("only -t, -u and -x options may be used with -f"); 684 1.1 jtc return 1; 685 1.1 jtc } 686 1.1 jtc if (wp[builtin_opt.optind]) { 687 1.11 mycroft /* Take care of exclusions. 688 1.5 hubertf * At this point, flags in fset are cleared in fclr and vise 689 1.5 hubertf * versa. This property should be preserved. 690 1.5 hubertf */ 691 1.5 hubertf if (fset & LCASEV) /* LCASEV has priority over UCASEV_AL */ 692 1.5 hubertf fset &= ~UCASEV_AL; 693 1.5 hubertf if (fset & LJUST) /* LJUST has priority over RJUST */ 694 1.5 hubertf fset &= ~RJUST; 695 1.5 hubertf if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) { /* -Z implies -ZR */ 696 1.5 hubertf fset |= RJUST; 697 1.5 hubertf fclr &= ~RJUST; 698 1.5 hubertf } 699 1.5 hubertf /* Setting these attributes clears the others, unless they 700 1.1 jtc * are also set in this command 701 1.1 jtc */ 702 1.1 jtc if (fset & (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER 703 1.1 jtc |INT_U|INT_L)) 704 1.1 jtc fclr |= ~fset & 705 1.1 jtc (LJUST|RJUST|ZEROFIL|UCASEV_AL|LCASEV|INTEGER 706 1.1 jtc |INT_U|INT_L); 707 1.1 jtc } 708 1.1 jtc 709 1.1 jtc /* set variables and attributes */ 710 1.1 jtc if (wp[builtin_opt.optind]) { 711 1.1 jtc int i; 712 1.1 jtc int rval = 0; 713 1.1 jtc struct tbl *f; 714 1.1 jtc 715 1.13 christos if (localv && !func) 716 1.1 jtc fset |= LOCAL; 717 1.1 jtc for (i = builtin_opt.optind; wp[i]; i++) { 718 1.1 jtc if (func) { 719 1.1 jtc f = findfunc(wp[i], hash(wp[i]), 720 1.26 kamil (fset&UCASEV_AL) ? true : false); 721 1.1 jtc if (!f) { 722 1.1 jtc /* at&t ksh does ++rval: bogus */ 723 1.1 jtc rval = 1; 724 1.1 jtc continue; 725 1.1 jtc } 726 1.1 jtc if (fset | fclr) { 727 1.1 jtc f->flag |= fset; 728 1.1 jtc f->flag &= ~fclr; 729 1.1 jtc } else 730 1.1 jtc fptreef(shl_stdout, 0, 731 1.5 hubertf f->flag & FKSH ? 732 1.5 hubertf "function %s %T\n" 733 1.5 hubertf : "%s() %T\n" 734 1.5 hubertf , 735 1.1 jtc wp[i], f->val.t); 736 1.1 jtc } else if (!typeset(wp[i], fset, fclr, field, base)) { 737 1.1 jtc bi_errorf("%s: not identifier", wp[i]); 738 1.1 jtc return 1; 739 1.1 jtc } 740 1.1 jtc } 741 1.1 jtc return rval; 742 1.1 jtc } 743 1.1 jtc 744 1.1 jtc /* list variables and attributes */ 745 1.1 jtc flag = fset | fclr; /* no difference at this point.. */ 746 1.1 jtc if (func) { 747 1.1 jtc for (l = e->loc; l; l = l->next) { 748 1.1 jtc for (p = tsort(&l->funs); (vp = *p++); ) { 749 1.1 jtc if (flag && (vp->flag & flag) == 0) 750 1.1 jtc continue; 751 1.1 jtc if (thing == '-') 752 1.5 hubertf fptreef(shl_stdout, 0, vp->flag & FKSH ? 753 1.5 hubertf "function %s %T\n" 754 1.5 hubertf : "%s() %T\n", 755 1.1 jtc vp->name, vp->val.t); 756 1.1 jtc else 757 1.1 jtc shprintf("%s\n", vp->name); 758 1.1 jtc } 759 1.1 jtc } 760 1.1 jtc } else { 761 1.1 jtc for (l = e->loc; l; l = l->next) { 762 1.5 hubertf for (p = tsort(&l->vars); (vp = *p++); ) { 763 1.5 hubertf struct tbl *tvp; 764 1.5 hubertf int any_set = 0; 765 1.5 hubertf /* 766 1.5 hubertf * See if the parameter is set (for arrays, if any 767 1.5 hubertf * element is set). 768 1.5 hubertf */ 769 1.5 hubertf for (tvp = vp; tvp; tvp = tvp->u.array) 770 1.5 hubertf if (tvp->flag & ISSET) { 771 1.5 hubertf any_set = 1; 772 1.5 hubertf break; 773 1.5 hubertf } 774 1.5 hubertf /* 775 1.5 hubertf * Check attributes - note that all array elements 776 1.5 hubertf * have (should have?) the same attributes, so checking 777 1.5 hubertf * the first is sufficient. 778 1.5 hubertf * 779 1.5 hubertf * Report an unset param only if the user has 780 1.5 hubertf * explicitly given it some attribute (like export); 781 1.5 hubertf * otherwise, after "echo $FOO", we would report FOO... 782 1.5 hubertf */ 783 1.5 hubertf if (!any_set && !(vp->flag & USERATTRIB)) 784 1.5 hubertf continue; 785 1.5 hubertf if (flag && (vp->flag & flag) == 0) 786 1.5 hubertf continue; 787 1.1 jtc for (; vp; vp = vp->u.array) { 788 1.5 hubertf /* Ignore array elements that aren't set unless there 789 1.5 hubertf * are no set elements, in which case the first is 790 1.5 hubertf * reported on 791 1.2 tls */ 792 1.5 hubertf if ((vp->flag&ARRAY) && any_set && !(vp->flag & ISSET)) 793 1.1 jtc continue; 794 1.1 jtc /* no arguments */ 795 1.1 jtc if (thing == 0 && flag == 0) { 796 1.1 jtc /* at&t ksh prints things like export, integer, 797 1.1 jtc * leftadj, zerofill, etc., but POSIX says must 798 1.1 jtc * be suitable for re-entry... 799 1.1 jtc */ 800 1.1 jtc shprintf("typeset "); 801 1.1 jtc if ((vp->flag&INTEGER)) 802 1.1 jtc shprintf("-i "); 803 1.1 jtc if ((vp->flag&EXPORT)) 804 1.1 jtc shprintf("-x "); 805 1.1 jtc if ((vp->flag&RDONLY)) 806 1.1 jtc shprintf("-r "); 807 1.11 mycroft if ((vp->flag&TRACE)) 808 1.1 jtc shprintf("-t "); 809 1.11 mycroft if ((vp->flag&LJUST)) 810 1.1 jtc shprintf("-L%d ", vp->u2.field); 811 1.11 mycroft if ((vp->flag&RJUST)) 812 1.1 jtc shprintf("-R%d ", vp->u2.field); 813 1.11 mycroft if ((vp->flag&ZEROFIL)) 814 1.1 jtc shprintf("-Z "); 815 1.11 mycroft if ((vp->flag&LCASEV)) 816 1.1 jtc shprintf("-l "); 817 1.11 mycroft if ((vp->flag&UCASEV_AL)) 818 1.1 jtc shprintf("-u "); 819 1.11 mycroft if ((vp->flag&INT_U)) 820 1.1 jtc shprintf("-U "); 821 1.5 hubertf shprintf("%s\n", vp->name); 822 1.1 jtc if (vp->flag&ARRAY) 823 1.5 hubertf break; 824 1.1 jtc } else { 825 1.1 jtc if (pflag) 826 1.1 jtc shprintf("%s ", 827 1.1 jtc (flag & EXPORT) ? "export" : "readonly"); 828 1.5 hubertf if ((vp->flag&ARRAY) && any_set) 829 1.1 jtc shprintf("%s[%d]", vp->name, vp->index); 830 1.1 jtc else 831 1.1 jtc shprintf("%s", vp->name); 832 1.1 jtc if (thing == '-' && (vp->flag&ISSET)) { 833 1.1 jtc char *s = str_val(vp); 834 1.1 jtc 835 1.1 jtc shprintf("="); 836 1.1 jtc /* at&t ksh can't have justified integers.. */ 837 1.1 jtc if ((vp->flag & (INTEGER|LJUST|RJUST)) 838 1.1 jtc == INTEGER) 839 1.1 jtc shprintf("%s", s); 840 1.1 jtc else 841 1.1 jtc print_value_quoted(s); 842 1.1 jtc } 843 1.18 joerg shprintf("%s", newline); 844 1.1 jtc } 845 1.5 hubertf /* Only report first `element' of an array with 846 1.5 hubertf * no set elements. 847 1.5 hubertf */ 848 1.5 hubertf if (!any_set) 849 1.5 hubertf break; 850 1.1 jtc } 851 1.5 hubertf } 852 1.1 jtc } 853 1.1 jtc } 854 1.1 jtc return 0; 855 1.1 jtc } 856 1.1 jtc 857 1.1 jtc int 858 1.1 jtc c_alias(wp) 859 1.1 jtc char **wp; 860 1.1 jtc { 861 1.1 jtc struct table *t = &aliases; 862 1.5 hubertf int rv = 0, rflag = 0, tflag, Uflag = 0, pflag = 0; 863 1.5 hubertf int prefix = 0; 864 1.1 jtc Tflag xflag = 0; 865 1.1 jtc int optc; 866 1.1 jtc 867 1.5 hubertf builtin_opt.flags |= GF_PLUSOPT; 868 1.5 hubertf while ((optc = ksh_getopt(wp, &builtin_opt, "dprtUx")) != EOF) { 869 1.5 hubertf prefix = builtin_opt.info & GI_PLUS ? '+' : '-'; 870 1.1 jtc switch (optc) { 871 1.1 jtc case 'd': 872 1.1 jtc t = &homedirs; 873 1.1 jtc break; 874 1.5 hubertf case 'p': 875 1.5 hubertf pflag = 1; 876 1.5 hubertf break; 877 1.1 jtc case 'r': 878 1.1 jtc rflag = 1; 879 1.1 jtc break; 880 1.1 jtc case 't': 881 1.1 jtc t = &taliases; 882 1.1 jtc break; 883 1.1 jtc case 'U': /* kludge for tracked alias initialization 884 1.1 jtc * (don't do a path search, just make an entry) 885 1.1 jtc */ 886 1.1 jtc Uflag = 1; 887 1.1 jtc break; 888 1.1 jtc case 'x': 889 1.1 jtc xflag = EXPORT; 890 1.1 jtc break; 891 1.1 jtc case '?': 892 1.1 jtc return 1; 893 1.1 jtc } 894 1.5 hubertf } 895 1.1 jtc wp += builtin_opt.optind; 896 1.1 jtc 897 1.5 hubertf if (!(builtin_opt.info & GI_MINUSMINUS) && *wp 898 1.5 hubertf && (wp[0][0] == '-' || wp[0][0] == '+') && wp[0][1] == '\0') 899 1.5 hubertf { 900 1.5 hubertf prefix = wp[0][0]; 901 1.5 hubertf wp++; 902 1.5 hubertf } 903 1.5 hubertf 904 1.1 jtc tflag = t == &taliases; 905 1.1 jtc 906 1.1 jtc /* "hash -r" means reset all the tracked aliases.. */ 907 1.1 jtc if (rflag) { 908 1.1 jtc static const char *const args[] = { 909 1.1 jtc "unalias", "-ta", (const char *) 0 910 1.1 jtc }; 911 1.1 jtc 912 1.1 jtc if (!tflag || *wp) { 913 1.1 jtc shprintf( 914 1.1 jtc "alias: -r flag can only be used with -t and without arguments\n"); 915 1.1 jtc return 1; 916 1.1 jtc } 917 1.1 jtc ksh_getopt_reset(&builtin_opt, GF_ERROR); 918 1.13 christos return c_unalias((char **)__UNCONST(args)); 919 1.1 jtc } 920 1.1 jtc 921 1.5 hubertf 922 1.1 jtc if (*wp == NULL) { 923 1.1 jtc struct tbl *ap, **p; 924 1.1 jtc 925 1.1 jtc for (p = tsort(t); (ap = *p++) != NULL; ) 926 1.1 jtc if ((ap->flag & (ISSET|xflag)) == (ISSET|xflag)) { 927 1.5 hubertf if (pflag) 928 1.5 hubertf shf_puts("alias ", shl_stdout); 929 1.5 hubertf shf_puts(ap->name, shl_stdout); 930 1.5 hubertf if (prefix != '+') { 931 1.5 hubertf shf_putc('=', shl_stdout); 932 1.5 hubertf print_value_quoted(ap->val.s); 933 1.5 hubertf } 934 1.18 joerg shprintf("%s", newline); 935 1.1 jtc } 936 1.1 jtc } 937 1.1 jtc 938 1.1 jtc for (; *wp != NULL; wp++) { 939 1.1 jtc char *alias = *wp; 940 1.1 jtc char *val = strchr(alias, '='); 941 1.1 jtc char *newval; 942 1.1 jtc struct tbl *ap; 943 1.1 jtc int h; 944 1.1 jtc 945 1.1 jtc if (val) 946 1.1 jtc alias = str_nsave(alias, val++ - alias, ATEMP); 947 1.1 jtc h = hash(alias); 948 1.1 jtc if (val == NULL && !tflag && !xflag) { 949 1.27 kamil ap = mytsearch(t, alias, h); 950 1.1 jtc if (ap != NULL && (ap->flag&ISSET)) { 951 1.5 hubertf if (pflag) 952 1.5 hubertf shf_puts("alias ", shl_stdout); 953 1.5 hubertf shf_puts(ap->name, shl_stdout); 954 1.5 hubertf if (prefix != '+') { 955 1.5 hubertf shf_putc('=', shl_stdout); 956 1.5 hubertf print_value_quoted(ap->val.s); 957 1.5 hubertf } 958 1.18 joerg shprintf("%s", newline); 959 1.1 jtc } else { 960 1.1 jtc shprintf("%s alias not found\n", alias); 961 1.1 jtc rv = 1; 962 1.1 jtc } 963 1.1 jtc continue; 964 1.1 jtc } 965 1.1 jtc ap = tenter(t, alias, h); 966 1.1 jtc ap->type = tflag ? CTALIAS : CALIAS; 967 1.1 jtc /* Are we setting the value or just some flags? */ 968 1.1 jtc if ((val && !tflag) || (!val && tflag && !Uflag)) { 969 1.1 jtc if (ap->flag&ALLOC) { 970 1.1 jtc ap->flag &= ~(ALLOC|ISSET); 971 1.1 jtc afree((void*)ap->val.s, APERM); 972 1.1 jtc } 973 1.1 jtc /* ignore values for -t (at&t ksh does this) */ 974 1.1 jtc newval = tflag ? search(alias, path, X_OK, (int *) 0) 975 1.1 jtc : val; 976 1.1 jtc if (newval) { 977 1.1 jtc ap->val.s = str_save(newval, APERM); 978 1.1 jtc ap->flag |= ALLOC|ISSET; 979 1.1 jtc } else 980 1.1 jtc ap->flag &= ~ISSET; 981 1.1 jtc } 982 1.5 hubertf ap->flag |= DEFINED; 983 1.5 hubertf if (prefix == '+') 984 1.5 hubertf ap->flag &= ~xflag; 985 1.5 hubertf else 986 1.5 hubertf ap->flag |= xflag; 987 1.1 jtc if (val) 988 1.1 jtc afree(alias, ATEMP); 989 1.1 jtc } 990 1.1 jtc 991 1.1 jtc return rv; 992 1.1 jtc } 993 1.1 jtc 994 1.1 jtc int 995 1.1 jtc c_unalias(wp) 996 1.1 jtc char **wp; 997 1.1 jtc { 998 1.28 kamil struct table *t = &aliases; 999 1.28 kamil struct tbl *ap; 1000 1.1 jtc int rv = 0, all = 0; 1001 1.1 jtc int optc; 1002 1.1 jtc 1003 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, "adt")) != EOF) 1004 1.1 jtc switch (optc) { 1005 1.1 jtc case 'a': 1006 1.1 jtc all = 1; 1007 1.1 jtc break; 1008 1.1 jtc case 'd': 1009 1.1 jtc t = &homedirs; 1010 1.1 jtc break; 1011 1.1 jtc case 't': 1012 1.1 jtc t = &taliases; 1013 1.1 jtc break; 1014 1.1 jtc case '?': 1015 1.1 jtc return 1; 1016 1.1 jtc } 1017 1.1 jtc wp += builtin_opt.optind; 1018 1.1 jtc 1019 1.1 jtc for (; *wp != NULL; wp++) { 1020 1.27 kamil ap = mytsearch(t, *wp, hash(*wp)); 1021 1.1 jtc if (ap == NULL) { 1022 1.1 jtc rv = 1; /* POSIX */ 1023 1.1 jtc continue; 1024 1.1 jtc } 1025 1.1 jtc if (ap->flag&ALLOC) { 1026 1.1 jtc ap->flag &= ~(ALLOC|ISSET); 1027 1.1 jtc afree((void*)ap->val.s, APERM); 1028 1.1 jtc } 1029 1.1 jtc ap->flag &= ~(DEFINED|ISSET|EXPORT); 1030 1.1 jtc } 1031 1.1 jtc 1032 1.1 jtc if (all) { 1033 1.1 jtc struct tstate ts; 1034 1.1 jtc 1035 1.29 kamil for (ksh_twalk(&ts, t); (ap = tnext(&ts)); ) { 1036 1.1 jtc if (ap->flag&ALLOC) { 1037 1.1 jtc ap->flag &= ~(ALLOC|ISSET); 1038 1.1 jtc afree((void*)ap->val.s, APERM); 1039 1.1 jtc } 1040 1.1 jtc ap->flag &= ~(DEFINED|ISSET|EXPORT); 1041 1.1 jtc } 1042 1.1 jtc } 1043 1.1 jtc 1044 1.1 jtc return rv; 1045 1.1 jtc } 1046 1.1 jtc 1047 1.2 tls #ifdef KSH 1048 1.1 jtc int 1049 1.1 jtc c_let(wp) 1050 1.1 jtc char **wp; 1051 1.1 jtc { 1052 1.1 jtc int rv = 1; 1053 1.1 jtc long val; 1054 1.1 jtc 1055 1.1 jtc if (wp[1] == (char *) 0) /* at&t ksh does this */ 1056 1.1 jtc bi_errorf("no arguments"); 1057 1.1 jtc else 1058 1.1 jtc for (wp++; *wp; wp++) 1059 1.5 hubertf if (!evaluate(*wp, &val, KSH_RETURN_ERROR)) { 1060 1.1 jtc rv = 2; /* distinguish error from zero result */ 1061 1.1 jtc break; 1062 1.1 jtc } else 1063 1.1 jtc rv = val == 0; 1064 1.1 jtc return rv; 1065 1.1 jtc } 1066 1.2 tls #endif /* KSH */ 1067 1.1 jtc 1068 1.1 jtc int 1069 1.1 jtc c_jobs(wp) 1070 1.1 jtc char **wp; 1071 1.1 jtc { 1072 1.1 jtc int optc; 1073 1.1 jtc int flag = 0; 1074 1.1 jtc int nflag = 0; 1075 1.30 christos int Zflag = 0; 1076 1.1 jtc int rv = 0; 1077 1.1 jtc 1078 1.30 christos while ((optc = ksh_getopt(wp, &builtin_opt, "lpnzZ")) != EOF) 1079 1.1 jtc switch (optc) { 1080 1.1 jtc case 'l': 1081 1.1 jtc flag = 1; 1082 1.1 jtc break; 1083 1.1 jtc case 'p': 1084 1.1 jtc flag = 2; 1085 1.1 jtc break; 1086 1.1 jtc case 'n': 1087 1.1 jtc nflag = 1; 1088 1.1 jtc break; 1089 1.1 jtc case 'z': /* debugging: print zombies */ 1090 1.1 jtc nflag = -1; 1091 1.1 jtc break; 1092 1.30 christos case 'Z': 1093 1.30 christos Zflag = 1; 1094 1.30 christos break; 1095 1.1 jtc case '?': 1096 1.1 jtc return 1; 1097 1.1 jtc } 1098 1.1 jtc wp += builtin_opt.optind; 1099 1.30 christos if (Zflag) { 1100 1.30 christos if (*wp && **wp) { 1101 1.30 christos setproctitle("%s", *wp); 1102 1.30 christos } else { 1103 1.30 christos setproctitle(NULL); 1104 1.30 christos } 1105 1.30 christos return 0; 1106 1.30 christos } 1107 1.3 thorpej if (!*wp) { 1108 1.1 jtc if (j_jobs((char *) 0, flag, nflag)) 1109 1.1 jtc rv = 1; 1110 1.3 thorpej } else { 1111 1.11 mycroft for (; *wp; wp++) 1112 1.1 jtc if (j_jobs(*wp, flag, nflag)) 1113 1.1 jtc rv = 1; 1114 1.3 thorpej } 1115 1.1 jtc return rv; 1116 1.1 jtc } 1117 1.1 jtc 1118 1.1 jtc #ifdef JOBS 1119 1.1 jtc int 1120 1.1 jtc c_fgbg(wp) 1121 1.1 jtc char **wp; 1122 1.1 jtc { 1123 1.1 jtc int bg = strcmp(*wp, "bg") == 0; 1124 1.1 jtc int UNINITIALIZED(rv); 1125 1.1 jtc 1126 1.1 jtc if (!Flag(FMONITOR)) { 1127 1.1 jtc bi_errorf("job control not enabled"); 1128 1.1 jtc return 1; 1129 1.1 jtc } 1130 1.1 jtc if (ksh_getopt(wp, &builtin_opt, null) == '?') 1131 1.1 jtc return 1; 1132 1.1 jtc wp += builtin_opt.optind; 1133 1.1 jtc if (*wp) 1134 1.1 jtc for (; *wp; wp++) 1135 1.1 jtc rv = j_resume(*wp, bg); 1136 1.1 jtc else 1137 1.1 jtc rv = j_resume("%%", bg); 1138 1.1 jtc /* POSIX says fg shall return 0 (unless an error occurs). 1139 1.1 jtc * at&t ksh returns the exit value of the job... 1140 1.1 jtc */ 1141 1.1 jtc return (bg || Flag(FPOSIX)) ? 0 : rv; 1142 1.1 jtc } 1143 1.1 jtc #endif 1144 1.1 jtc 1145 1.1 jtc struct kill_info { 1146 1.1 jtc int num_width; 1147 1.1 jtc int name_width; 1148 1.1 jtc }; 1149 1.1 jtc static char *kill_fmt_entry ARGS((void *arg, int i, char *buf, int buflen)); 1150 1.1 jtc 1151 1.1 jtc /* format a single kill item */ 1152 1.1 jtc static char * 1153 1.1 jtc kill_fmt_entry(arg, i, buf, buflen) 1154 1.1 jtc void *arg; 1155 1.1 jtc int i; 1156 1.1 jtc char *buf; 1157 1.1 jtc int buflen; 1158 1.1 jtc { 1159 1.1 jtc struct kill_info *ki = (struct kill_info *) arg; 1160 1.1 jtc 1161 1.1 jtc i++; 1162 1.1 jtc if (sigtraps[i].name) 1163 1.1 jtc shf_snprintf(buf, buflen, "%*d %*s %s", 1164 1.1 jtc ki->num_width, i, 1165 1.1 jtc ki->name_width, sigtraps[i].name, 1166 1.1 jtc sigtraps[i].mess); 1167 1.1 jtc else 1168 1.1 jtc shf_snprintf(buf, buflen, "%*d %*d %s", 1169 1.1 jtc ki->num_width, i, 1170 1.1 jtc ki->name_width, sigtraps[i].signal, 1171 1.1 jtc sigtraps[i].mess); 1172 1.1 jtc return buf; 1173 1.1 jtc } 1174 1.1 jtc 1175 1.1 jtc 1176 1.1 jtc int 1177 1.1 jtc c_kill(wp) 1178 1.1 jtc char **wp; 1179 1.1 jtc { 1180 1.1 jtc Trap *t = (Trap *) 0; 1181 1.1 jtc char *p; 1182 1.1 jtc int lflag = 0; 1183 1.1 jtc int i, n, rv, sig; 1184 1.1 jtc 1185 1.1 jtc /* assume old style options if -digits or -UPPERCASE */ 1186 1.12 dsl if ((p = wp[1]) && *p == '-' 1187 1.12 dsl && (digit(p[1]) || isupper((unsigned char)p[1]))) { 1188 1.26 kamil if (!(t = gettrap(p + 1, true))) { 1189 1.1 jtc bi_errorf("bad signal `%s'", p + 1); 1190 1.1 jtc return 1; 1191 1.1 jtc } 1192 1.1 jtc i = (wp[2] && strcmp(wp[2], "--") == 0) ? 3 : 2; 1193 1.1 jtc } else { 1194 1.1 jtc int optc; 1195 1.1 jtc 1196 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, "ls:")) != EOF) 1197 1.1 jtc switch (optc) { 1198 1.1 jtc case 'l': 1199 1.1 jtc lflag = 1; 1200 1.1 jtc break; 1201 1.1 jtc case 's': 1202 1.26 kamil if (!(t = gettrap(builtin_opt.optarg, true))) { 1203 1.1 jtc bi_errorf("bad signal `%s'", 1204 1.1 jtc builtin_opt.optarg); 1205 1.1 jtc return 1; 1206 1.1 jtc } 1207 1.9 wiz break; 1208 1.1 jtc case '?': 1209 1.1 jtc return 1; 1210 1.1 jtc } 1211 1.1 jtc i = builtin_opt.optind; 1212 1.1 jtc } 1213 1.1 jtc if ((lflag && t) || (!wp[i] && !lflag)) { 1214 1.1 jtc shf_fprintf(shl_out, 1215 1.10 jmmv "usage: kill [ -s signame | -signum | -signame ] {pid|job}...\n\ 1216 1.1 jtc kill -l [exit_status]\n" 1217 1.1 jtc ); 1218 1.18 joerg bi_errorf("%s", null); 1219 1.1 jtc return 1; 1220 1.1 jtc } 1221 1.1 jtc 1222 1.1 jtc if (lflag) { 1223 1.1 jtc if (wp[i]) { 1224 1.1 jtc for (; wp[i]; i++) { 1225 1.1 jtc if (!bi_getn(wp[i], &n)) 1226 1.1 jtc return 1; 1227 1.1 jtc if (n > 128 && n < 128 + SIGNALS) 1228 1.1 jtc n -= 128; 1229 1.1 jtc if (n > 0 && n < SIGNALS && sigtraps[n].name) 1230 1.1 jtc shprintf("%s\n", sigtraps[n].name); 1231 1.1 jtc else 1232 1.1 jtc shprintf("%d\n", n); 1233 1.1 jtc } 1234 1.1 jtc } else if (Flag(FPOSIX)) { 1235 1.1 jtc p = null; 1236 1.1 jtc for (i = 1; i < SIGNALS; i++, p = space) 1237 1.1 jtc if (sigtraps[i].name) 1238 1.1 jtc shprintf("%s%s", p, sigtraps[i].name); 1239 1.18 joerg shprintf("%s", newline); 1240 1.1 jtc } else { 1241 1.13 christos int w, si; 1242 1.1 jtc int mess_width; 1243 1.1 jtc struct kill_info ki; 1244 1.1 jtc 1245 1.13 christos for (si = SIGNALS, ki.num_width = 1; si >= 10; si /= 10) 1246 1.1 jtc ki.num_width++; 1247 1.1 jtc ki.name_width = mess_width = 0; 1248 1.13 christos for (si = 0; si < SIGNALS; si++) { 1249 1.13 christos w = sigtraps[si].name ? 1250 1.16 lukem (int)strlen(sigtraps[si].name) : 1251 1.16 lukem ki.num_width; 1252 1.1 jtc if (w > ki.name_width) 1253 1.1 jtc ki.name_width = w; 1254 1.13 christos w = strlen(sigtraps[si].mess); 1255 1.1 jtc if (w > mess_width) 1256 1.1 jtc mess_width = w; 1257 1.1 jtc } 1258 1.1 jtc 1259 1.1 jtc print_columns(shl_stdout, SIGNALS - 1, 1260 1.1 jtc kill_fmt_entry, (void *) &ki, 1261 1.7 provos ki.num_width + ki.name_width + mess_width + 3, 1); 1262 1.1 jtc } 1263 1.1 jtc return 0; 1264 1.1 jtc } 1265 1.1 jtc rv = 0; 1266 1.1 jtc sig = t ? t->signal : SIGTERM; 1267 1.1 jtc for (; (p = wp[i]); i++) { 1268 1.1 jtc if (*p == '%') { 1269 1.1 jtc if (j_kill(p, sig)) 1270 1.1 jtc rv = 1; 1271 1.1 jtc } else if (!getn(p, &n)) { 1272 1.11 mycroft bi_errorf("%s: arguments must be jobs or process IDs", 1273 1.1 jtc p); 1274 1.1 jtc rv = 1; 1275 1.1 jtc } else { 1276 1.1 jtc /* use killpg if < -1 since -1 does special things for 1277 1.1 jtc * some non-killpg-endowed kills 1278 1.1 jtc */ 1279 1.1 jtc if ((n < -1 ? killpg(-n, sig) : kill(n, sig)) < 0) { 1280 1.1 jtc bi_errorf("%s: %s", p, strerror(errno)); 1281 1.1 jtc rv = 1; 1282 1.1 jtc } 1283 1.1 jtc } 1284 1.1 jtc } 1285 1.1 jtc return rv; 1286 1.1 jtc } 1287 1.1 jtc 1288 1.1 jtc void 1289 1.1 jtc getopts_reset(val) 1290 1.1 jtc int val; 1291 1.1 jtc { 1292 1.5 hubertf if (val >= 1) { 1293 1.1 jtc ksh_getopt_reset(&user_opt, 1294 1.1 jtc GF_NONAME | (Flag(FPOSIX) ? 0 : GF_PLUSOPT)); 1295 1.5 hubertf user_opt.optind = user_opt.uoptind = val; 1296 1.1 jtc } 1297 1.1 jtc } 1298 1.1 jtc 1299 1.1 jtc int 1300 1.1 jtc c_getopts(wp) 1301 1.1 jtc char **wp; 1302 1.1 jtc { 1303 1.1 jtc int argc; 1304 1.1 jtc const char *options; 1305 1.1 jtc const char *var; 1306 1.1 jtc int optc; 1307 1.5 hubertf int ret; 1308 1.1 jtc char buf[3]; 1309 1.5 hubertf struct tbl *vq, *voptarg; 1310 1.1 jtc 1311 1.1 jtc if (ksh_getopt(wp, &builtin_opt, null) == '?') 1312 1.1 jtc return 1; 1313 1.1 jtc wp += builtin_opt.optind; 1314 1.1 jtc 1315 1.1 jtc options = *wp++; 1316 1.1 jtc if (!options) { 1317 1.1 jtc bi_errorf("missing options argument"); 1318 1.1 jtc return 1; 1319 1.1 jtc } 1320 1.1 jtc 1321 1.1 jtc var = *wp++; 1322 1.1 jtc if (!var) { 1323 1.1 jtc bi_errorf("missing name argument"); 1324 1.1 jtc return 1; 1325 1.1 jtc } 1326 1.26 kamil if (!*var || *skip_varname(var, true)) { 1327 1.1 jtc bi_errorf("%s: is not an identifier", var); 1328 1.1 jtc return 1; 1329 1.1 jtc } 1330 1.1 jtc 1331 1.1 jtc if (e->loc->next == (struct block *) 0) { 1332 1.1 jtc internal_errorf(0, "c_getopts: no argv"); 1333 1.1 jtc return 1; 1334 1.1 jtc } 1335 1.1 jtc /* Which arguments are we parsing... */ 1336 1.1 jtc if (*wp == (char *) 0) 1337 1.1 jtc wp = e->loc->next->argv; 1338 1.1 jtc else 1339 1.1 jtc *--wp = e->loc->next->argv[0]; 1340 1.1 jtc 1341 1.1 jtc /* Check that our saved state won't cause a core dump... */ 1342 1.1 jtc for (argc = 0; wp[argc]; argc++) 1343 1.1 jtc ; 1344 1.1 jtc if (user_opt.optind > argc 1345 1.1 jtc || (user_opt.p != 0 1346 1.1 jtc && user_opt.p > strlen(wp[user_opt.optind - 1]))) 1347 1.1 jtc { 1348 1.1 jtc bi_errorf("arguments changed since last call"); 1349 1.1 jtc return 1; 1350 1.1 jtc } 1351 1.1 jtc 1352 1.1 jtc user_opt.optarg = (char *) 0; 1353 1.1 jtc optc = ksh_getopt(wp, &user_opt, options); 1354 1.1 jtc 1355 1.1 jtc if (optc >= 0 && optc != '?' && (user_opt.info & GI_PLUS)) { 1356 1.1 jtc buf[0] = '+'; 1357 1.1 jtc buf[1] = optc; 1358 1.1 jtc buf[2] = '\0'; 1359 1.1 jtc } else { 1360 1.1 jtc /* POSIX says var is set to ? at end-of-options, at&t ksh 1361 1.1 jtc * sets it to null - we go with POSIX... 1362 1.1 jtc */ 1363 1.1 jtc buf[0] = optc < 0 ? '?' : optc; 1364 1.1 jtc buf[1] = '\0'; 1365 1.1 jtc } 1366 1.1 jtc 1367 1.1 jtc /* at&t ksh does not change OPTIND if it was an unknown option. 1368 1.1 jtc * Scripts counting on this are prone to break... (ie, don't count 1369 1.1 jtc * on this staying). 1370 1.1 jtc */ 1371 1.1 jtc if (optc != '?') { 1372 1.5 hubertf user_opt.uoptind = user_opt.optind; 1373 1.1 jtc } 1374 1.1 jtc 1375 1.5 hubertf voptarg = global("OPTARG"); 1376 1.5 hubertf voptarg->flag &= ~RDONLY; /* at&t ksh clears ro and int */ 1377 1.5 hubertf /* Paranoia: ensure no bizarre results. */ 1378 1.5 hubertf if (voptarg->flag & INTEGER) 1379 1.5 hubertf typeset("OPTARG", 0, INTEGER, 0, 0); 1380 1.1 jtc if (user_opt.optarg == (char *) 0) 1381 1.5 hubertf unset(voptarg, 0); 1382 1.1 jtc else 1383 1.5 hubertf /* This can't fail (have cleared readonly/integer) */ 1384 1.5 hubertf setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR); 1385 1.5 hubertf 1386 1.5 hubertf ret = 0; 1387 1.1 jtc 1388 1.1 jtc vq = global(var); 1389 1.5 hubertf /* Error message already printed (integer, readonly) */ 1390 1.5 hubertf if (!setstr(vq, buf, KSH_RETURN_ERROR)) 1391 1.5 hubertf ret = 1; 1392 1.1 jtc if (Flag(FEXPORT)) 1393 1.1 jtc typeset(var, EXPORT, 0, 0, 0); 1394 1.1 jtc 1395 1.5 hubertf return optc < 0 ? 1 : ret; 1396 1.1 jtc } 1397 1.1 jtc 1398 1.1 jtc #ifdef EMACS 1399 1.1 jtc int 1400 1.1 jtc c_bind(wp) 1401 1.1 jtc char **wp; 1402 1.1 jtc { 1403 1.1 jtc int rv = 0, macro = 0, list = 0; 1404 1.28 kamil char *cp; 1405 1.1 jtc int optc; 1406 1.1 jtc 1407 1.1 jtc while ((optc = ksh_getopt(wp, &builtin_opt, "lm")) != EOF) 1408 1.1 jtc switch (optc) { 1409 1.1 jtc case 'l': 1410 1.1 jtc list = 1; 1411 1.1 jtc break; 1412 1.1 jtc case 'm': 1413 1.1 jtc macro = 1; 1414 1.1 jtc break; 1415 1.1 jtc case '?': 1416 1.1 jtc return 1; 1417 1.1 jtc } 1418 1.1 jtc wp += builtin_opt.optind; 1419 1.1 jtc 1420 1.1 jtc if (*wp == NULL) /* list all */ 1421 1.17 plunky rv = x_bind(NULL, NULL, 0, list); 1422 1.1 jtc 1423 1.1 jtc for (; *wp != NULL; wp++) { 1424 1.1 jtc cp = strchr(*wp, '='); 1425 1.1 jtc if (cp != NULL) 1426 1.1 jtc *cp++ = '\0'; 1427 1.1 jtc if (x_bind(*wp, cp, macro, 0)) 1428 1.1 jtc rv = 1; 1429 1.1 jtc } 1430 1.1 jtc 1431 1.1 jtc return rv; 1432 1.1 jtc } 1433 1.1 jtc #endif 1434 1.1 jtc 1435 1.1 jtc /* A leading = means assignments before command are kept; 1436 1.1 jtc * a leading * means a POSIX special builtin; 1437 1.1 jtc * a leading + means a POSIX regular builtin 1438 1.1 jtc * (* and + should not be combined). 1439 1.1 jtc */ 1440 1.1 jtc const struct builtin kshbuiltins [] = { 1441 1.1 jtc {"+alias", c_alias}, /* no =: at&t manual wrong */ 1442 1.1 jtc {"+cd", c_cd}, 1443 1.1 jtc {"+command", c_command}, 1444 1.1 jtc {"echo", c_print}, 1445 1.1 jtc {"*=export", c_typeset}, 1446 1.1 jtc #ifdef HISTORY 1447 1.1 jtc {"+fc", c_fc}, 1448 1.1 jtc #endif /* HISTORY */ 1449 1.1 jtc {"+getopts", c_getopts}, 1450 1.1 jtc {"+jobs", c_jobs}, 1451 1.1 jtc {"+kill", c_kill}, 1452 1.2 tls #ifdef KSH 1453 1.1 jtc {"let", c_let}, 1454 1.2 tls #endif /* KSH */ 1455 1.1 jtc {"print", c_print}, 1456 1.1 jtc {"pwd", c_pwd}, 1457 1.1 jtc {"*=readonly", c_typeset}, 1458 1.1 jtc {"=typeset", c_typeset}, 1459 1.1 jtc {"+unalias", c_unalias}, 1460 1.1 jtc {"whence", c_whence}, 1461 1.1 jtc #ifdef JOBS 1462 1.1 jtc {"+bg", c_fgbg}, 1463 1.1 jtc {"+fg", c_fgbg}, 1464 1.1 jtc #endif 1465 1.1 jtc #ifdef EMACS 1466 1.1 jtc {"bind", c_bind}, 1467 1.1 jtc #endif 1468 1.1 jtc {NULL, NULL} 1469 1.1 jtc }; 1470