blob: 2b99a32543c8ae9ee4197be3dc94dd4a339180f6 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
Eric Andersen81fe1232003-07-29 06:38:40 +00008 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
10 *
11 *
Eric Andersencb57d552001-06-28 07:25:16 +000012 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
Eric Andersendf82f612001-06-28 07:46:40 +000015 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000019 *
Eric Andersendf82f612001-06-28 07:46:40 +000020 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
Eric Andersendf82f612001-06-28 07:46:40 +000029 *
Eric Andersenc470f442003-07-28 09:56:35 +000030 * Modified by Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
Eric Andersen2870d962001-07-02 17:27:21 +000031 *
Eric Andersendf82f612001-06-28 07:46:40 +000032 *
Eric Andersen81fe1232003-07-29 06:38:40 +000033 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000034 */
35
Eric Andersenc470f442003-07-28 09:56:35 +000036/*
37 * The follow should be set to reflect the type of system you have:
38 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
39 * define SYSV if you are running under System V.
40 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
41 * define DEBUG=2 to compile in and turn on debugging.
42 *
43 * When debugging is on, debugging info will be written to ./trace and
44 * a quit signal will generate a core dump.
45 */
Eric Andersen2870d962001-07-02 17:27:21 +000046
Eric Andersen2870d962001-07-02 17:27:21 +000047
Eric Andersenc470f442003-07-28 09:56:35 +000048
Eric Andersen5bb16772001-09-06 18:00:41 +000049#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000050
Eric Andersenc470f442003-07-28 09:56:35 +000051#define PROFILE 0
52
53#ifdef DEBUG
54#define _GNU_SOURCE
55#endif
56
57#include <sys/types.h>
58#include <sys/cdefs.h>
59#include <sys/ioctl.h>
60#include <sys/param.h>
61#include <sys/resource.h>
62#include <sys/stat.h>
63#include <sys/time.h>
64#include <sys/wait.h>
65
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70
71#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000072#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000073#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000074#include <ctype.h>
75#include <dirent.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <limits.h>
79#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000080#include <setjmp.h>
81#include <signal.h>
Eric Andersenc470f442003-07-28 09:56:35 +000082#include <stdint.h>
Eric Andersencb57d552001-06-28 07:25:16 +000083#include <sysexits.h>
Eric Andersenc470f442003-07-28 09:56:35 +000084
85#include <fnmatch.h>
86#include <glob.h>
87
88
89
Robert Grieblea1a63a2002-06-04 20:10:23 +000090#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000091#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000092
Eric Andersend35c5df2002-01-09 15:37:36 +000093#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000094#define JOBS 1
95#else
Eric Andersenca162042003-07-29 07:15:17 +000096#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +000097#endif
98
99#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000100#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000101#endif
102
Eric Andersen2870d962001-07-02 17:27:21 +0000103#include "cmdedit.h"
104
Eric Andersenc470f442003-07-28 09:56:35 +0000105#ifdef __GLIBC__
106/* glibc sucks */
107static int *dash_errno;
108#undef errno
109#define errno (*dash_errno)
110#endif
111
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000112#if defined(__uClinux__)
113#error "Do not even bother, ash will not run on uClinux"
114#endif
115
Eric Andersenc470f442003-07-28 09:56:35 +0000116#ifdef DEBUG
117#define _DIAGASSERT(assert_expr) assert(assert_expr)
118#else
119#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000120#endif
121
Eric Andersen2870d962001-07-02 17:27:21 +0000122
Eric Andersenc470f442003-07-28 09:56:35 +0000123#ifdef CONFIG_ASH_ALIAS
124/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
125
126#define ALIASINUSE 1
127#define ALIASDEAD 2
128
129struct alias {
130 struct alias *next;
131 char *name;
132 char *val;
133 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000134};
135
Eric Andersenc470f442003-07-28 09:56:35 +0000136static struct alias *lookupalias(const char *, int);
137static int aliascmd(int, char **);
138static int unaliascmd(int, char **);
139static void rmaliases(void);
140static int unalias(const char *);
141static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000142#endif
143
Eric Andersenc470f442003-07-28 09:56:35 +0000144/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
145
146
147static void setpwd(const char *, int);
148
149/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
150
151
152/*
153 * Types of operations (passed to the errmsg routine).
154 */
155
156
157static const char not_found_msg[] = "%s: not found";
158
159
160#define E_OPEN "No such file" /* opening a file */
161#define E_CREAT "Directory nonexistent" /* creating a file */
162#define E_EXEC not_found_msg+4 /* executing a program */
163
164/*
165 * We enclose jmp_buf in a structure so that we can declare pointers to
166 * jump locations. The global variable handler contains the location to
167 * jump to when an exception occurs, and the global variable exception
168 * contains a code identifying the exeception. To implement nested
169 * exception handlers, the user should save the value of handler on entry
170 * to an inner scope, set handler to point to a jmploc structure for the
171 * inner scope, and restore handler on exit from the scope.
172 */
173
174struct jmploc {
175 jmp_buf loc;
176};
177
178static struct jmploc *handler;
179static int exception;
180static volatile int suppressint;
181static volatile sig_atomic_t intpending;
182
183static int exerrno; /* Last exec error, error for EXEXEC */
184
185/* exceptions */
186#define EXINT 0 /* SIGINT received */
187#define EXERROR 1 /* a generic error */
188#define EXSHELLPROC 2 /* execute a shell procedure */
189#define EXEXEC 3 /* command execution failed */
190#define EXEXIT 4 /* exit the shell */
191#define EXSIG 5 /* trapped signal in wait(1) */
192
193
194/* do we generate EXSIG events */
195static int exsig;
196/* last pending signal */
197static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000198
199/*
200 * These macros allow the user to suspend the handling of interrupt signals
201 * over a period of time. This is similar to SIGHOLD to or sigblock, but
202 * much more efficient and portable. (But hacking the kernel is so much
203 * more fun than worrying about efficiency and portability. :-))
204 */
205
Eric Andersenc470f442003-07-28 09:56:35 +0000206#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
207#define INTOFF \
208 ({ \
209 suppressint++; \
210 barrier(); \
211 0; \
212 })
213#define SAVEINT(v) ((v) = suppressint)
214#define RESTOREINT(v) \
215 ({ \
216 barrier(); \
217 if ((suppressint = (v)) == 0 && intpending) onint(); \
218 0; \
219 })
220#define EXSIGON() \
221 ({ \
222 exsig++; \
223 barrier(); \
224 if (pendingsigs) \
225 exraise(EXSIG); \
226 0; \
227 })
228/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000229
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000230
Eric Andersenc470f442003-07-28 09:56:35 +0000231static void exraise(int) __attribute__((__noreturn__));
232static void onint(void) __attribute__((__noreturn__));
233
234static void error(const char *, ...) __attribute__((__noreturn__));
235static void exerror(int, const char *, ...) __attribute__((__noreturn__));
236
237static void sh_warnx(const char *, ...);
238
239#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
240static void
241inton(void) {
242 if (--suppressint == 0 && intpending) {
243 onint();
244 }
245}
246#define INTON inton()
247static void forceinton(void)
248{
249 suppressint = 0;
250 if (intpending)
251 onint();
252}
Eric Andersen3102ac42001-07-06 04:26:23 +0000253#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000254#else
Eric Andersenc470f442003-07-28 09:56:35 +0000255#define INTON \
256 ({ \
257 barrier(); \
258 if (--suppressint == 0 && intpending) onint(); \
259 0; \
260 })
261#define FORCEINTON \
262 ({ \
263 barrier(); \
264 suppressint = 0; \
265 if (intpending) onint(); \
266 0; \
267 })
268#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000269
270/*
Eric Andersenc470f442003-07-28 09:56:35 +0000271 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
272 * so we use _setjmp instead.
Eric Andersen2870d962001-07-02 17:27:21 +0000273 */
Eric Andersen2870d962001-07-02 17:27:21 +0000274
Eric Andersenc470f442003-07-28 09:56:35 +0000275#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
276#define setjmp(jmploc) _setjmp(jmploc)
277#define longjmp(jmploc, val) _longjmp(jmploc, val)
278#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000279
Eric Andersenc470f442003-07-28 09:56:35 +0000280/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000281
282struct strlist {
283 struct strlist *next;
284 char *text;
285};
286
287
288struct arglist {
289 struct strlist *list;
290 struct strlist **lastp;
291};
292
Eric Andersenc470f442003-07-28 09:56:35 +0000293/*
294 * expandarg() flags
295 */
296#define EXP_FULL 0x1 /* perform word splitting & file globbing */
297#define EXP_TILDE 0x2 /* do normal tilde expansion */
298#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
299#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
300#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
301#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
302#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
303#define EXP_WORD 0x80 /* expand word in parameter expansion */
304#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
305
306
307union node;
308static void expandarg(union node *, struct arglist *, int);
309#define rmescapes(p) _rmescapes((p), 0)
310static char *_rmescapes(char *, int);
311static int casematch(union node *, char *);
312
313#ifdef CONFIG_ASH_MATH_SUPPORT
314static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000315#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000316
Eric Andersenc470f442003-07-28 09:56:35 +0000317/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000318
Eric Andersenc470f442003-07-28 09:56:35 +0000319static char *commandname; /* currently executing command */
320static struct strlist *cmdenviron; /* environment for builtin command */
321static int exitstatus; /* exit status of last command */
322static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000323
Eric Andersenc470f442003-07-28 09:56:35 +0000324
325struct backcmd { /* result of evalbackcmd */
326 int fd; /* file descriptor to read from */
327 char *buf; /* buffer */
328 int nleft; /* number of chars in buffer */
329 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000330};
331
Eric Andersen62483552001-07-10 06:09:16 +0000332/*
Eric Andersenc470f442003-07-28 09:56:35 +0000333 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000334 */
Eric Andersenc470f442003-07-28 09:56:35 +0000335
336#define NCMD 0
337#define NPIPE 1
338#define NREDIR 2
339#define NBACKGND 3
340#define NSUBSHELL 4
341#define NAND 5
342#define NOR 6
343#define NSEMI 7
344#define NIF 8
345#define NWHILE 9
346#define NUNTIL 10
347#define NFOR 11
348#define NCASE 12
349#define NCLIST 13
350#define NDEFUN 14
351#define NARG 15
352#define NTO 16
353#define NCLOBBER 17
354#define NFROM 18
355#define NFROMTO 19
356#define NAPPEND 20
357#define NTOFD 21
358#define NFROMFD 22
359#define NHERE 23
360#define NXHERE 24
361#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000362
363
364
Eric Andersenc470f442003-07-28 09:56:35 +0000365struct ncmd {
366 int type;
367 union node *assign;
368 union node *args;
369 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000370};
371
372
Eric Andersenc470f442003-07-28 09:56:35 +0000373struct npipe {
374 int type;
375 int backgnd;
376 struct nodelist *cmdlist;
377};
Eric Andersen62483552001-07-10 06:09:16 +0000378
379
Eric Andersenc470f442003-07-28 09:56:35 +0000380struct nredir {
381 int type;
382 union node *n;
383 union node *redirect;
384};
Eric Andersen62483552001-07-10 06:09:16 +0000385
386
Eric Andersenc470f442003-07-28 09:56:35 +0000387struct nbinary {
388 int type;
389 union node *ch1;
390 union node *ch2;
391};
Eric Andersen2870d962001-07-02 17:27:21 +0000392
Eric Andersen2870d962001-07-02 17:27:21 +0000393
Eric Andersenc470f442003-07-28 09:56:35 +0000394struct nif {
395 int type;
396 union node *test;
397 union node *ifpart;
398 union node *elsepart;
399};
400
401
402struct nfor {
403 int type;
404 union node *args;
405 union node *body;
406 char *var;
407};
408
409
410struct ncase {
411 int type;
412 union node *expr;
413 union node *cases;
414};
415
416
417struct nclist {
418 int type;
419 union node *next;
420 union node *pattern;
421 union node *body;
422};
423
424
425struct narg {
426 int type;
427 union node *next;
428 char *text;
429 struct nodelist *backquote;
430};
431
432
433struct nfile {
434 int type;
435 union node *next;
436 int fd;
437 union node *fname;
438 char *expfname;
439};
440
441
442struct ndup {
443 int type;
444 union node *next;
445 int fd;
446 int dupfd;
447 union node *vname;
448};
449
450
451struct nhere {
452 int type;
453 union node *next;
454 int fd;
455 union node *doc;
456};
457
458
459struct nnot {
460 int type;
461 union node *com;
462};
463
464
465union node {
466 int type;
467 struct ncmd ncmd;
468 struct npipe npipe;
469 struct nredir nredir;
470 struct nbinary nbinary;
471 struct nif nif;
472 struct nfor nfor;
473 struct ncase ncase;
474 struct nclist nclist;
475 struct narg narg;
476 struct nfile nfile;
477 struct ndup ndup;
478 struct nhere nhere;
479 struct nnot nnot;
480};
481
482
483struct nodelist {
484 struct nodelist *next;
485 union node *n;
486};
487
488
489struct funcnode {
490 int count;
491 union node n;
492};
493
494
495static void freefunc(struct funcnode *);
496/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
497
498/* control characters in argument strings */
499#define CTL_FIRST '\201' /* first 'special' character */
500#define CTLESC '\201' /* escape next character */
501#define CTLVAR '\202' /* variable defn */
502#define CTLENDVAR '\203'
503#define CTLBACKQ '\204'
504#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
505/* CTLBACKQ | CTLQUOTE == '\205' */
506#define CTLARI '\206' /* arithmetic expression */
507#define CTLENDARI '\207'
508#define CTLQUOTEMARK '\210'
509#define CTL_LAST '\210' /* last 'special' character */
510
511/* variable substitution byte (follows CTLVAR) */
512#define VSTYPE 0x0f /* type of variable substitution */
513#define VSNUL 0x10 /* colon--treat the empty string as unset */
514#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
515
516/* values of VSTYPE field */
517#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
518#define VSMINUS 0x2 /* ${var-text} */
519#define VSPLUS 0x3 /* ${var+text} */
520#define VSQUESTION 0x4 /* ${var?message} */
521#define VSASSIGN 0x5 /* ${var=text} */
522#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
523#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
524#define VSTRIMLEFT 0x8 /* ${var#pattern} */
525#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
526#define VSLENGTH 0xa /* ${#var} */
527
528/* values of checkkwd variable */
529#define CHKALIAS 0x1
530#define CHKKWD 0x2
531#define CHKNL 0x4
532
533#define IBUFSIZ (BUFSIZ + 1)
534
535/*
536 * NEOF is returned by parsecmd when it encounters an end of file. It
537 * must be distinct from NULL, so we use the address of a variable that
538 * happens to be handy.
539 */
540static int plinno = 1; /* input line number */
541
542/* number of characters left in input buffer */
543static int parsenleft; /* copy of parsefile->nleft */
544static int parselleft; /* copy of parsefile->lleft */
545
546/* next character in input buffer */
547static char *parsenextc; /* copy of parsefile->nextc */
548static struct parsefile basepf; /* top level input file */
549static char basebuf[IBUFSIZ]; /* buffer for top level input file */
550static struct parsefile *parsefile = &basepf; /* current input file */
551
552
553static int tokpushback; /* last token pushed back */
554#define NEOF ((union node *)&tokpushback)
555static int parsebackquote; /* nonzero if we are inside backquotes */
556static int doprompt; /* if set, prompt the user */
557static int needprompt; /* true if interactive and at start of line */
558static int lasttoken; /* last token read */
559static char *wordtext; /* text of last word returned by readtoken */
560static int checkkwd;
561static struct nodelist *backquotelist;
562static union node *redirnode;
563static struct heredoc *heredoc;
564static int quoteflag; /* set if (part of) last token was quoted */
565static int startlinno; /* line # where last token started */
566
567static union node *parsecmd(int);
568static void fixredir(union node *, const char *, int);
569static const char *const *findkwd(const char *);
570static char *endofname(const char *);
571
572/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
573
574typedef void *pointer;
575
576static char nullstr[1]; /* zero length string */
577static const char spcstr[] = " ";
578static const char snlfmt[] = "%s\n";
579static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
580static const char illnum[] = "Illegal number: %s";
581static const char homestr[] = "HOME";
582
583#ifdef DEBUG
584#define TRACE(param) trace param
585#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000586#else
Eric Andersenc470f442003-07-28 09:56:35 +0000587#define TRACE(param)
588#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000589#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000590
Eric Andersenc470f442003-07-28 09:56:35 +0000591#if defined(__GNUC__) && __GNUC__ < 3
592#define va_copy __va_copy
593#endif
594
595#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
596#define __builtin_expect(x, expected_value) (x)
597#endif
598
599#define likely(x) __builtin_expect((x),1)
600#define unlikely(x) __builtin_expect((x),0)
601
602#define TEOF 0
603#define TNL 1
604#define TREDIR 2
605#define TWORD 3
606#define TSEMI 4
607#define TBACKGND 5
608#define TAND 6
609#define TOR 7
610#define TPIPE 8
611#define TLP 9
612#define TRP 10
613#define TENDCASE 11
614#define TENDBQUOTE 12
615#define TNOT 13
616#define TCASE 14
617#define TDO 15
618#define TDONE 16
619#define TELIF 17
620#define TELSE 18
621#define TESAC 19
622#define TFI 20
623#define TFOR 21
624#define TIF 22
625#define TIN 23
626#define TTHEN 24
627#define TUNTIL 25
628#define TWHILE 26
629#define TBEGIN 27
630#define TEND 28
631
632/* first char is indicating which tokens mark the end of a list */
633static const char *const tokname_array[] = {
634 "\1end of file",
635 "\0newline",
636 "\0redirection",
637 "\0word",
638 "\0;",
639 "\0&",
640 "\0&&",
641 "\0||",
642 "\0|",
643 "\0(",
644 "\1)",
645 "\1;;",
646 "\1`",
647#define KWDOFFSET 13
648 /* the following are keywords */
649 "\0!",
650 "\0case",
651 "\1do",
652 "\1done",
653 "\1elif",
654 "\1else",
655 "\1esac",
656 "\1fi",
657 "\0for",
658 "\0if",
659 "\0in",
660 "\1then",
661 "\0until",
662 "\0while",
663 "\0{",
664 "\1}",
665};
666
667static const char *tokname(int tok)
668{
669 static char buf[16];
670
671 if (tok >= TSEMI)
672 buf[0] = '"';
673 sprintf(buf + (tok >= TSEMI), "%s%c",
674 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
675 return buf;
676}
677
678/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
679
680/*
681 * Most machines require the value returned from malloc to be aligned
682 * in some way. The following macro will get this right on many machines.
683 */
684
685#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
686/*
687 * It appears that grabstackstr() will barf with such alignments
688 * because stalloc() will return a string allocated in a new stackblock.
689 */
690#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
691
692/*
693 * This file was generated by the mksyntax program.
694 */
695
696
697/* Syntax classes */
698#define CWORD 0 /* character is nothing special */
699#define CNL 1 /* newline character */
700#define CBACK 2 /* a backslash character */
701#define CSQUOTE 3 /* single quote */
702#define CDQUOTE 4 /* double quote */
703#define CENDQUOTE 5 /* a terminating quote */
704#define CBQUOTE 6 /* backwards single quote */
705#define CVAR 7 /* a dollar sign */
706#define CENDVAR 8 /* a '}' character */
707#define CLP 9 /* a left paren in arithmetic */
708#define CRP 10 /* a right paren in arithmetic */
709#define CENDFILE 11 /* end of file */
710#define CCTL 12 /* like CWORD, except it must be escaped */
711#define CSPCL 13 /* these terminate a word */
712#define CIGN 14 /* character should be ignored */
713
714#ifdef CONFIG_ASH_ALIAS
715#define SYNBASE 130
716#define PEOF -130
717#define PEOA -129
718#define PEOA_OR_PEOF PEOA
719#else
720#define SYNBASE 129
721#define PEOF -129
722#define PEOA_OR_PEOF PEOF
723#endif
724
725#define is_digit(c) ((unsigned)((c) - '0') <= 9)
726#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
727#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
728
729/*
730 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
731 * (assuming ascii char codes, as the original implementation did)
732 */
733#define is_special(c) \
734 ( (((unsigned int)c) - 33 < 32) \
735 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
736
737#define digit_val(c) ((c) - '0')
738
739/*
740 * This file was generated by the mksyntax program.
741 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000742
Eric Andersend35c5df2002-01-09 15:37:36 +0000743#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000744#define USE_SIT_FUNCTION
745#endif
746
747/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000748#define BASESYNTAX 0 /* not in quotes */
749#define DQSYNTAX 1 /* in double quotes */
750#define SQSYNTAX 2 /* in single quotes */
751#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000752
Eric Andersenc470f442003-07-28 09:56:35 +0000753#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000754static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000755#ifdef CONFIG_ASH_ALIAS
756 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
757#endif
758 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
759 {CNL, CNL, CNL, CNL}, /* 2, \n */
760 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
761 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
762 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
763 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
764 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
765 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
766 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
767 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
768 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000769#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000770 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
771 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
772 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000773#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000774};
Eric Andersenc470f442003-07-28 09:56:35 +0000775#else
776static const char S_I_T[][3] = {
777#ifdef CONFIG_ASH_ALIAS
778 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
779#endif
780 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
781 {CNL, CNL, CNL}, /* 2, \n */
782 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
783 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
784 {CVAR, CVAR, CWORD}, /* 5, $ */
785 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
786 {CSPCL, CWORD, CWORD}, /* 7, ( */
787 {CSPCL, CWORD, CWORD}, /* 8, ) */
788 {CBACK, CBACK, CCTL}, /* 9, \ */
789 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
790 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
791#ifndef USE_SIT_FUNCTION
792 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
793 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
794 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
795#endif
796};
797#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000798
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000799#ifdef USE_SIT_FUNCTION
800
801#define U_C(c) ((unsigned char)(c))
802
803static int SIT(int c, int syntax)
804{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000805 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000806#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000807 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000808 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
809 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
810 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
811 11, 3 /* "}~" */
812 };
813#else
814 static const char syntax_index_table[] = {
815 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
816 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
817 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
818 10, 2 /* "}~" */
819 };
820#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000821 const char *s;
822 int indx;
823
Eric Andersenc470f442003-07-28 09:56:35 +0000824 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000825 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000826#ifdef CONFIG_ASH_ALIAS
827 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000828 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000829 else
830#endif
831 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
832 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000833 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000834 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000835 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000836 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000837 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000838 }
839 return S_I_T[indx][syntax];
840}
841
Eric Andersenc470f442003-07-28 09:56:35 +0000842#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000843
844#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
845
Eric Andersenc470f442003-07-28 09:56:35 +0000846#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000847#define CSPCL_CIGN_CIGN_CIGN 0
848#define CSPCL_CWORD_CWORD_CWORD 1
849#define CNL_CNL_CNL_CNL 2
850#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000851#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000852#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000853#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000854#define CSPCL_CWORD_CWORD_CLP 7
855#define CSPCL_CWORD_CWORD_CRP 8
856#define CBACK_CBACK_CCTL_CBACK 9
857#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
858#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
859#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
860#define CWORD_CWORD_CWORD_CWORD 13
861#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000862#else
863#define CSPCL_CWORD_CWORD_CWORD 0
864#define CNL_CNL_CNL_CNL 1
865#define CWORD_CCTL_CCTL_CWORD 2
866#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
867#define CVAR_CVAR_CWORD_CVAR 4
868#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
869#define CSPCL_CWORD_CWORD_CLP 6
870#define CSPCL_CWORD_CWORD_CRP 7
871#define CBACK_CBACK_CCTL_CBACK 8
872#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
873#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
874#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
875#define CWORD_CWORD_CWORD_CWORD 12
876#define CCTL_CCTL_CCTL_CCTL 13
877#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000878
879static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000880 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000881 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
882#ifdef CONFIG_ASH_ALIAS
883 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
884#endif
885 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
886 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
887 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
888 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
889 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
890 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
891 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
892 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
893 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000894 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
895 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
896 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
897 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
898 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
899 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
900 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
901 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
902 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
903 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
904 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
905 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
906 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
907 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
908 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
909 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
910 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
911 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
912 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
913 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
914 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
915 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
916 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
917 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
918 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
919 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
920 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
921 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
922 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
923 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
924 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
925 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
926 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
927 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
928 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
929 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
930 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
931 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
932 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
933 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
934 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
935 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
936 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
937 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
938 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
939 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
940 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
941 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
942 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
943 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
944 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
945 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
946 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
947 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
948 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
949 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
950 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
951 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
952 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
953 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
954 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
955 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
956 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
957 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
958 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
959 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
960 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
961 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
962 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
963 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
964 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
965 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
966 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
967 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
968 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
969 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
970 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
971 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
972 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
973 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
974 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
975 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
976 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
977 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
978 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
979 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
980 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
981 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
982 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
983 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
984 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
985 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
986 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
987 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
988 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
989 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
990 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
991 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
992 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
993 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
994 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
995 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
996 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
997 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
998 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
999 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1023 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1024 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1046 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001047 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001048 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1049 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1050 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1051 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001052 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001053 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1054 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1055 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1056 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1057 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1058 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1059 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1060 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1061 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1062 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1063 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1072 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1073 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1075 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1078 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1106 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1107 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1110 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1138 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1139 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1140 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001141};
1142
Eric Andersenc470f442003-07-28 09:56:35 +00001143#endif /* USE_SIT_FUNCTION */
1144
1145/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001146
Eric Andersen2870d962001-07-02 17:27:21 +00001147
Eric Andersenc470f442003-07-28 09:56:35 +00001148#define ATABSIZE 39
1149
1150static int funcblocksize; /* size of structures in function */
1151static int funcstringsize; /* size of strings in node */
1152static pointer funcblock; /* block to allocate function from */
1153static char *funcstring; /* block to allocate strings from */
1154
1155static const short nodesize[26] = {
1156 SHELL_ALIGN(sizeof (struct ncmd)),
1157 SHELL_ALIGN(sizeof (struct npipe)),
1158 SHELL_ALIGN(sizeof (struct nredir)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nbinary)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nif)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nfor)),
1168 SHELL_ALIGN(sizeof (struct ncase)),
1169 SHELL_ALIGN(sizeof (struct nclist)),
1170 SHELL_ALIGN(sizeof (struct narg)),
1171 SHELL_ALIGN(sizeof (struct narg)),
1172 SHELL_ALIGN(sizeof (struct nfile)),
1173 SHELL_ALIGN(sizeof (struct nfile)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct ndup)),
1178 SHELL_ALIGN(sizeof (struct ndup)),
1179 SHELL_ALIGN(sizeof (struct nhere)),
1180 SHELL_ALIGN(sizeof (struct nhere)),
1181 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001182};
1183
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001184
Eric Andersenc470f442003-07-28 09:56:35 +00001185static void calcsize(union node *);
1186static void sizenodelist(struct nodelist *);
1187static union node *copynode(union node *);
1188static struct nodelist *copynodelist(struct nodelist *);
1189static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001190
1191
Eric Andersen2870d962001-07-02 17:27:21 +00001192
Eric Andersenc470f442003-07-28 09:56:35 +00001193static void evalstring(char *, int);
1194union node; /* BLETCH for ansi C */
1195static void evaltree(union node *, int);
1196static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001197
Eric Andersenc470f442003-07-28 09:56:35 +00001198/* in_function returns nonzero if we are currently evaluating a function */
1199#define in_function() funcnest
1200static int evalskip; /* set if we are skipping commands */
1201static int skipcount; /* number of levels to skip */
1202static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001203
1204/* reasons for skipping commands (see comment on breakcmd routine) */
1205#define SKIPBREAK 1
1206#define SKIPCONT 2
1207#define SKIPFUNC 3
1208#define SKIPFILE 4
1209
Eric Andersenc470f442003-07-28 09:56:35 +00001210/*
1211 * This file was generated by the mkbuiltins program.
1212 */
Eric Andersen2870d962001-07-02 17:27:21 +00001213
Eric Andersenc470f442003-07-28 09:56:35 +00001214#ifdef JOBS
1215static int bgcmd(int, char **);
1216#endif
1217static int breakcmd(int, char **);
1218static int cdcmd(int, char **);
1219#ifdef CONFIG_ASH_CMDCMD
1220static int commandcmd(int, char **);
1221#endif
1222static int dotcmd(int, char **);
1223static int evalcmd(int, char **);
1224static int execcmd(int, char **);
1225static int exitcmd(int, char **);
1226#ifdef CONFIG_ASH_MATH_SUPPORT
1227static int expcmd(int, char **);
1228#endif
1229static int exportcmd(int, char **);
1230static int falsecmd(int, char **);
1231#ifdef JOBS
1232static int fgcmd(int, char **);
1233#endif
1234#ifdef CONFIG_ASH_GETOPTS
1235static int getoptscmd(int, char **);
1236#endif
1237static int hashcmd(int, char **);
1238#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1239static int helpcmd(int argc, char **argv);
1240#endif
1241#ifdef JOBS
1242static int jobscmd(int, char **);
1243#endif
1244static int localcmd(int, char **);
1245static int pwdcmd(int, char **);
1246static int readcmd(int, char **);
1247static int returncmd(int, char **);
1248static int setcmd(int, char **);
1249static int shiftcmd(int, char **);
1250static int timescmd(int, char **);
1251static int trapcmd(int, char **);
1252static int truecmd(int, char **);
1253static int typecmd(int, char **);
1254static int umaskcmd(int, char **);
1255static int unsetcmd(int, char **);
1256static int waitcmd(int, char **);
1257static int ulimitcmd(int, char **);
1258#ifdef JOBS
1259static int killcmd(int, char **);
1260#endif
1261
1262/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1263
1264#ifdef CONFIG_ASH_MAIL
1265static void chkmail(void);
1266static void changemail(const char *);
1267#endif
1268
1269/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1270
1271/* values of cmdtype */
1272#define CMDUNKNOWN -1 /* no entry in table for command */
1273#define CMDNORMAL 0 /* command is an executable program */
1274#define CMDFUNCTION 1 /* command is a shell function */
1275#define CMDBUILTIN 2 /* command is a shell builtin */
1276
1277struct builtincmd {
1278 const char *name;
1279 int (*builtin)(int, char **);
1280 /* unsigned flags; */
1281};
1282
1283#ifdef CONFIG_ASH_CMDCMD
1284# ifdef JOBS
1285# ifdef CONFIG_ASH_ALIAS
1286# define COMMANDCMD (builtincmd + 7)
1287# define EXECCMD (builtincmd + 10)
1288# else
1289# define COMMANDCMD (builtincmd + 6)
1290# define EXECCMD (builtincmd + 9)
1291# endif
1292# else /* ! JOBS */
1293# ifdef CONFIG_ASH_ALIAS
1294# define COMMANDCMD (builtincmd + 6)
1295# define EXECCMD (builtincmd + 9)
1296# else
1297# define COMMANDCMD (builtincmd + 5)
1298# define EXECCMD (builtincmd + 8)
1299# endif
1300# endif /* JOBS */
1301#else /* ! CONFIG_ASH_CMDCMD */
1302# ifdef JOBS
1303# ifdef CONFIG_ASH_ALIAS
1304# define EXECCMD (builtincmd + 9)
1305# else
1306# define EXECCMD (builtincmd + 8)
1307# endif
1308# else /* ! JOBS */
1309# ifdef CONFIG_ASH_ALIAS
1310# define EXECCMD (builtincmd + 8)
1311# else
1312# define EXECCMD (builtincmd + 7)
1313# endif
1314# endif /* JOBS */
1315#endif /* CONFIG_ASH_CMDCMD */
1316
1317#define BUILTIN_NOSPEC "0"
1318#define BUILTIN_SPECIAL "1"
1319#define BUILTIN_REGULAR "2"
1320#define BUILTIN_SPEC_REG "3"
1321#define BUILTIN_ASSIGN "4"
1322#define BUILTIN_SPEC_ASSG "5"
1323#define BUILTIN_REG_ASSG "6"
1324#define BUILTIN_SPEC_REG_ASSG "7"
1325
1326#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1327#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1328
1329static const struct builtincmd builtincmd[] = {
1330 { BUILTIN_SPEC_REG ".", dotcmd },
1331 { BUILTIN_SPEC_REG ":", truecmd },
1332#ifdef CONFIG_ASH_ALIAS
1333 { BUILTIN_REG_ASSG "alias", aliascmd },
1334#endif
1335#ifdef JOBS
1336 { BUILTIN_REGULAR "bg", bgcmd },
1337#endif
1338 { BUILTIN_SPEC_REG "break", breakcmd },
1339 { BUILTIN_REGULAR "cd", cdcmd },
1340 { BUILTIN_NOSPEC "chdir", cdcmd },
1341#ifdef CONFIG_ASH_CMDCMD
1342 { BUILTIN_REGULAR "command", commandcmd },
1343#endif
1344 { BUILTIN_SPEC_REG "continue", breakcmd },
1345 { BUILTIN_SPEC_REG "eval", evalcmd },
1346 { BUILTIN_SPEC_REG "exec", execcmd },
1347 { BUILTIN_SPEC_REG "exit", exitcmd },
1348#ifdef CONFIG_ASH_MATH_SUPPORT
1349 { BUILTIN_NOSPEC "exp", expcmd },
1350#endif
1351 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1352 { BUILTIN_REGULAR "false", falsecmd },
1353#ifdef JOBS
1354 { BUILTIN_REGULAR "fg", fgcmd },
1355#endif
1356#ifdef CONFIG_ASH_GETOPTS
1357 { BUILTIN_REGULAR "getopts", getoptscmd },
1358#endif
1359 { BUILTIN_NOSPEC "hash", hashcmd },
1360#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1361 { BUILTIN_NOSPEC "help", helpcmd },
1362#endif
1363#ifdef JOBS
1364 { BUILTIN_REGULAR "jobs", jobscmd },
1365 { BUILTIN_REGULAR "kill", killcmd },
1366#endif
1367#ifdef CONFIG_ASH_MATH_SUPPORT
1368 { BUILTIN_NOSPEC "let", expcmd },
1369#endif
1370 { BUILTIN_ASSIGN "local", localcmd },
1371 { BUILTIN_NOSPEC "pwd", pwdcmd },
1372 { BUILTIN_REGULAR "read", readcmd },
1373 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1374 { BUILTIN_SPEC_REG "return", returncmd },
1375 { BUILTIN_SPEC_REG "set", setcmd },
1376 { BUILTIN_SPEC_REG "shift", shiftcmd },
1377 { BUILTIN_SPEC_REG "times", timescmd },
1378 { BUILTIN_SPEC_REG "trap", trapcmd },
1379 { BUILTIN_REGULAR "true", truecmd },
1380 { BUILTIN_NOSPEC "type", typecmd },
1381 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1382 { BUILTIN_REGULAR "umask", umaskcmd },
1383#ifdef CONFIG_ASH_ALIAS
1384 { BUILTIN_REGULAR "unalias", unaliascmd },
1385#endif
1386 { BUILTIN_SPEC_REG "unset", unsetcmd },
1387 { BUILTIN_REGULAR "wait", waitcmd },
1388};
1389
1390#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1391
1392
1393
1394struct cmdentry {
1395 int cmdtype;
1396 union param {
1397 int index;
1398 const struct builtincmd *cmd;
1399 struct funcnode *func;
1400 } u;
1401};
1402
1403
1404/* action to find_command() */
1405#define DO_ERR 0x01 /* prints errors */
1406#define DO_ABS 0x02 /* checks absolute paths */
1407#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1408#define DO_ALTPATH 0x08 /* using alternate path */
1409#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1410
1411static const char *pathopt; /* set by padvance */
1412
1413static void shellexec(char **, const char *, int)
1414 __attribute__((__noreturn__));
1415static char *padvance(const char **, const char *);
1416static void find_command(char *, struct cmdentry *, int, const char *);
1417static struct builtincmd *find_builtin(const char *);
1418static void hashcd(void);
1419static void changepath(const char *);
1420static void defun(char *, union node *);
1421static void unsetfunc(const char *);
1422
1423#ifdef CONFIG_ASH_MATH_SUPPORT
1424/* From arith.y */
1425static int dash_arith(const char *);
1426#endif
1427
1428/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1429
1430static void reset(void);
1431
1432/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001433
1434/*
1435 * Shell variables.
1436 */
1437
1438/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001439#define VEXPORT 0x01 /* variable is exported */
1440#define VREADONLY 0x02 /* variable cannot be modified */
1441#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1442#define VTEXTFIXED 0x08 /* text is statically allocated */
1443#define VSTACK 0x10 /* text is allocated on the stack */
1444#define VUNSET 0x20 /* the variable is not set */
1445#define VNOFUNC 0x40 /* don't call the callback function */
1446#define VNOSET 0x80 /* do not set variable - just readonly test */
1447#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen2870d962001-07-02 17:27:21 +00001448
1449
1450struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001451 struct var *next; /* next entry in hash list */
1452 int flags; /* flags are defined above */
1453 const char *text; /* name=value */
1454 void (*func)(const char *);
1455 /* function to be called when */
1456 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001457};
1458
1459struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001460 struct localvar *next; /* next local variable in list */
1461 struct var *vp; /* the variable that was made local */
1462 int flags; /* saved flags */
1463 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001464};
1465
1466
Eric Andersen2870d962001-07-02 17:27:21 +00001467static struct localvar *localvars;
1468
Eric Andersenc470f442003-07-28 09:56:35 +00001469/*
1470 * Shell variables.
1471 */
1472
1473#ifdef CONFIG_ASH_GETOPTS
1474static void getoptsreset(const char *);
1475#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001476
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001477#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001478#include <locale.h>
1479static void change_lc_all(const char *value);
1480static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001481#endif
1482
Eric Andersen2870d962001-07-02 17:27:21 +00001483#define VTABSIZE 39
1484
Eric Andersenc470f442003-07-28 09:56:35 +00001485static const char defpathvar[] =
1486 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1487#ifdef IFS_BROKEN
1488static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001489#define defifs (defifsvar + 4)
1490#else
Eric Andersenc470f442003-07-28 09:56:35 +00001491static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001492#endif
1493
Eric Andersenc470f442003-07-28 09:56:35 +00001494
1495static struct var varinit[] = {
1496#ifdef IFS_BROKEN
1497 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1498#else
1499 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1500#endif
1501
1502#ifdef CONFIG_ASH_MAIL
1503 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1504 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1505#endif
1506
1507 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1508 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1509 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1510 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1511#ifdef CONFIG_ASH_GETOPTS
1512 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1513#endif
1514#ifdef CONFIG_LOCALE_SUPPORT
1515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1516 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1517#endif
1518#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1519 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1520#endif
1521};
1522
1523#define vifs varinit[0]
1524#ifdef CONFIG_ASH_MAIL
1525#define vmail (&vifs)[1]
1526#define vmpath (&vmail)[1]
1527#else
1528#define vmpath vifs
1529#endif
1530#define vpath (&vmpath)[1]
1531#define vps1 (&vpath)[1]
1532#define vps2 (&vps1)[1]
1533#define vps4 (&vps2)[1]
1534#define voptind (&vps4)[1]
1535
1536#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001537
1538/*
1539 * The following macros access the values of the above variables.
1540 * They have to skip over the name. They return the null string
1541 * for unset variables.
1542 */
1543
1544#define ifsval() (vifs.text + 4)
1545#define ifsset() ((vifs.flags & VUNSET) == 0)
1546#define mailval() (vmail.text + 5)
1547#define mpathval() (vmpath.text + 9)
1548#define pathval() (vpath.text + 5)
1549#define ps1val() (vps1.text + 4)
1550#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001551#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001552#define optindval() (voptind.text + 7)
1553
1554#define mpathset() ((vmpath.flags & VUNSET) == 0)
1555
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001556static void setvar(const char *, const char *, int);
1557static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001558static void listsetvar(struct strlist *, int);
1559static char *lookupvar(const char *);
1560static char *bltinlookup(const char *);
1561static char **listvars(int, int, char ***);
1562#define environment() listvars(VEXPORT, VUNSET, 0)
1563static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001564static void poplocalvars(void);
1565static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001566#ifdef CONFIG_ASH_GETOPTS
1567static int setvarsafe(const char *, const char *, int);
1568#endif
1569static int varcmp(const char *, const char *);
1570static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001571
1572
Eric Andersenc470f442003-07-28 09:56:35 +00001573static inline int varequal(const char *a, const char *b) {
1574 return !varcmp(a, b);
1575}
Eric Andersen2870d962001-07-02 17:27:21 +00001576
1577
Eric Andersenc470f442003-07-28 09:56:35 +00001578static int loopnest; /* current loop nesting level */
1579
1580struct strpush {
1581 struct strpush *prev; /* preceding string on stack */
1582 char *prevstring;
1583 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00001584#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00001585 struct alias *ap; /* if push was associated with an alias */
1586#endif
1587 char *string; /* remember the string since it may change */
Eric Andersen2870d962001-07-02 17:27:21 +00001588};
1589
Eric Andersenc470f442003-07-28 09:56:35 +00001590struct parsefile {
1591 struct parsefile *prev; /* preceding file on stack */
1592 int linno; /* current line */
1593 int fd; /* file descriptor (or -1 if string) */
1594 int nleft; /* number of chars left in this line */
1595 int lleft; /* number of chars left in this buffer */
1596 char *nextc; /* next char in buffer */
1597 char *buf; /* input buffer */
1598 struct strpush *strpush; /* for pushing strings at this level */
1599 struct strpush basestrpush; /* so pushing one is fast */
1600};
1601
1602/*
1603 * The parsefile structure pointed to by the global variable parsefile
1604 * contains information about the current file being read.
1605 */
1606
1607
1608struct redirtab {
1609 struct redirtab *next;
1610 int renamed[10];
1611 int nullredirs;
1612};
1613
1614static struct redirtab *redirlist;
1615static int nullredirs;
1616
1617extern char **environ;
1618
1619/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1620
1621
1622static void outstr(const char *, FILE *);
1623static void outcslow(int, FILE *);
1624static void flushall(void);
1625static void flushout(FILE *);
1626static int out1fmt(const char *, ...)
1627 __attribute__((__format__(__printf__,1,2)));
1628static int fmtstr(char *, size_t, const char *, ...)
1629 __attribute__((__format__(__printf__,3,4)));
1630static void xwrite(int, const void *, size_t);
1631
1632
1633#define outerr(f) ferror(f)
1634#define out2c(c) outcslow((c), stderr)
1635
1636static void out1str(const char *p)
1637{
1638 outstr(p, stdout);
1639}
1640
1641static void out2str(const char *p)
1642{
1643 outstr(p, stderr);
1644}
1645
1646static void out1c(char c)
1647{
1648 char s[2];
1649
1650 s[0] = c;
1651 s[1] = 0;
1652 outstr(s, stdout);
1653}
1654
1655/*
1656 * Initialization code.
1657 */
1658
1659/*
1660 * This routine initializes the builtin variables.
1661 */
1662
1663static inline void
1664initvar(void)
1665{
1666 struct var *vp;
1667 struct var *end;
1668 struct var **vpp;
1669
1670 /*
1671 * PS1 depends on uid
1672 */
1673#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1674 vps1.text = "PS1=\\w \\$ ";
1675#else
1676 if (!geteuid())
1677 vps1.text = "PS1=# ";
1678#endif
1679 vp = varinit;
1680 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1681 do {
1682 vpp = hashvar(vp->text);
1683 vp->next = *vpp;
1684 *vpp = vp;
1685 } while (++vp < end);
1686}
1687
1688static inline void
1689init(void)
1690{
1691
1692 /* from input.c: */
1693 {
1694 basepf.nextc = basepf.buf = basebuf;
1695 }
1696
1697 /* from trap.c: */
1698 {
1699 signal(SIGCHLD, SIG_DFL);
1700 }
1701
1702 /* from var.c: */
1703 {
1704 char **envp;
1705 char ppid[32];
1706
1707 initvar();
1708 for (envp = environ ; *envp ; envp++) {
1709 if (strchr(*envp, '=')) {
1710 setvareq(*envp, VEXPORT|VTEXTFIXED);
1711 }
1712 }
1713
1714 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1715 setvar("PPID", ppid, 0);
1716 setpwd(0, 0);
1717 }
1718}
1719
1720/* PEOF (the end of file marker) */
1721
1722/*
1723 * The input line number. Input.c just defines this variable, and saves
1724 * and restores it when files are pushed and popped. The user of this
1725 * package must set its value.
1726 */
1727
1728static int pgetc(void);
1729static int pgetc2(void);
1730static int preadbuffer(void);
1731static void pungetc(void);
1732static void pushstring(char *, void *);
1733static void popstring(void);
1734static void setinputfile(const char *, int);
1735static void setinputfd(int, int);
1736static void setinputstring(char *);
1737static void popfile(void);
1738static void popallfiles(void);
1739static void closescript(void);
1740
1741
1742/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1743
1744
1745/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1746#define FORK_FG 0
1747#define FORK_BG 1
1748#define FORK_NOJOB 2
1749
1750/* mode flags for showjob(s) */
1751#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1752#define SHOW_PID 0x04 /* include process pid */
1753#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1754
1755
1756/*
1757 * A job structure contains information about a job. A job is either a
1758 * single process or a set of processes contained in a pipeline. In the
1759 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1760 * array of pids.
1761 */
1762
1763struct procstat {
1764 pid_t pid; /* process id */
1765 int status; /* last process status from wait() */
1766 char *cmd; /* text of command being run */
1767};
1768
1769struct job {
1770 struct procstat ps0; /* status of process */
1771 struct procstat *ps; /* status or processes when more than one */
1772#if JOBS
1773 int stopstatus; /* status of a stopped job */
1774#endif
1775 uint32_t
1776 nprocs: 16, /* number of processes */
1777 state: 8,
1778#define JOBRUNNING 0 /* at least one proc running */
1779#define JOBSTOPPED 1 /* all procs are stopped */
1780#define JOBDONE 2 /* all procs are completed */
1781#if JOBS
1782 sigint: 1, /* job was killed by SIGINT */
1783 jobctl: 1, /* job running under job control */
1784#endif
1785 waited: 1, /* true if this entry has been waited for */
1786 used: 1, /* true if this entry is in used */
1787 changed: 1; /* true if status has changed */
1788 struct job *prev_job; /* previous job */
1789};
1790
1791static pid_t backgndpid; /* pid of last background process */
1792static int job_warning; /* user was warned about stopped jobs */
1793#if JOBS
1794static int jobctl; /* true if doing job control */
1795#endif
1796
1797static struct job *makejob(union node *, int);
1798static int forkshell(struct job *, union node *, int);
1799static int waitforjob(struct job *);
1800static int stoppedjobs(void);
1801
1802#if ! JOBS
1803#define setjobctl(on) /* do nothing */
1804#else
1805static void setjobctl(int);
1806static void showjobs(FILE *, int);
1807#endif
1808
1809/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1810
1811
1812/* pid of main shell */
1813static int rootpid;
1814/* true if we aren't a child of the main shell */
1815static int rootshell;
1816
1817static void readcmdfile(char *);
1818static void cmdloop(int);
1819
1820/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1821
1822
1823struct stackmark {
1824 struct stack_block *stackp;
1825 char *stacknxt;
1826 size_t stacknleft;
1827 struct stackmark *marknext;
1828};
1829
1830/* minimum size of a block */
1831#define MINSIZE SHELL_ALIGN(504)
1832
1833struct stack_block {
1834 struct stack_block *prev;
1835 char space[MINSIZE];
1836};
1837
1838static struct stack_block stackbase;
1839static struct stack_block *stackp = &stackbase;
1840static struct stackmark *markp;
1841static char *stacknxt = stackbase.space;
1842static size_t stacknleft = MINSIZE;
1843static char *sstrend = stackbase.space + MINSIZE;
1844static int herefd = -1;
1845
1846
1847static pointer ckmalloc(size_t);
1848static pointer ckrealloc(pointer, size_t);
1849static char *savestr(const char *);
1850static pointer stalloc(size_t);
1851static void stunalloc(pointer);
1852static void setstackmark(struct stackmark *);
1853static void popstackmark(struct stackmark *);
1854static void growstackblock(void);
1855static void *growstackstr(void);
1856static char *makestrspace(size_t, char *);
1857static char *stnputs(const char *, size_t, char *);
1858static char *stputs(const char *, char *);
1859
1860
1861static inline char *_STPUTC(char c, char *p) {
1862 if (p == sstrend)
1863 p = growstackstr();
1864 *p++ = c;
1865 return p;
1866}
1867
1868#define stackblock() ((void *)stacknxt)
1869#define stackblocksize() stacknleft
1870#define STARTSTACKSTR(p) ((p) = stackblock())
1871#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1872#define CHECKSTRSPACE(n, p) \
1873 ({ \
1874 char *q = (p); \
1875 size_t l = (n); \
1876 size_t m = sstrend - q; \
1877 if (l > m) \
1878 (p) = makestrspace(l, q); \
1879 0; \
1880 })
1881#define USTPUTC(c, p) (*p++ = (c))
1882#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1883#define STUNPUTC(p) (--p)
1884#define STTOPC(p) p[-1]
1885#define STADJUST(amount, p) (p += (amount))
1886
1887#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1888#define ungrabstackstr(s, p) stunalloc((s))
1889#define stackstrend() ((void *)sstrend)
1890
1891#define ckfree(p) free((pointer)(p))
1892
1893/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1894
1895
1896#define DOLATSTRLEN 4
1897
1898static char *prefix(const char *, const char *);
1899static int number(const char *);
1900static int is_number(const char *);
1901static char *single_quote(const char *);
1902static char *sstrdup(const char *);
1903
1904#define equal(s1, s2) (strcmp(s1, s2) == 0)
1905#define scopy(s1, s2) ((void)strcpy(s2, s1))
1906
1907/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1908
1909struct shparam {
1910 int nparam; /* # of positional parameters (without $0) */
1911 unsigned char malloc; /* if parameter list dynamically allocated */
1912 char **p; /* parameter list */
1913#ifdef CONFIG_ASH_GETOPTS
1914 int optind; /* next parameter to be processed by getopts */
1915 int optoff; /* used by getopts */
1916#endif
1917};
1918
1919
1920#define eflag optlist[0]
1921#define fflag optlist[1]
1922#define Iflag optlist[2]
1923#define iflag optlist[3]
1924#define mflag optlist[4]
1925#define nflag optlist[5]
1926#define sflag optlist[6]
1927#define xflag optlist[7]
1928#define vflag optlist[8]
1929#define Cflag optlist[9]
1930#define aflag optlist[10]
1931#define bflag optlist[11]
1932#define uflag optlist[12]
1933#define qflag optlist[13]
1934
1935#ifdef DEBUG
1936#define nolog optlist[14]
1937#define debug optlist[15]
1938#define NOPTS 16
1939#else
1940#define NOPTS 14
1941#endif
1942
1943/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1944
1945
1946static const char *const optletters_optnames[NOPTS] = {
1947 "e" "errexit",
1948 "f" "noglob",
1949 "I" "ignoreeof",
1950 "i" "interactive",
1951 "m" "monitor",
1952 "n" "noexec",
1953 "s" "stdin",
1954 "x" "xtrace",
1955 "v" "verbose",
1956 "C" "noclobber",
1957 "a" "allexport",
1958 "b" "notify",
1959 "u" "nounset",
1960 "q" "quietprofile",
1961#ifdef DEBUG
1962 "\0" "nolog",
1963 "\0" "debug",
1964#endif
1965};
1966
1967#define optletters(n) optletters_optnames[(n)][0]
1968#define optnames(n) (&optletters_optnames[(n)][1])
1969
1970
1971static char optlist[NOPTS];
1972
1973
1974static char *arg0; /* value of $0 */
1975static struct shparam shellparam; /* $@ current positional parameters */
1976static char **argptr; /* argument list for builtin commands */
1977static char *optionarg; /* set by nextopt (like getopt) */
1978static char *optptr; /* used by nextopt */
1979
1980static char *minusc; /* argument to -c option */
1981
1982
1983static void procargs(int, char **);
1984static void optschanged(void);
1985static void setparam(char **);
1986static void freeparam(volatile struct shparam *);
1987static int shiftcmd(int, char **);
1988static int setcmd(int, char **);
1989static int nextopt(const char *);
1990
1991/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1992
1993/* flags passed to redirect */
1994#define REDIR_PUSH 01 /* save previous values of file descriptors */
1995
1996union node;
1997static void redirect(union node *, int);
1998static void popredir(int);
1999static void clearredir(int);
2000static int copyfd(int, int);
2001static int redirectsafe(union node *, int);
2002
2003/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2004
2005
2006#ifdef DEBUG
2007static void showtree(union node *);
2008static void trace(const char *, ...);
2009static void tracev(const char *, va_list);
2010static void trargs(char **);
2011static void trputc(int);
2012static void trputs(const char *);
2013static void opentrace(void);
2014#endif
2015
2016/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2017
2018
2019/* trap handler commands */
2020static char *trap[NSIG];
2021/* current value of signal */
2022static char sigmode[NSIG - 1];
2023/* indicates specified signal received */
2024static char gotsig[NSIG - 1];
2025
2026static void clear_traps(void);
2027static void setsignal(int);
2028static void ignoresig(int);
2029static void onsig(int);
2030static void dotrap(void);
2031static void setinteractive(int);
2032static void exitshell(void) __attribute__((__noreturn__));
2033static int decode_signal(const char *, int);
2034
2035/*
2036 * This routine is called when an error or an interrupt occurs in an
2037 * interactive shell and control is returned to the main command loop.
2038 */
2039
2040static void
2041reset(void)
2042{
2043 /* from eval.c: */
2044 {
2045 evalskip = 0;
2046 loopnest = 0;
2047 funcnest = 0;
2048 }
2049
2050 /* from input.c: */
2051 {
2052 parselleft = parsenleft = 0; /* clear input buffer */
2053 popallfiles();
2054 }
2055
2056 /* from parser.c: */
2057 {
2058 tokpushback = 0;
2059 checkkwd = 0;
2060 }
2061
2062 /* from redir.c: */
2063 {
2064 clearredir(0);
2065 }
2066
2067}
2068
2069#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002070static struct alias *atab[ATABSIZE];
2071
Eric Andersenc470f442003-07-28 09:56:35 +00002072static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002073static struct alias *freealias(struct alias *);
2074static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002075
Eric Andersenc470f442003-07-28 09:56:35 +00002076static void
2077setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002078{
2079 struct alias *ap, **app;
2080
2081 app = __lookupalias(name);
2082 ap = *app;
2083 INTOFF;
2084 if (ap) {
2085 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002086 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002087 }
Eric Andersenc470f442003-07-28 09:56:35 +00002088 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002089 ap->flag &= ~ALIASDEAD;
2090 } else {
2091 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002092 ap = ckmalloc(sizeof (struct alias));
2093 ap->name = savestr(name);
2094 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002095 ap->flag = 0;
2096 ap->next = 0;
2097 *app = ap;
2098 }
2099 INTON;
2100}
2101
Eric Andersenc470f442003-07-28 09:56:35 +00002102static int
2103unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002104{
Eric Andersencb57d552001-06-28 07:25:16 +00002105 struct alias **app;
2106
2107 app = __lookupalias(name);
2108
2109 if (*app) {
2110 INTOFF;
2111 *app = freealias(*app);
2112 INTON;
2113 return (0);
2114 }
2115
2116 return (1);
2117}
2118
Eric Andersenc470f442003-07-28 09:56:35 +00002119static void
2120rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002121{
Eric Andersencb57d552001-06-28 07:25:16 +00002122 struct alias *ap, **app;
2123 int i;
2124
2125 INTOFF;
2126 for (i = 0; i < ATABSIZE; i++) {
2127 app = &atab[i];
2128 for (ap = *app; ap; ap = *app) {
2129 *app = freealias(*app);
2130 if (ap == *app) {
2131 app = &ap->next;
2132 }
2133 }
2134 }
2135 INTON;
2136}
2137
Eric Andersenc470f442003-07-28 09:56:35 +00002138static struct alias *
2139lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002140{
Eric Andersenc470f442003-07-28 09:56:35 +00002141 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002142
Eric Andersenc470f442003-07-28 09:56:35 +00002143 if (check && ap && (ap->flag & ALIASINUSE))
2144 return (NULL);
2145 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002146}
2147
Eric Andersencb57d552001-06-28 07:25:16 +00002148/*
2149 * TODO - sort output
2150 */
Eric Andersenc470f442003-07-28 09:56:35 +00002151static int
2152aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002153{
2154 char *n, *v;
2155 int ret = 0;
2156 struct alias *ap;
2157
2158 if (argc == 1) {
2159 int i;
2160
2161 for (i = 0; i < ATABSIZE; i++)
2162 for (ap = atab[i]; ap; ap = ap->next) {
2163 printalias(ap);
2164 }
2165 return (0);
2166 }
2167 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002168 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002169 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002170 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002171 ret = 1;
2172 } else
2173 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002174 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002175 *v++ = '\0';
2176 setalias(n, v);
2177 }
2178 }
2179
2180 return (ret);
2181}
2182
Eric Andersenc470f442003-07-28 09:56:35 +00002183static int
2184unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002185{
2186 int i;
2187
2188 while ((i = nextopt("a")) != '\0') {
2189 if (i == 'a') {
2190 rmaliases();
2191 return (0);
2192 }
2193 }
2194 for (i = 0; *argptr; argptr++) {
2195 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002196 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002197 i = 1;
2198 }
2199 }
2200
2201 return (i);
2202}
2203
Eric Andersenc470f442003-07-28 09:56:35 +00002204static struct alias *
2205freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002206 struct alias *next;
2207
2208 if (ap->flag & ALIASINUSE) {
2209 ap->flag |= ALIASDEAD;
2210 return ap;
2211 }
2212
2213 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002214 ckfree(ap->name);
2215 ckfree(ap->val);
2216 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002217 return next;
2218}
2219
Eric Andersenc470f442003-07-28 09:56:35 +00002220static void
2221printalias(const struct alias *ap) {
2222 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2223}
Eric Andersencb57d552001-06-28 07:25:16 +00002224
Eric Andersenc470f442003-07-28 09:56:35 +00002225static struct alias **
2226__lookupalias(const char *name) {
2227 unsigned int hashval;
2228 struct alias **app;
2229 const char *p;
2230 unsigned int ch;
2231
2232 p = name;
2233
2234 ch = (unsigned char)*p;
2235 hashval = ch << 4;
2236 while (ch) {
2237 hashval += ch;
2238 ch = (unsigned char)*++p;
2239 }
2240 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002241
2242 for (; *app; app = &(*app)->next) {
2243 if (equal(name, (*app)->name)) {
2244 break;
2245 }
2246 }
2247
2248 return app;
2249}
Eric Andersenc470f442003-07-28 09:56:35 +00002250#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002251
Eric Andersencb57d552001-06-28 07:25:16 +00002252
Eric Andersenc470f442003-07-28 09:56:35 +00002253/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002254
Eric Andersencb57d552001-06-28 07:25:16 +00002255/*
Eric Andersenc470f442003-07-28 09:56:35 +00002256 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002257 */
2258
Eric Andersenc470f442003-07-28 09:56:35 +00002259#define CD_PHYSICAL 1
2260#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002261
Eric Andersenc470f442003-07-28 09:56:35 +00002262static int docd(const char *, int);
2263static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002264
Eric Andersenc470f442003-07-28 09:56:35 +00002265static char *curdir = nullstr; /* current working directory */
2266static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002267
Eric Andersenc470f442003-07-28 09:56:35 +00002268static int
2269cdopt(void)
2270{
2271 int flags = 0;
2272 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002273
Eric Andersenc470f442003-07-28 09:56:35 +00002274 j = 'L';
2275 while ((i = nextopt("LP"))) {
2276 if (i != j) {
2277 flags ^= CD_PHYSICAL;
2278 j = i;
2279 }
2280 }
Eric Andersencb57d552001-06-28 07:25:16 +00002281
Eric Andersenc470f442003-07-28 09:56:35 +00002282 return flags;
2283}
Eric Andersen2870d962001-07-02 17:27:21 +00002284
Eric Andersenc470f442003-07-28 09:56:35 +00002285static int
2286cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002287{
2288 const char *dest;
2289 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002290 const char *p;
2291 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002292 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002293 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002294
Eric Andersenc470f442003-07-28 09:56:35 +00002295 flags = cdopt();
2296 dest = *argptr;
2297 if (!dest)
2298 dest = bltinlookup(homestr);
2299 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002300 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002301 flags |= CD_PRINT;
2302 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002303 }
Eric Andersenc470f442003-07-28 09:56:35 +00002304 if (!dest)
2305 dest = nullstr;
2306 if (*dest == '/')
2307 goto step7;
2308 if (*dest == '.') {
2309 c = dest[1];
2310dotdot:
2311 switch (c) {
2312 case '\0':
2313 case '/':
2314 goto step6;
2315 case '.':
2316 c = dest[2];
2317 if (c != '.')
2318 goto dotdot;
2319 }
2320 }
2321 if (!*dest)
2322 dest = ".";
2323 if (!(path = bltinlookup("CDPATH"))) {
2324step6:
2325step7:
2326 p = dest;
2327 goto docd;
2328 }
2329 do {
2330 c = *path;
2331 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002332 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002333 if (c && c != ':')
2334 flags |= CD_PRINT;
2335docd:
2336 if (!docd(p, flags))
2337 goto out;
2338 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002339 }
Eric Andersenc470f442003-07-28 09:56:35 +00002340 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002341 error("can't cd to %s", dest);
2342 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002343out:
2344 if (flags & CD_PRINT)
2345 out1fmt(snlfmt, curdir);
2346 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002347}
2348
2349
2350/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002351 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002352 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002353 */
2354
Eric Andersenc470f442003-07-28 09:56:35 +00002355static inline const char *
2356updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002357{
Eric Andersenc470f442003-07-28 09:56:35 +00002358 char *new;
2359 char *p;
2360 char *cdcomppath;
2361 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002362
Eric Andersenc470f442003-07-28 09:56:35 +00002363 cdcomppath = sstrdup(dir);
2364 STARTSTACKSTR(new);
2365 if (*dir != '/') {
2366 if (curdir == nullstr)
2367 return 0;
2368 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002369 }
Eric Andersenc470f442003-07-28 09:56:35 +00002370 new = makestrspace(strlen(dir) + 2, new);
2371 lim = stackblock() + 1;
2372 if (*dir != '/') {
2373 if (new[-1] != '/')
2374 USTPUTC('/', new);
2375 if (new > lim && *lim == '/')
2376 lim++;
2377 } else {
2378 USTPUTC('/', new);
2379 cdcomppath++;
2380 if (dir[1] == '/' && dir[2] != '/') {
2381 USTPUTC('/', new);
2382 cdcomppath++;
2383 lim++;
2384 }
2385 }
2386 p = strtok(cdcomppath, "/");
2387 while (p) {
2388 switch(*p) {
2389 case '.':
2390 if (p[1] == '.' && p[2] == '\0') {
2391 while (new > lim) {
2392 STUNPUTC(new);
2393 if (new[-1] == '/')
2394 break;
2395 }
2396 break;
2397 } else if (p[1] == '\0')
2398 break;
2399 /* fall through */
2400 default:
2401 new = stputs(p, new);
2402 USTPUTC('/', new);
2403 }
2404 p = strtok(0, "/");
2405 }
2406 if (new > lim)
2407 STUNPUTC(new);
2408 *new = 0;
2409 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002410}
2411
2412/*
Eric Andersenc470f442003-07-28 09:56:35 +00002413 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2414 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002415 */
2416
Eric Andersenc470f442003-07-28 09:56:35 +00002417static int
2418docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002419{
Eric Andersenc470f442003-07-28 09:56:35 +00002420 const char *dir = 0;
2421 int err;
2422
2423 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2424
Eric Andersencb57d552001-06-28 07:25:16 +00002425 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002426 if (!(flags & CD_PHYSICAL)) {
2427 dir = updatepwd(dest);
2428 if (dir)
2429 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002430 }
Eric Andersenc470f442003-07-28 09:56:35 +00002431 err = chdir(dest);
2432 if (err)
2433 goto out;
2434 setpwd(dir, 1);
2435 hashcd();
2436out:
Eric Andersencb57d552001-06-28 07:25:16 +00002437 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002438 return err;
2439}
2440
2441/*
2442 * Find out what the current directory is. If we already know the current
2443 * directory, this routine returns immediately.
2444 */
2445static inline char *
2446getpwd(void)
2447{
2448 char *dir = getcwd(0, 0);
2449 return dir ? dir : nullstr;
2450}
2451
2452static int
2453pwdcmd(int argc, char **argv)
2454{
2455 int flags;
2456 const char *dir = curdir;
2457
2458 flags = cdopt();
2459 if (flags) {
2460 if (physdir == nullstr)
2461 setpwd(dir, 0);
2462 dir = physdir;
2463 }
2464 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002465 return 0;
2466}
2467
Eric Andersenc470f442003-07-28 09:56:35 +00002468static void
2469setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002470{
Eric Andersenc470f442003-07-28 09:56:35 +00002471 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002472
Eric Andersenc470f442003-07-28 09:56:35 +00002473 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002474
Eric Andersencb57d552001-06-28 07:25:16 +00002475 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002476 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002477 }
2478 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002479 if (physdir != nullstr) {
2480 if (physdir != oldcur)
2481 free(physdir);
2482 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002483 }
Eric Andersenc470f442003-07-28 09:56:35 +00002484 if (oldcur == val || !val) {
2485 char *s = getpwd();
2486 physdir = s;
2487 if (!val)
2488 dir = s;
2489 } else
2490 dir = savestr(val);
2491 if (oldcur != dir && oldcur != nullstr) {
2492 free(oldcur);
2493 }
2494 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002495 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002496 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002497}
2498
Eric Andersenc470f442003-07-28 09:56:35 +00002499/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2500
Eric Andersencb57d552001-06-28 07:25:16 +00002501/*
2502 * Errors and exceptions.
2503 */
2504
2505/*
2506 * Code to handle exceptions in C.
2507 */
2508
Eric Andersen2870d962001-07-02 17:27:21 +00002509
Eric Andersencb57d552001-06-28 07:25:16 +00002510
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002511static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002512 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002513
2514/*
2515 * Called to raise an exception. Since C doesn't include exceptions, we
2516 * just do a longjmp to the exception handler. The type of exception is
2517 * stored in the global variable "exception".
2518 */
2519
Eric Andersenc470f442003-07-28 09:56:35 +00002520static void
2521exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002522{
2523#ifdef DEBUG
2524 if (handler == NULL)
2525 abort();
2526#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002527 INTOFF;
2528
Eric Andersencb57d552001-06-28 07:25:16 +00002529 exception = e;
2530 longjmp(handler->loc, 1);
2531}
2532
2533
2534/*
2535 * Called from trap.c when a SIGINT is received. (If the user specifies
2536 * that SIGINT is to be trapped or ignored using the trap builtin, then
2537 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002538 * are held using the INTOFF macro. (The test for iflag is just
2539 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002540 */
2541
Eric Andersenc470f442003-07-28 09:56:35 +00002542static void
2543onint(void) {
2544 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002545
Eric Andersencb57d552001-06-28 07:25:16 +00002546 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002547 sigsetmask(0);
2548 i = EXSIG;
2549 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2550 if (!(rootshell && iflag)) {
2551 signal(SIGINT, SIG_DFL);
2552 raise(SIGINT);
2553 }
2554 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002555 }
Eric Andersenc470f442003-07-28 09:56:35 +00002556 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002557 /* NOTREACHED */
2558}
2559
Eric Andersenc470f442003-07-28 09:56:35 +00002560static void
2561exvwarning(const char *msg, va_list ap)
2562{
2563 FILE *errs;
2564 const char *name;
2565 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002566
Eric Andersenc470f442003-07-28 09:56:35 +00002567 errs = stderr;
2568 name = arg0;
2569 fmt = "%s: ";
2570 if (commandname) {
2571 name = commandname;
2572 fmt = "%s: %d: ";
2573 }
2574 fprintf(errs, fmt, name, startlinno);
2575 vfprintf(errs, msg, ap);
2576 outcslow('\n', errs);
2577}
Eric Andersen2870d962001-07-02 17:27:21 +00002578
Eric Andersencb57d552001-06-28 07:25:16 +00002579/*
Eric Andersenc470f442003-07-28 09:56:35 +00002580 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002581 * is not NULL then error prints an error message using printf style
2582 * formatting. It then raises the error exception.
2583 */
Eric Andersenc470f442003-07-28 09:56:35 +00002584static void
2585exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002586{
Eric Andersencb57d552001-06-28 07:25:16 +00002587#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002588 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002589 TRACE(("exverror(%d, \"", cond));
2590 TRACEV((msg, ap));
2591 TRACE(("\") pid=%d\n", getpid()));
2592 } else
2593 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2594 if (msg)
2595#endif
2596 exvwarning(msg, ap);
2597
2598 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002599 exraise(cond);
2600 /* NOTREACHED */
2601}
2602
2603
Eric Andersenc470f442003-07-28 09:56:35 +00002604static void
2605error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002606{
Eric Andersencb57d552001-06-28 07:25:16 +00002607 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002608
Eric Andersencb57d552001-06-28 07:25:16 +00002609 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002610 exverror(EXERROR, msg, ap);
2611 /* NOTREACHED */
2612 va_end(ap);
2613}
2614
2615
Eric Andersenc470f442003-07-28 09:56:35 +00002616static void
2617exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002618{
Eric Andersencb57d552001-06-28 07:25:16 +00002619 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002620
Eric Andersencb57d552001-06-28 07:25:16 +00002621 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002622 exverror(cond, msg, ap);
2623 /* NOTREACHED */
2624 va_end(ap);
2625}
2626
Eric Andersencb57d552001-06-28 07:25:16 +00002627/*
Eric Andersenc470f442003-07-28 09:56:35 +00002628 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002629 */
2630
Eric Andersenc470f442003-07-28 09:56:35 +00002631static void
2632sh_warnx(const char *fmt, ...)
2633{
2634 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002635
Eric Andersenc470f442003-07-28 09:56:35 +00002636 va_start(ap, fmt);
2637 exvwarning(fmt, ap);
2638 va_end(ap);
2639}
Eric Andersen2870d962001-07-02 17:27:21 +00002640
Eric Andersencb57d552001-06-28 07:25:16 +00002641
2642/*
2643 * Return a string describing an error. The returned string may be a
2644 * pointer to a static buffer that will be overwritten on the next call.
2645 * Action describes the operation that got the error.
2646 */
2647
Eric Andersenc470f442003-07-28 09:56:35 +00002648static const char *
2649errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002650{
Eric Andersenc470f442003-07-28 09:56:35 +00002651 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002652
Eric Andersenc470f442003-07-28 09:56:35 +00002653 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002654 }
Eric Andersenc470f442003-07-28 09:56:35 +00002655 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002656}
2657
2658
Eric Andersenc470f442003-07-28 09:56:35 +00002659/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2660
2661/*
2662 * Evaluate a command.
2663 */
Eric Andersencb57d552001-06-28 07:25:16 +00002664
2665/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002666#define EV_EXIT 01 /* exit after evaluating tree */
2667#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2668#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002669
2670
Eric Andersenc470f442003-07-28 09:56:35 +00002671static void evalloop(union node *, int);
2672static void evalfor(union node *, int);
2673static void evalcase(union node *, int);
2674static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002675static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002676static void evalpipe(union node *, int);
2677static void evalcommand(union node *, int);
2678static int evalbltin(const struct builtincmd *, int, char **);
2679static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002680static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002681static int eprintlist(struct strlist *, int);
2682static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002683
Eric Andersenc470f442003-07-28 09:56:35 +00002684
2685static const struct builtincmd bltin = {
2686 "\0\0", bltincmd
2687};
2688
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002689
Eric Andersencb57d552001-06-28 07:25:16 +00002690/*
2691 * Called to reset things after an exception.
2692 */
2693
Eric Andersencb57d552001-06-28 07:25:16 +00002694/*
2695 * The eval commmand.
2696 */
2697
Eric Andersenc470f442003-07-28 09:56:35 +00002698static int
2699evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002700{
Eric Andersen2870d962001-07-02 17:27:21 +00002701 char *p;
2702 char *concat;
2703 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002704
Eric Andersen2870d962001-07-02 17:27:21 +00002705 if (argc > 1) {
2706 p = argv[1];
2707 if (argc > 2) {
2708 STARTSTACKSTR(concat);
2709 ap = argv + 2;
2710 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002711 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002712 if ((p = *ap++) == NULL)
2713 break;
2714 STPUTC(' ', concat);
2715 }
2716 STPUTC('\0', concat);
2717 p = grabstackstr(concat);
2718 }
2719 evalstring(p, EV_TESTED);
2720 }
2721 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002722}
2723
Eric Andersenc470f442003-07-28 09:56:35 +00002724
Eric Andersencb57d552001-06-28 07:25:16 +00002725/*
2726 * Execute a command or commands contained in a string.
2727 */
2728
Eric Andersenc470f442003-07-28 09:56:35 +00002729static void
2730evalstring(char *s, int flag)
Eric Andersen2870d962001-07-02 17:27:21 +00002731{
Eric Andersencb57d552001-06-28 07:25:16 +00002732 union node *n;
2733 struct stackmark smark;
2734
2735 setstackmark(&smark);
2736 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002737
Eric Andersencb57d552001-06-28 07:25:16 +00002738 while ((n = parsecmd(0)) != NEOF) {
2739 evaltree(n, flag);
2740 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002741 if (evalskip)
2742 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002743 }
2744 popfile();
2745 popstackmark(&smark);
2746}
2747
Eric Andersenc470f442003-07-28 09:56:35 +00002748
Eric Andersen62483552001-07-10 06:09:16 +00002749
2750/*
Eric Andersenc470f442003-07-28 09:56:35 +00002751 * Evaluate a parse tree. The value is left in the global variable
2752 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002753 */
2754
Eric Andersenc470f442003-07-28 09:56:35 +00002755static void
2756evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002757{
Eric Andersenc470f442003-07-28 09:56:35 +00002758 int checkexit = 0;
2759 void (*evalfn)(union node *, int);
2760 unsigned isor;
2761 int status;
2762 if (n == NULL) {
2763 TRACE(("evaltree(NULL) called\n"));
2764 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002765 }
Eric Andersenc470f442003-07-28 09:56:35 +00002766 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2767 getpid(), n, n->type, flags));
2768 switch (n->type) {
2769 default:
2770#ifdef DEBUG
2771 out1fmt("Node type = %d\n", n->type);
2772 flushout(stdout);
2773 break;
2774#endif
2775 case NNOT:
2776 evaltree(n->nnot.com, EV_TESTED);
2777 status = !exitstatus;
2778 goto setstatus;
2779 case NREDIR:
2780 expredir(n->nredir.redirect);
2781 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2782 if (!status) {
2783 evaltree(n->nredir.n, flags & EV_TESTED);
2784 status = exitstatus;
2785 }
2786 popredir(0);
2787 goto setstatus;
2788 case NCMD:
2789 evalfn = evalcommand;
2790checkexit:
2791 if (eflag && !(flags & EV_TESTED))
2792 checkexit = ~0;
2793 goto calleval;
2794 case NFOR:
2795 evalfn = evalfor;
2796 goto calleval;
2797 case NWHILE:
2798 case NUNTIL:
2799 evalfn = evalloop;
2800 goto calleval;
2801 case NSUBSHELL:
2802 case NBACKGND:
2803 evalfn = evalsubshell;
2804 goto calleval;
2805 case NPIPE:
2806 evalfn = evalpipe;
2807 goto checkexit;
2808 case NCASE:
2809 evalfn = evalcase;
2810 goto calleval;
2811 case NAND:
2812 case NOR:
2813 case NSEMI:
2814#if NAND + 1 != NOR
2815#error NAND + 1 != NOR
2816#endif
2817#if NOR + 1 != NSEMI
2818#error NOR + 1 != NSEMI
2819#endif
2820 isor = n->type - NAND;
2821 evaltree(
2822 n->nbinary.ch1,
2823 (flags | ((isor >> 1) - 1)) & EV_TESTED
2824 );
2825 if (!exitstatus == isor)
2826 break;
2827 if (!evalskip) {
2828 n = n->nbinary.ch2;
2829evaln:
2830 evalfn = evaltree;
2831calleval:
2832 evalfn(n, flags);
2833 break;
2834 }
2835 break;
2836 case NIF:
2837 evaltree(n->nif.test, EV_TESTED);
2838 if (evalskip)
2839 break;
2840 if (exitstatus == 0) {
2841 n = n->nif.ifpart;
2842 goto evaln;
2843 } else if (n->nif.elsepart) {
2844 n = n->nif.elsepart;
2845 goto evaln;
2846 }
2847 goto success;
2848 case NDEFUN:
2849 defun(n->narg.text, n->narg.next);
2850success:
2851 status = 0;
2852setstatus:
2853 exitstatus = status;
2854 break;
2855 }
2856out:
2857 if (pendingsigs)
2858 dotrap();
2859 if (flags & EV_EXIT || checkexit & exitstatus)
2860 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002861}
2862
Eric Andersenc470f442003-07-28 09:56:35 +00002863
2864#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2865static
2866#endif
2867void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2868
2869
2870static void
2871evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002872{
2873 int status;
2874
2875 loopnest++;
2876 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002877 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002878 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002879 int i;
2880
Eric Andersencb57d552001-06-28 07:25:16 +00002881 evaltree(n->nbinary.ch1, EV_TESTED);
2882 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002883skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002884 evalskip = 0;
2885 continue;
2886 }
2887 if (evalskip == SKIPBREAK && --skipcount <= 0)
2888 evalskip = 0;
2889 break;
2890 }
Eric Andersenc470f442003-07-28 09:56:35 +00002891 i = exitstatus;
2892 if (n->type != NWHILE)
2893 i = !i;
2894 if (i != 0)
2895 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002896 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002897 status = exitstatus;
2898 if (evalskip)
2899 goto skipping;
2900 }
2901 loopnest--;
2902 exitstatus = status;
2903}
2904
Eric Andersenc470f442003-07-28 09:56:35 +00002905
2906
2907static void
2908evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002909{
2910 struct arglist arglist;
2911 union node *argp;
2912 struct strlist *sp;
2913 struct stackmark smark;
2914
2915 setstackmark(&smark);
2916 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002917 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002918 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002919 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002920 if (evalskip)
2921 goto out;
2922 }
2923 *arglist.lastp = NULL;
2924
2925 exitstatus = 0;
2926 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002927 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002928 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002929 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002930 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002931 if (evalskip) {
2932 if (evalskip == SKIPCONT && --skipcount <= 0) {
2933 evalskip = 0;
2934 continue;
2935 }
2936 if (evalskip == SKIPBREAK && --skipcount <= 0)
2937 evalskip = 0;
2938 break;
2939 }
2940 }
2941 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002942out:
Eric Andersencb57d552001-06-28 07:25:16 +00002943 popstackmark(&smark);
2944}
2945
Eric Andersenc470f442003-07-28 09:56:35 +00002946
2947
2948static void
2949evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002950{
2951 union node *cp;
2952 union node *patp;
2953 struct arglist arglist;
2954 struct stackmark smark;
2955
2956 setstackmark(&smark);
2957 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002958 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002959 exitstatus = 0;
2960 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2961 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002962 if (casematch(patp, arglist.list->text)) {
2963 if (evalskip == 0) {
2964 evaltree(cp->nclist.body, flags);
2965 }
2966 goto out;
2967 }
2968 }
2969 }
Eric Andersenc470f442003-07-28 09:56:35 +00002970out:
Eric Andersencb57d552001-06-28 07:25:16 +00002971 popstackmark(&smark);
2972}
2973
Eric Andersenc470f442003-07-28 09:56:35 +00002974
2975
2976/*
2977 * Kick off a subshell to evaluate a tree.
2978 */
2979
2980static void
2981evalsubshell(union node *n, int flags)
2982{
2983 struct job *jp;
2984 int backgnd = (n->type == NBACKGND);
2985 int status;
2986
2987 expredir(n->nredir.redirect);
2988 if (!backgnd && flags & EV_EXIT && !trap[0])
2989 goto nofork;
2990 INTOFF;
2991 jp = makejob(n, 1);
2992 if (forkshell(jp, n, backgnd) == 0) {
2993 INTON;
2994 flags |= EV_EXIT;
2995 if (backgnd)
2996 flags &=~ EV_TESTED;
2997nofork:
2998 redirect(n->nredir.redirect, 0);
2999 evaltreenr(n->nredir.n, flags);
3000 /* never returns */
3001 }
3002 status = 0;
3003 if (! backgnd)
3004 status = waitforjob(jp);
3005 exitstatus = status;
3006 INTON;
3007}
3008
3009
3010
3011/*
3012 * Compute the names of the files in a redirection list.
3013 */
3014
3015static void
3016expredir(union node *n)
3017{
3018 union node *redir;
3019
3020 for (redir = n ; redir ; redir = redir->nfile.next) {
3021 struct arglist fn;
3022 fn.lastp = &fn.list;
3023 switch (redir->type) {
3024 case NFROMTO:
3025 case NFROM:
3026 case NTO:
3027 case NCLOBBER:
3028 case NAPPEND:
3029 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3030 redir->nfile.expfname = fn.list->text;
3031 break;
3032 case NFROMFD:
3033 case NTOFD:
3034 if (redir->ndup.vname) {
3035 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3036 fixredir(redir, fn.list->text, 1);
3037 }
3038 break;
3039 }
3040 }
3041}
3042
3043
3044
Eric Andersencb57d552001-06-28 07:25:16 +00003045/*
Eric Andersencb57d552001-06-28 07:25:16 +00003046 * Evaluate a pipeline. All the processes in the pipeline are children
3047 * of the process creating the pipeline. (This differs from some versions
3048 * of the shell, which make the last process in a pipeline the parent
3049 * of all the rest.)
3050 */
3051
Eric Andersenc470f442003-07-28 09:56:35 +00003052static void
3053evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003054{
3055 struct job *jp;
3056 struct nodelist *lp;
3057 int pipelen;
3058 int prevfd;
3059 int pip[2];
3060
Eric Andersenc470f442003-07-28 09:56:35 +00003061 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003062 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003063 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003064 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003065 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003066 INTOFF;
3067 jp = makejob(n, pipelen);
3068 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003069 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003070 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003071 pip[1] = -1;
3072 if (lp->next) {
3073 if (pipe(pip) < 0) {
3074 close(prevfd);
3075 error("Pipe call failed");
3076 }
3077 }
3078 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3079 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003080 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003081 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003082 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003083 if (prevfd > 0) {
3084 dup2(prevfd, 0);
3085 close(prevfd);
3086 }
3087 if (pip[1] > 1) {
3088 dup2(pip[1], 1);
3089 close(pip[1]);
3090 }
Eric Andersenc470f442003-07-28 09:56:35 +00003091 evaltreenr(lp->n, flags);
3092 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003093 }
3094 if (prevfd >= 0)
3095 close(prevfd);
3096 prevfd = pip[0];
3097 close(pip[1]);
3098 }
Eric Andersencb57d552001-06-28 07:25:16 +00003099 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003100 exitstatus = waitforjob(jp);
3101 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003102 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003103 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003104}
3105
Eric Andersen62483552001-07-10 06:09:16 +00003106
3107
3108/*
3109 * Execute a command inside back quotes. If it's a builtin command, we
3110 * want to save its output in a block obtained from malloc. Otherwise
3111 * we fork off a subprocess and get the output of the command via a pipe.
3112 * Should be called with interrupts off.
3113 */
3114
Eric Andersenc470f442003-07-28 09:56:35 +00003115static void
3116evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003117{
Eric Andersenc470f442003-07-28 09:56:35 +00003118 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003119
Eric Andersen62483552001-07-10 06:09:16 +00003120 result->fd = -1;
3121 result->buf = NULL;
3122 result->nleft = 0;
3123 result->jp = NULL;
3124 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003125 goto out;
3126 }
Eric Andersenc470f442003-07-28 09:56:35 +00003127
3128 saveherefd = herefd;
3129 herefd = -1;
3130
3131 {
3132 int pip[2];
3133 struct job *jp;
3134
3135 if (pipe(pip) < 0)
3136 error("Pipe call failed");
3137 jp = makejob(n, 1);
3138 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3139 FORCEINTON;
3140 close(pip[0]);
3141 if (pip[1] != 1) {
3142 close(1);
3143 copyfd(pip[1], 1);
3144 close(pip[1]);
3145 }
3146 eflag = 0;
3147 evaltreenr(n, EV_EXIT);
3148 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003149 }
Eric Andersenc470f442003-07-28 09:56:35 +00003150 close(pip[1]);
3151 result->fd = pip[0];
3152 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003153 }
Eric Andersenc470f442003-07-28 09:56:35 +00003154 herefd = saveherefd;
3155out:
Eric Andersen62483552001-07-10 06:09:16 +00003156 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003157 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003158}
3159
Eric Andersenc470f442003-07-28 09:56:35 +00003160#ifdef CONFIG_ASH_CMDCMD
3161static inline char **
3162parse_command_args(char **argv, const char **path)
3163{
3164 char *cp, c;
3165
3166 for (;;) {
3167 cp = *++argv;
3168 if (!cp)
3169 return 0;
3170 if (*cp++ != '-')
3171 break;
3172 if (!(c = *cp++))
3173 break;
3174 if (c == '-' && !*cp) {
3175 argv++;
3176 break;
3177 }
3178 do {
3179 switch (c) {
3180 case 'p':
3181 *path = defpath;
3182 break;
3183 default:
3184 /* run 'typecmd' for other options */
3185 return 0;
3186 }
3187 } while ((c = *cp++));
3188 }
3189 return argv;
3190}
3191#endif
3192
3193
Eric Andersen62483552001-07-10 06:09:16 +00003194
3195/*
3196 * Execute a simple command.
3197 */
Eric Andersencb57d552001-06-28 07:25:16 +00003198
Eric Andersenc470f442003-07-28 09:56:35 +00003199static void
3200evalcommand(union node *cmd, int flags)
3201{
3202 struct stackmark smark;
3203 union node *argp;
3204 struct arglist arglist;
3205 struct arglist varlist;
3206 char **argv;
3207 int argc;
3208 struct strlist *sp;
3209 struct cmdentry cmdentry;
3210 struct job *jp;
3211 char *lastarg;
3212 const char *path;
3213 int spclbltin;
3214 int cmd_is_exec;
3215 int status;
3216 char **nargv;
3217
3218 /* First expand the arguments. */
3219 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3220 setstackmark(&smark);
3221 back_exitstatus = 0;
3222
3223 cmdentry.cmdtype = CMDBUILTIN;
3224 cmdentry.u.cmd = &bltin;
3225 varlist.lastp = &varlist.list;
3226 *varlist.lastp = NULL;
3227 arglist.lastp = &arglist.list;
3228 *arglist.lastp = NULL;
3229
3230 argc = 0;
3231 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3232 struct strlist **spp;
3233
3234 spp = arglist.lastp;
3235 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3236 for (sp = *spp; sp; sp = sp->next)
3237 argc++;
3238 }
3239
3240 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3241 for (sp = arglist.list ; sp ; sp = sp->next) {
3242 TRACE(("evalcommand arg: %s\n", sp->text));
3243 *nargv++ = sp->text;
3244 }
3245 *nargv = NULL;
3246
3247 lastarg = NULL;
3248 if (iflag && funcnest == 0 && argc > 0)
3249 lastarg = nargv[-1];
3250
3251 expredir(cmd->ncmd.redirect);
3252 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH);
3253
3254 path = vpath.text;
3255 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3256 struct strlist **spp;
3257 char *p;
3258
3259 spp = varlist.lastp;
3260 expandarg(argp, &varlist, EXP_VARTILDE);
3261
3262 /*
3263 * Modify the command lookup path, if a PATH= assignment
3264 * is present
3265 */
3266 p = (*spp)->text;
3267 if (varequal(p, path))
3268 path = p;
3269 }
3270
3271 /* Print the command if xflag is set. */
3272 if (xflag) {
3273 int sep;
3274
3275 out2str(ps4val());
3276 sep = 0;
3277 sep = eprintlist(varlist.list, sep);
3278 eprintlist(arglist.list, sep);
3279 out2c('\n');
3280 flushall();
3281 }
3282
3283 cmd_is_exec = 0;
3284 spclbltin = -1;
3285
3286 /* Now locate the command. */
3287 if (argc) {
3288 const char *oldpath;
3289 int cmd_flag = DO_ERR;
3290
3291 path += 5;
3292 oldpath = path;
3293 for (;;) {
3294 find_command(argv[0], &cmdentry, cmd_flag, path);
3295 if (cmdentry.cmdtype == CMDUNKNOWN) {
3296 status = 127;
3297 flushout(stderr);
3298 goto bail;
3299 }
3300
3301 /* implement bltin and command here */
3302 if (cmdentry.cmdtype != CMDBUILTIN)
3303 break;
3304 if (spclbltin < 0)
3305 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3306 if (cmdentry.u.cmd == EXECCMD)
3307 cmd_is_exec++;
3308#ifdef CONFIG_ASH_CMDCMD
3309 if (cmdentry.u.cmd == COMMANDCMD) {
3310
3311 path = oldpath;
3312 nargv = parse_command_args(argv, &path);
3313 if (!nargv)
3314 break;
3315 argc -= nargv - argv;
3316 argv = nargv;
3317 cmd_flag |= DO_NOFUNC;
3318 } else
3319#endif
3320 break;
3321 }
3322 }
3323
3324 if (status) {
3325 /* We have a redirection error. */
3326 if (spclbltin > 0)
3327 exraise(EXERROR);
3328bail:
3329 exitstatus = status;
3330 goto out;
3331 }
3332
3333 /* Execute the command. */
3334 switch (cmdentry.cmdtype) {
3335 default:
3336 /* Fork off a child process if necessary. */
3337 if (!(flags & EV_EXIT) || trap[0]) {
3338 INTOFF;
3339 jp = makejob(cmd, 1);
3340 if (forkshell(jp, cmd, FORK_FG) != 0) {
3341 exitstatus = waitforjob(jp);
3342 INTON;
3343 break;
3344 }
3345 FORCEINTON;
3346 }
3347 listsetvar(varlist.list, VEXPORT|VSTACK);
3348 shellexec(argv, path, cmdentry.u.index);
3349 /* NOTREACHED */
3350
3351 case CMDBUILTIN:
3352 cmdenviron = varlist.list;
3353 if (cmdenviron) {
3354 struct strlist *list = cmdenviron;
3355 int i = VNOSET;
3356 if (spclbltin > 0 || argc == 0) {
3357 i = 0;
3358 if (cmd_is_exec && argc > 1)
3359 i = VEXPORT;
3360 }
3361 listsetvar(list, i);
3362 }
3363 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3364 int exit_status;
3365 int i, j;
3366
3367 i = exception;
3368 if (i == EXEXIT)
3369 goto raise;
3370
3371 exit_status = 2;
3372 j = 0;
3373 if (i == EXINT)
3374 j = SIGINT;
3375 if (i == EXSIG)
3376 j = pendingsigs;
3377 if (j)
3378 exit_status = j + 128;
3379 exitstatus = exit_status;
3380
3381 if (i == EXINT || spclbltin > 0) {
3382raise:
3383 longjmp(handler->loc, 1);
3384 }
3385 FORCEINTON;
3386 }
3387 break;
3388
3389 case CMDFUNCTION:
3390 listsetvar(varlist.list, 0);
3391 if (evalfun(cmdentry.u.func, argc, argv, flags))
3392 goto raise;
3393 break;
3394 }
3395
3396out:
3397 popredir(cmd_is_exec);
3398 if (lastarg)
3399 /* dsl: I think this is intended to be used to support
3400 * '_' in 'vi' command mode during line editing...
3401 * However I implemented that within libedit itself.
3402 */
3403 setvar("_", lastarg, 0);
3404 popstackmark(&smark);
3405}
3406
3407static int
3408evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3409 char *volatile savecmdname;
3410 struct jmploc *volatile savehandler;
3411 struct jmploc jmploc;
3412 int i;
3413
3414 savecmdname = commandname;
3415 if ((i = setjmp(jmploc.loc)))
3416 goto cmddone;
3417 savehandler = handler;
3418 handler = &jmploc;
3419 commandname = argv[0];
3420 argptr = argv + 1;
3421 optptr = NULL; /* initialize nextopt */
3422 exitstatus = (*cmd->builtin)(argc, argv);
3423 flushall();
3424cmddone:
3425 exitstatus |= outerr(stdout);
3426 commandname = savecmdname;
3427 exsig = 0;
3428 handler = savehandler;
3429
3430 return i;
3431}
3432
3433static int
3434evalfun(struct funcnode *func, int argc, char **argv, int flags)
3435{
3436 volatile struct shparam saveparam;
3437 struct localvar *volatile savelocalvars;
3438 struct jmploc *volatile savehandler;
3439 struct jmploc jmploc;
3440 int e;
3441
3442 saveparam = shellparam;
3443 savelocalvars = localvars;
3444 if ((e = setjmp(jmploc.loc))) {
3445 goto funcdone;
3446 }
3447 INTOFF;
3448 savehandler = handler;
3449 handler = &jmploc;
3450 localvars = NULL;
3451 shellparam.malloc = 0;
3452 func->count++;
3453 INTON;
3454 shellparam.nparam = argc - 1;
3455 shellparam.p = argv + 1;
3456#ifdef CONFIG_ASH_GETOPTS
3457 shellparam.optind = 1;
3458 shellparam.optoff = -1;
3459#endif
3460 funcnest++;
3461 evaltree(&func->n, flags & EV_TESTED);
3462 funcnest--;
3463funcdone:
3464 INTOFF;
3465 freefunc(func);
3466 poplocalvars();
3467 localvars = savelocalvars;
3468 freeparam(&shellparam);
3469 shellparam = saveparam;
3470 handler = savehandler;
3471 INTON;
3472 if (evalskip == SKIPFUNC) {
3473 evalskip = 0;
3474 skipcount = 0;
3475 }
3476 return e;
3477}
3478
3479
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003480/*
3481 * Search for a command. This is called before we fork so that the
3482 * location of the command will be available in the parent as well as
Eric Andersenc470f442003-07-28 09:56:35 +00003483 * the child.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003484 */
3485
Eric Andersenc470f442003-07-28 09:56:35 +00003486static void
3487prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003488{
3489 struct cmdentry entry;
3490
3491 if (n->type == NCMD && n->ncmd.args)
Eric Andersenc470f442003-07-28 09:56:35 +00003492 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003493}
3494
Eric Andersencb57d552001-06-28 07:25:16 +00003495
Eric Andersenc470f442003-07-28 09:56:35 +00003496
Eric Andersencb57d552001-06-28 07:25:16 +00003497/*
3498 * Builtin commands. Builtin commands whose functions are closely
3499 * tied to evaluation are implemented here.
3500 */
3501
3502/*
Eric Andersenc470f442003-07-28 09:56:35 +00003503 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003504 */
3505
Eric Andersenc470f442003-07-28 09:56:35 +00003506static int
3507bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003508{
3509 /*
3510 * Preserve exitstatus of a previous possible redirection
3511 * as POSIX mandates
3512 */
Eric Andersenc470f442003-07-28 09:56:35 +00003513 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003514}
3515
3516
3517/*
3518 * Handle break and continue commands. Break, continue, and return are
3519 * all handled by setting the evalskip flag. The evaluation routines
3520 * above all check this flag, and if it is set they start skipping
3521 * commands rather than executing them. The variable skipcount is
3522 * the number of loops to break/continue, or the number of function
3523 * levels to return. (The latter is always 1.) It should probably
3524 * be an error to break out of more loops than exist, but it isn't
3525 * in the standard shell so we don't make it one here.
3526 */
3527
Eric Andersenc470f442003-07-28 09:56:35 +00003528static int
3529breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003530{
3531 int n = argc > 1 ? number(argv[1]) : 1;
3532
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003533 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003534 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003535 if (n > loopnest)
3536 n = loopnest;
3537 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003538 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003539 skipcount = n;
3540 }
3541 return 0;
3542}
3543
3544
3545/*
3546 * The return command.
3547 */
3548
Eric Andersenc470f442003-07-28 09:56:35 +00003549static int
3550returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003551{
Eric Andersenc470f442003-07-28 09:56:35 +00003552 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003553
3554 if (funcnest) {
3555 evalskip = SKIPFUNC;
3556 skipcount = 1;
3557 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003558 }
3559 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003560 /* Do what ksh does; skip the rest of the file */
3561 evalskip = SKIPFILE;
3562 skipcount = 1;
3563 return ret;
3564 }
3565}
3566
3567
Eric Andersenc470f442003-07-28 09:56:35 +00003568static int
3569falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003570{
3571 return 1;
3572}
3573
Eric Andersenc470f442003-07-28 09:56:35 +00003574
3575static int
3576truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003577{
3578 return 0;
3579}
Eric Andersen2870d962001-07-02 17:27:21 +00003580
Eric Andersencb57d552001-06-28 07:25:16 +00003581
Eric Andersenc470f442003-07-28 09:56:35 +00003582static int
3583execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003584{
3585 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003586 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003587 mflag = 0;
3588 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003589 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003590 }
3591 return 0;
3592}
3593
Eric Andersenc470f442003-07-28 09:56:35 +00003594
3595static int
3596eprintlist(struct strlist *sp, int sep)
Eric Andersencb57d552001-06-28 07:25:16 +00003597{
Eric Andersenc470f442003-07-28 09:56:35 +00003598 while (sp) {
3599 const char *p;
3600
3601 p = " %s" + (1 - sep);
3602 sep |= 1;
3603 fprintf(stderr, p, sp->text);
3604 sp = sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00003605 }
Eric Andersenc470f442003-07-28 09:56:35 +00003606
3607 return sep;
Eric Andersencb57d552001-06-28 07:25:16 +00003608}
Eric Andersenc470f442003-07-28 09:56:35 +00003609/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3610
3611/*
3612 * When commands are first encountered, they are entered in a hash table.
3613 * This ensures that a full path search will not have to be done for them
3614 * on each invocation.
3615 *
3616 * We should investigate converting to a linear search, even though that
3617 * would make the command name "hash" a misnomer.
3618 */
3619
3620#define CMDTABLESIZE 31 /* should be prime */
3621#define ARB 1 /* actual size determined at run time */
3622
3623
3624
3625struct tblentry {
3626 struct tblentry *next; /* next entry in hash chain */
3627 union param param; /* definition of builtin function */
3628 short cmdtype; /* index identifying command */
3629 char rehash; /* if set, cd done since entry created */
3630 char cmdname[ARB]; /* name of command */
3631};
3632
3633
3634static struct tblentry *cmdtable[CMDTABLESIZE];
3635static int builtinloc = -1; /* index in path of %builtin, or -1 */
3636
3637
3638static void tryexec(char *, char **, char **);
3639static void printentry(struct tblentry *);
3640static void clearcmdentry(int);
3641static struct tblentry *cmdlookup(const char *, int);
3642static void delete_cmd_entry(void);
3643
Eric Andersencb57d552001-06-28 07:25:16 +00003644
3645/*
3646 * Exec a program. Never returns. If you change this routine, you may
3647 * have to change the find_command routine as well.
3648 */
3649
Eric Andersenc470f442003-07-28 09:56:35 +00003650static void
3651shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003652{
3653 char *cmdname;
3654 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003655 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003656
Eric Andersenc470f442003-07-28 09:56:35 +00003657 clearredir(1);
3658 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003659 if (strchr(argv[0], '/') != NULL
3660#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3661 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003662#endif
3663 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003664 tryexec(argv[0], argv, envp);
3665 e = errno;
3666 } else {
3667 e = ENOENT;
3668 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3669 if (--idx < 0 && pathopt == NULL) {
3670 tryexec(cmdname, argv, envp);
3671 if (errno != ENOENT && errno != ENOTDIR)
3672 e = errno;
3673 }
3674 stunalloc(cmdname);
3675 }
3676 }
3677
3678 /* Map to POSIX errors */
3679 switch (e) {
3680 case EACCES:
3681 exerrno = 126;
3682 break;
3683 case ENOENT:
3684 exerrno = 127;
3685 break;
3686 default:
3687 exerrno = 2;
3688 break;
3689 }
Eric Andersenc470f442003-07-28 09:56:35 +00003690 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3691 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003692 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3693 /* NOTREACHED */
3694}
3695
Eric Andersen2870d962001-07-02 17:27:21 +00003696
Eric Andersenc470f442003-07-28 09:56:35 +00003697static void
3698tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003699{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003700 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003701#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003702 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003703 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003704
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003705#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Manuel Novoa III cad53642003-03-19 09:13:01 +00003706 name = bb_get_last_path_component(name);
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003707 if(find_applet_by_name(name) != NULL)
3708 flg_bb = 1;
3709#else
3710 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3711 flg_bb = 1;
3712 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003713#endif
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003714 if(flg_bb) {
3715 char **ap;
3716 char **new;
3717
3718 *argv = name;
3719 if(strcmp(name, "busybox")) {
3720 for (ap = argv; *ap; ap++);
3721 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3722 *ap++ = cmd = "/bin/busybox";
3723 while ((*ap++ = *argv++));
3724 argv = new;
3725 repeated++;
3726 } else {
3727 cmd = "/bin/busybox";
3728 }
3729 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003730#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003731
3732repeat:
3733#ifdef SYSV
3734 do {
3735 execve(cmd, argv, envp);
3736 } while (errno == EINTR);
3737#else
Eric Andersencb57d552001-06-28 07:25:16 +00003738 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003739#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003740 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003741 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003742 } else if (errno == ENOEXEC) {
3743 char **ap;
3744 char **new;
3745
Eric Andersenc470f442003-07-28 09:56:35 +00003746 for (ap = argv; *ap; ap++)
3747 ;
3748 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003749 *ap++ = cmd = "/bin/sh";
Eric Andersenc470f442003-07-28 09:56:35 +00003750 while ((*ap++ = *argv++))
3751 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003752 argv = new;
3753 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003754 }
Eric Andersencb57d552001-06-28 07:25:16 +00003755}
3756
Eric Andersenc470f442003-07-28 09:56:35 +00003757
Eric Andersencb57d552001-06-28 07:25:16 +00003758
3759/*
3760 * Do a path search. The variable path (passed by reference) should be
3761 * set to the start of the path before the first call; padvance will update
3762 * this value as it proceeds. Successive calls to padvance will return
3763 * the possible path expansions in sequence. If an option (indicated by
3764 * a percent sign) appears in the path entry then the global variable
3765 * pathopt will be set to point to it; otherwise pathopt will be set to
3766 * NULL.
3767 */
3768
Eric Andersenc470f442003-07-28 09:56:35 +00003769static char *
3770padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003771{
Eric Andersencb57d552001-06-28 07:25:16 +00003772 const char *p;
3773 char *q;
3774 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003775 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003776
3777 if (*path == NULL)
3778 return NULL;
3779 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003780 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3781 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003782 while (stackblocksize() < len)
3783 growstackblock();
3784 q = stackblock();
3785 if (p != start) {
3786 memcpy(q, start, p - start);
3787 q += p - start;
3788 *q++ = '/';
3789 }
3790 strcpy(q, name);
3791 pathopt = NULL;
3792 if (*p == '%') {
3793 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003794 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003795 }
3796 if (*p == ':')
3797 *path = p + 1;
3798 else
3799 *path = NULL;
3800 return stalloc(len);
3801}
3802
3803
3804
3805/*** Command hashing code ***/
3806
Eric Andersenc470f442003-07-28 09:56:35 +00003807
3808static int
3809hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003810{
3811 struct tblentry **pp;
3812 struct tblentry *cmdp;
3813 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003814 struct cmdentry entry;
3815 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003816
Eric Andersenc470f442003-07-28 09:56:35 +00003817 while ((c = nextopt("r")) != '\0') {
3818 clearcmdentry(0);
3819 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003820 }
3821 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003822 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3823 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3824 if (cmdp->cmdtype == CMDNORMAL)
3825 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003826 }
3827 }
3828 return 0;
3829 }
3830 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003831 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003832 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003833 && (cmdp->cmdtype == CMDNORMAL
3834 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003835 delete_cmd_entry();
3836 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003837 if (entry.cmdtype == CMDUNKNOWN)
3838 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003839 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003840 }
3841 return c;
3842}
3843
Eric Andersenc470f442003-07-28 09:56:35 +00003844
3845static void
3846printentry(struct tblentry *cmdp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00003847{
Eric Andersencb57d552001-06-28 07:25:16 +00003848 int idx;
3849 const char *path;
3850 char *name;
3851
Eric Andersenc470f442003-07-28 09:56:35 +00003852 idx = cmdp->param.index;
3853 path = pathval();
3854 do {
3855 name = padvance(&path, cmdp->cmdname);
3856 stunalloc(name);
3857 } while (--idx >= 0);
3858 out1str(name);
3859 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +00003860}
3861
3862
3863
3864/*
3865 * Resolve a command name. If you change this routine, you may have to
3866 * change the shellexec routine as well.
3867 */
3868
3869static void
Eric Andersenc470f442003-07-28 09:56:35 +00003870find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003871{
3872 struct tblentry *cmdp;
3873 int idx;
3874 int prev;
3875 char *fullname;
3876 struct stat statb;
3877 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003878 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003879 struct builtincmd *bcmd;
3880
Eric Andersenc470f442003-07-28 09:56:35 +00003881 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003882 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003883 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003884 if (act & DO_ABS) {
3885 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003886#ifdef SYSV
3887 if (errno == EINTR)
3888 continue;
3889#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003890 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003891 return;
3892 }
Eric Andersencb57d552001-06-28 07:25:16 +00003893 }
3894 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003895 return;
3896 }
3897
Eric Andersenbf8bf102002-09-17 08:41:08 +00003898#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3899 if (find_applet_by_name(name)) {
3900 entry->cmdtype = CMDNORMAL;
3901 entry->u.index = -1;
3902 return;
3903 }
3904#endif
3905
Eric Andersenc470f442003-07-28 09:56:35 +00003906 updatetbl = (path == pathval());
3907 if (!updatetbl) {
3908 act |= DO_ALTPATH;
3909 if (strstr(path, "%builtin") != NULL)
3910 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003911 }
3912
Eric Andersenc470f442003-07-28 09:56:35 +00003913 /* If name is in the table, check answer will be ok */
3914 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3915 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003916
Eric Andersenc470f442003-07-28 09:56:35 +00003917 switch (cmdp->cmdtype) {
3918 default:
3919#if DEBUG
3920 abort();
3921#endif
3922 case CMDNORMAL:
3923 bit = DO_ALTPATH;
3924 break;
3925 case CMDFUNCTION:
3926 bit = DO_NOFUNC;
3927 break;
3928 case CMDBUILTIN:
3929 bit = DO_ALTBLTIN;
3930 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003931 }
Eric Andersenc470f442003-07-28 09:56:35 +00003932 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003933 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003934 cmdp = NULL;
3935 } else if (cmdp->rehash == 0)
3936 /* if not invalidated by cd, we're done */
3937 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003938 }
3939
3940 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003941 bcmd = find_builtin(name);
3942 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3943 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3944 )))
3945 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003946
3947 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003948 prev = -1; /* where to start */
3949 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003950 if (cmdp->cmdtype == CMDBUILTIN)
3951 prev = builtinloc;
3952 else
3953 prev = cmdp->param.index;
3954 }
3955
3956 e = ENOENT;
3957 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003958loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003959 while ((fullname = padvance(&path, name)) != NULL) {
3960 stunalloc(fullname);
3961 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003962 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003963 if (prefix(pathopt, "builtin")) {
3964 if (bcmd)
3965 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003966 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003967 } else if (!(act & DO_NOFUNC) &&
3968 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003969 /* handled below */
3970 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003971 /* ignore unimplemented options */
3972 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003973 }
3974 }
3975 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003976 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003977 if (idx < prev)
3978 continue;
3979 TRACE(("searchexec \"%s\": no change\n", name));
3980 goto success;
3981 }
3982 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003983#ifdef SYSV
3984 if (errno == EINTR)
3985 continue;
3986#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003987 if (errno != ENOENT && errno != ENOTDIR)
3988 e = errno;
3989 goto loop;
3990 }
Eric Andersenc470f442003-07-28 09:56:35 +00003991 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003992 if (!S_ISREG(statb.st_mode))
3993 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003994 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003995 stalloc(strlen(fullname) + 1);
3996 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003997 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3998 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003999 error("%s not defined in %s", name, fullname);
4000 stunalloc(fullname);
4001 goto success;
4002 }
Eric Andersencb57d552001-06-28 07:25:16 +00004003 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004004 if (!updatetbl) {
4005 entry->cmdtype = CMDNORMAL;
4006 entry->u.index = idx;
4007 return;
4008 }
4009 INTOFF;
4010 cmdp = cmdlookup(name, 1);
4011 cmdp->cmdtype = CMDNORMAL;
4012 cmdp->param.index = idx;
4013 INTON;
4014 goto success;
4015 }
4016
4017 /* We failed. If there was an entry for this command, delete it */
4018 if (cmdp && updatetbl)
4019 delete_cmd_entry();
4020 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004021 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004022 entry->cmdtype = CMDUNKNOWN;
4023 return;
4024
Eric Andersenc470f442003-07-28 09:56:35 +00004025builtin_success:
4026 if (!updatetbl) {
4027 entry->cmdtype = CMDBUILTIN;
4028 entry->u.cmd = bcmd;
4029 return;
4030 }
4031 INTOFF;
4032 cmdp = cmdlookup(name, 1);
4033 cmdp->cmdtype = CMDBUILTIN;
4034 cmdp->param.cmd = bcmd;
4035 INTON;
4036success:
Eric Andersencb57d552001-06-28 07:25:16 +00004037 cmdp->rehash = 0;
4038 entry->cmdtype = cmdp->cmdtype;
4039 entry->u = cmdp->param;
4040}
4041
4042
Eric Andersenc470f442003-07-28 09:56:35 +00004043/*
4044 * Wrapper around strcmp for qsort/bsearch/...
4045 */
4046static int pstrcmp(const void *a, const void *b)
4047{
4048 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4049}
Eric Andersencb57d552001-06-28 07:25:16 +00004050
4051/*
4052 * Search the table of builtin commands.
4053 */
4054
Eric Andersenc470f442003-07-28 09:56:35 +00004055static struct builtincmd *
4056find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004057{
4058 struct builtincmd *bp;
4059
Eric Andersenc470f442003-07-28 09:56:35 +00004060 bp = bsearch(
4061 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4062 pstrcmp
4063 );
Eric Andersencb57d552001-06-28 07:25:16 +00004064 return bp;
4065}
4066
4067
Eric Andersenc470f442003-07-28 09:56:35 +00004068
Eric Andersencb57d552001-06-28 07:25:16 +00004069/*
4070 * Called when a cd is done. Marks all commands so the next time they
4071 * are executed they will be rehashed.
4072 */
4073
Eric Andersenc470f442003-07-28 09:56:35 +00004074static void
4075hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004076{
Eric Andersencb57d552001-06-28 07:25:16 +00004077 struct tblentry **pp;
4078 struct tblentry *cmdp;
4079
Eric Andersenc470f442003-07-28 09:56:35 +00004080 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4081 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4082 if (cmdp->cmdtype == CMDNORMAL || (
4083 cmdp->cmdtype == CMDBUILTIN &&
4084 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4085 builtinloc > 0
4086 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004087 cmdp->rehash = 1;
4088 }
4089 }
4090}
4091
4092
4093
4094/*
Eric Andersenc470f442003-07-28 09:56:35 +00004095 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004096 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004097 * pathval() still returns the old value at this point.
4098 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004099 */
4100
Eric Andersenc470f442003-07-28 09:56:35 +00004101static void
4102changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004103{
Eric Andersenc470f442003-07-28 09:56:35 +00004104 const char *old, *new;
4105 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004106 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004107 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004108
Eric Andersenc470f442003-07-28 09:56:35 +00004109 old = pathval();
4110 new = newval;
4111 firstchange = 9999; /* assume no change */
4112 idx = 0;
4113 idx_bltin = -1;
4114 for (;;) {
4115 if (*old != *new) {
4116 firstchange = idx;
4117 if ((*old == '\0' && *new == ':')
4118 || (*old == ':' && *new == '\0'))
4119 firstchange++;
4120 old = new; /* ignore subsequent differences */
4121 }
4122 if (*new == '\0')
4123 break;
4124 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4125 idx_bltin = idx;
4126 if (*new == ':') {
4127 idx++;
4128 }
4129 new++, old++;
4130 }
4131 if (builtinloc < 0 && idx_bltin >= 0)
4132 builtinloc = idx_bltin; /* zap builtins */
4133 if (builtinloc >= 0 && idx_bltin < 0)
4134 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004135 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004136 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004137}
4138
4139
4140/*
4141 * Clear out command entries. The argument specifies the first entry in
4142 * PATH which has changed.
4143 */
4144
Eric Andersenc470f442003-07-28 09:56:35 +00004145static void
4146clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004147{
4148 struct tblentry **tblp;
4149 struct tblentry **pp;
4150 struct tblentry *cmdp;
4151
4152 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004153 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004154 pp = tblp;
4155 while ((cmdp = *pp) != NULL) {
4156 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004157 cmdp->param.index >= firstchange)
4158 || (cmdp->cmdtype == CMDBUILTIN &&
4159 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004160 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004161 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004162 } else {
4163 pp = &cmdp->next;
4164 }
4165 }
4166 }
4167 INTON;
4168}
4169
4170
Eric Andersenc470f442003-07-28 09:56:35 +00004171
Eric Andersencb57d552001-06-28 07:25:16 +00004172/*
Eric Andersencb57d552001-06-28 07:25:16 +00004173 * Locate a command in the command hash table. If "add" is nonzero,
4174 * add the command to the table if it is not already present. The
4175 * variable "lastcmdentry" is set to point to the address of the link
4176 * pointing to the entry, so that delete_cmd_entry can delete the
4177 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004178 *
4179 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004180 */
4181
Eric Andersen2870d962001-07-02 17:27:21 +00004182static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004183
Eric Andersenc470f442003-07-28 09:56:35 +00004184
4185static struct tblentry *
4186cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004187{
Eric Andersenc470f442003-07-28 09:56:35 +00004188 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004189 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004190 struct tblentry *cmdp;
4191 struct tblentry **pp;
4192
4193 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004194 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004195 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004196 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004197 hashval &= 0x7FFF;
4198 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004199 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004200 if (equal(cmdp->cmdname, name))
4201 break;
4202 pp = &cmdp->next;
4203 }
4204 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004205 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4206 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004207 cmdp->next = NULL;
4208 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004209 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004210 }
4211 lastcmdentry = pp;
4212 return cmdp;
4213}
4214
4215/*
4216 * Delete the command entry returned on the last lookup.
4217 */
4218
Eric Andersenc470f442003-07-28 09:56:35 +00004219static void
4220delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004221{
Eric Andersencb57d552001-06-28 07:25:16 +00004222 struct tblentry *cmdp;
4223
4224 INTOFF;
4225 cmdp = *lastcmdentry;
4226 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004227 if (cmdp->cmdtype == CMDFUNCTION)
4228 freefunc(cmdp->param.func);
4229 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004230 INTON;
4231}
4232
4233
Eric Andersenc470f442003-07-28 09:56:35 +00004234/*
4235 * Add a new command entry, replacing any existing command entry for
4236 * the same name - except special builtins.
4237 */
Eric Andersencb57d552001-06-28 07:25:16 +00004238
Eric Andersenc470f442003-07-28 09:56:35 +00004239static inline void
4240addcmdentry(char *name, struct cmdentry *entry)
4241{
4242 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004243
Eric Andersenc470f442003-07-28 09:56:35 +00004244 cmdp = cmdlookup(name, 1);
4245 if (cmdp->cmdtype == CMDFUNCTION) {
4246 freefunc(cmdp->param.func);
4247 }
4248 cmdp->cmdtype = entry->cmdtype;
4249 cmdp->param = entry->u;
4250 cmdp->rehash = 0;
4251}
Eric Andersencb57d552001-06-28 07:25:16 +00004252
Eric Andersenc470f442003-07-28 09:56:35 +00004253/*
4254 * Make a copy of a parse tree.
4255 */
Eric Andersencb57d552001-06-28 07:25:16 +00004256
Eric Andersenc470f442003-07-28 09:56:35 +00004257static inline struct funcnode *
4258copyfunc(union node *n)
4259{
4260 struct funcnode *f;
4261 size_t blocksize;
4262
4263 funcblocksize = offsetof(struct funcnode, n);
4264 funcstringsize = 0;
4265 calcsize(n);
4266 blocksize = funcblocksize;
4267 f = ckmalloc(blocksize + funcstringsize);
4268 funcblock = (char *) f + offsetof(struct funcnode, n);
4269 funcstring = (char *) f + blocksize;
4270 copynode(n);
4271 f->count = 0;
4272 return f;
4273}
4274
4275/*
4276 * Define a shell function.
4277 */
4278
4279static void
4280defun(char *name, union node *func)
4281{
4282 struct cmdentry entry;
4283
4284 INTOFF;
4285 entry.cmdtype = CMDFUNCTION;
4286 entry.u.func = copyfunc(func);
4287 addcmdentry(name, &entry);
4288 INTON;
4289}
Eric Andersencb57d552001-06-28 07:25:16 +00004290
4291
4292/*
4293 * Delete a function if it exists.
4294 */
4295
Eric Andersenc470f442003-07-28 09:56:35 +00004296static void
4297unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004298{
Eric Andersencb57d552001-06-28 07:25:16 +00004299 struct tblentry *cmdp;
4300
Eric Andersenc470f442003-07-28 09:56:35 +00004301 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4302 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004303 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004304}
4305
Eric Andersen2870d962001-07-02 17:27:21 +00004306/*
Eric Andersencb57d552001-06-28 07:25:16 +00004307 * Locate and print what a word is...
4308 */
4309
Eric Andersenc470f442003-07-28 09:56:35 +00004310
4311#ifdef CONFIG_ASH_CMDCMD
4312static int
4313describe_command(char *command, int describe_command_verbose)
4314#else
4315#define describe_command_verbose 1
4316static int
4317describe_command(char *command)
4318#endif
4319{
4320 struct cmdentry entry;
4321 struct tblentry *cmdp;
4322#ifdef CONFIG_ASH_ALIAS
4323 const struct alias *ap;
4324#endif
4325 const char *path = pathval();
4326
4327 if (describe_command_verbose) {
4328 out1str(command);
4329 }
4330
4331 /* First look at the keywords */
4332 if (findkwd(command)) {
4333 out1str(describe_command_verbose ? " is a shell keyword" : command);
4334 goto out;
4335 }
4336
4337#ifdef CONFIG_ASH_ALIAS
4338 /* Then look at the aliases */
4339 if ((ap = lookupalias(command, 0)) != NULL) {
4340 if (describe_command_verbose) {
4341 out1fmt(" is an alias for %s", ap->val);
4342 } else {
4343 out1str("alias ");
4344 printalias(ap);
4345 return 0;
4346 }
4347 goto out;
4348 }
4349#endif
4350 /* Then check if it is a tracked alias */
4351 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4352 entry.cmdtype = cmdp->cmdtype;
4353 entry.u = cmdp->param;
4354 } else {
4355 /* Finally use brute force */
4356 find_command(command, &entry, DO_ABS, path);
4357 }
4358
4359 switch (entry.cmdtype) {
4360 case CMDNORMAL: {
4361 int j = entry.u.index;
4362 char *p;
4363 if (j == -1) {
4364 p = command;
4365 } else {
4366 do {
4367 p = padvance(&path, command);
4368 stunalloc(p);
4369 } while (--j >= 0);
4370 }
4371 if (describe_command_verbose) {
4372 out1fmt(" is%s %s",
4373 (cmdp ? " a tracked alias for" : nullstr), p
4374 );
4375 } else {
4376 out1str(p);
4377 }
4378 break;
4379 }
4380
4381 case CMDFUNCTION:
4382 if (describe_command_verbose) {
4383 out1str(" is a shell function");
4384 } else {
4385 out1str(command);
4386 }
4387 break;
4388
4389 case CMDBUILTIN:
4390 if (describe_command_verbose) {
4391 out1fmt(" is a %sshell builtin",
4392 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4393 "special " : nullstr
4394 );
4395 } else {
4396 out1str(command);
4397 }
4398 break;
4399
4400 default:
4401 if (describe_command_verbose) {
4402 out1str(": not found\n");
4403 }
4404 return 127;
4405 }
4406
4407out:
4408 out1c('\n');
4409 return 0;
4410}
4411
4412static int
4413typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004414{
4415 int i;
4416 int err = 0;
4417
4418 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004419#ifdef CONFIG_ASH_CMDCMD
4420 err |= describe_command(argv[i], 1);
4421#else
4422 err |= describe_command(argv[i]);
4423#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004424 }
4425 return err;
4426}
4427
Eric Andersend35c5df2002-01-09 15:37:36 +00004428#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004429static int
4430commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004431{
4432 int c;
4433 int default_path = 0;
4434 int verify_only = 0;
4435 int verbose_verify_only = 0;
4436
4437 while ((c = nextopt("pvV")) != '\0')
4438 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004439 default:
4440#ifdef DEBUG
4441 fprintf(stderr,
4442"command: nextopt returned character code 0%o\n", c);
4443 return EX_SOFTWARE;
4444#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004445 case 'p':
4446 default_path = 1;
4447 break;
4448 case 'v':
4449 verify_only = 1;
4450 break;
4451 case 'V':
4452 verbose_verify_only = 1;
4453 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004454 }
4455
Eric Andersenc470f442003-07-28 09:56:35 +00004456 if (default_path + verify_only + verbose_verify_only > 1 ||
4457 !*argptr) {
4458 fprintf(stderr,
4459 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004460 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004461 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004462 }
4463
Eric Andersencb57d552001-06-28 07:25:16 +00004464 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004465 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004466 }
Eric Andersencb57d552001-06-28 07:25:16 +00004467
4468 return 0;
4469}
Eric Andersen2870d962001-07-02 17:27:21 +00004470#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004471
Eric Andersenc470f442003-07-28 09:56:35 +00004472/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004473
Eric Andersencb57d552001-06-28 07:25:16 +00004474/*
4475 * Routines to expand arguments to commands. We have to deal with
4476 * backquotes, shell variables, and file metacharacters.
4477 */
Eric Andersenc470f442003-07-28 09:56:35 +00004478
Eric Andersencb57d552001-06-28 07:25:16 +00004479/*
4480 * _rmescape() flags
4481 */
Eric Andersenc470f442003-07-28 09:56:35 +00004482#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4483#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4484#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4485#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4486#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004487
4488/*
4489 * Structure specifying which parts of the string should be searched
4490 * for IFS characters.
4491 */
4492
4493struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004494 struct ifsregion *next; /* next region in list */
4495 int begoff; /* offset of start of region */
4496 int endoff; /* offset of end of region */
4497 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004498};
4499
Eric Andersenc470f442003-07-28 09:56:35 +00004500/* output of current string */
4501static char *expdest;
4502/* list of back quote expressions */
4503static struct nodelist *argbackq;
4504/* first struct in list of ifs regions */
4505static struct ifsregion ifsfirst;
4506/* last struct in list */
4507static struct ifsregion *ifslastp;
4508/* holds expanded arg list */
4509static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004510
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004511static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004512static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004513static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004514static const char *subevalvar(char *, char *, int, int, int, int, int);
4515static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004516static int varisset(char *, int);
4517static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004518static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004519static void varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004520static void recordregion(int, int, int);
4521static void removerecordregions(int);
4522static void ifsbreakup(char *, struct arglist *);
4523static void ifsfree(void);
4524static void expandmeta(struct strlist *, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004525static void addglob(const glob_t *);
Eric Andersenc470f442003-07-28 09:56:35 +00004526static void addfname(char *);
4527static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004528
Eric Andersenc470f442003-07-28 09:56:35 +00004529static int cvtnum(long);
4530static size_t esclen(const char *, const char *);
4531static char *scanleft(char *, char *, char *, char *, int, int);
4532static char *scanright(char *, char *, char *, char *, int, int);
4533static void varunset(const char *, const char *, const char *, int)
4534 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004535
Eric Andersenc470f442003-07-28 09:56:35 +00004536
4537#define pmatch(a, b) !fnmatch((a), (b), 0)
4538/*
4539 * Prepare a pattern for a glob(3) call.
4540 *
4541 * Returns an stalloced string.
4542 */
4543
4544static inline char *
4545preglob(const char *pattern, int quoted, int flag) {
4546 flag |= RMESCAPE_GLOB;
4547 if (quoted) {
4548 flag |= RMESCAPE_QUOTED;
4549 }
4550 return _rmescapes((char *)pattern, flag);
4551}
4552
4553
4554static size_t
4555esclen(const char *start, const char *p) {
4556 size_t esc = 0;
4557
4558 while (p > start && *--p == CTLESC) {
4559 esc++;
4560 }
4561 return esc;
4562}
4563
Eric Andersencb57d552001-06-28 07:25:16 +00004564
4565/*
4566 * Expand shell variables and backquotes inside a here document.
4567 */
4568
Eric Andersenc470f442003-07-28 09:56:35 +00004569static inline void
4570expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004571{
Eric Andersencb57d552001-06-28 07:25:16 +00004572 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004573 expandarg(arg, (struct arglist *)NULL, 0);
4574 xwrite(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004575}
4576
4577
4578/*
4579 * Perform variable substitution and command substitution on an argument,
4580 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4581 * perform splitting and file name expansion. When arglist is NULL, perform
4582 * here document expansion.
4583 */
4584
Eric Andersenc470f442003-07-28 09:56:35 +00004585void
4586expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004587{
4588 struct strlist *sp;
4589 char *p;
4590
4591 argbackq = arg->narg.backquote;
4592 STARTSTACKSTR(expdest);
4593 ifsfirst.next = NULL;
4594 ifslastp = NULL;
4595 argstr(arg->narg.text, flag);
4596 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004597 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004598 }
4599 STPUTC('\0', expdest);
4600 p = grabstackstr(expdest);
4601 exparg.lastp = &exparg.list;
4602 /*
4603 * TODO - EXP_REDIR
4604 */
4605 if (flag & EXP_FULL) {
4606 ifsbreakup(p, &exparg);
4607 *exparg.lastp = NULL;
4608 exparg.lastp = &exparg.list;
4609 expandmeta(exparg.list, flag);
4610 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004611 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004612 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004613 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004614 sp->text = p;
4615 *exparg.lastp = sp;
4616 exparg.lastp = &sp->next;
4617 }
Eric Andersenc470f442003-07-28 09:56:35 +00004618 if (ifsfirst.next)
4619 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004620 *exparg.lastp = NULL;
4621 if (exparg.list) {
4622 *arglist->lastp = exparg.list;
4623 arglist->lastp = exparg.lastp;
4624 }
4625}
4626
4627
Eric Andersenc470f442003-07-28 09:56:35 +00004628
4629/*
4630 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4631 * characters to allow for further processing. Otherwise treat
4632 * $@ like $* since no splitting will be performed.
4633 */
4634
4635static void
4636argstr(char *p, int flag)
4637{
4638 static const char spclchars[] = {
4639 '=',
4640 ':',
4641 CTLQUOTEMARK,
4642 CTLENDVAR,
4643 CTLESC,
4644 CTLVAR,
4645 CTLBACKQ,
4646 CTLBACKQ | CTLQUOTE,
4647#ifdef CONFIG_ASH_MATH_SUPPORT
4648 CTLENDARI,
4649#endif
4650 0
4651 };
4652 const char *reject = spclchars;
4653 int c;
4654 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4655 int breakall = flag & EXP_WORD;
4656 int inquotes;
4657 size_t length;
4658 int startloc;
4659
4660 if (!(flag & EXP_VARTILDE)) {
4661 reject += 2;
4662 } else if (flag & EXP_VARTILDE2) {
4663 reject++;
4664 }
4665 inquotes = 0;
4666 length = 0;
4667 if (flag & EXP_TILDE) {
4668 char *q;
4669
4670 flag &= ~EXP_TILDE;
4671tilde:
4672 q = p;
4673 if (*q == CTLESC && (flag & EXP_QWORD))
4674 q++;
4675 if (*q == '~')
4676 p = exptilde(p, q, flag);
4677 }
4678start:
4679 startloc = expdest - (char *)stackblock();
4680 for (;;) {
4681 length += strcspn(p + length, reject);
4682 c = p[length];
4683 if (c && (!(c & 0x80)
4684#ifdef CONFIG_ASH_MATH_SUPPORT
4685 || c == CTLENDARI
4686#endif
4687 )) {
4688 /* c == '=' || c == ':' || c == CTLENDARI */
4689 length++;
4690 }
4691 if (length > 0) {
4692 int newloc;
4693 expdest = stnputs(p, length, expdest);
4694 newloc = expdest - (char *)stackblock();
4695 if (breakall && !inquotes && newloc > startloc) {
4696 recordregion(startloc, newloc, 0);
4697 }
4698 startloc = newloc;
4699 }
4700 p += length + 1;
4701 length = 0;
4702
4703 switch (c) {
4704 case '\0':
4705 goto breakloop;
4706 case '=':
4707 if (flag & EXP_VARTILDE2) {
4708 p--;
4709 continue;
4710 }
4711 flag |= EXP_VARTILDE2;
4712 reject++;
4713 /* fall through */
4714 case ':':
4715 /*
4716 * sort of a hack - expand tildes in variable
4717 * assignments (after the first '=' and after ':'s).
4718 */
4719 if (*--p == '~') {
4720 goto tilde;
4721 }
4722 continue;
4723 }
4724
4725 switch (c) {
4726 case CTLENDVAR: /* ??? */
4727 goto breakloop;
4728 case CTLQUOTEMARK:
4729 /* "$@" syntax adherence hack */
4730 if (
4731 !inquotes &&
4732 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4733 (p[4] == CTLQUOTEMARK || (
4734 p[4] == CTLENDVAR &&
4735 p[5] == CTLQUOTEMARK
4736 ))
4737 ) {
4738 p = evalvar(p + 1, flag) + 1;
4739 goto start;
4740 }
4741 inquotes = !inquotes;
4742addquote:
4743 if (quotes) {
4744 p--;
4745 length++;
4746 startloc++;
4747 }
4748 break;
4749 case CTLESC:
4750 startloc++;
4751 length++;
4752 goto addquote;
4753 case CTLVAR:
4754 p = evalvar(p, flag);
4755 goto start;
4756 case CTLBACKQ:
4757 c = 0;
4758 case CTLBACKQ|CTLQUOTE:
4759 expbackq(argbackq->n, c, quotes);
4760 argbackq = argbackq->next;
4761 goto start;
4762#ifdef CONFIG_ASH_MATH_SUPPORT
4763 case CTLENDARI:
4764 p--;
4765 expari(quotes);
4766 goto start;
4767#endif
4768 }
4769 }
4770breakloop:
4771 ;
4772}
4773
4774static char *
4775exptilde(char *startp, char *p, int flag)
4776{
4777 char c;
4778 char *name;
4779 struct passwd *pw;
4780 const char *home;
4781 int quotes = flag & (EXP_FULL | EXP_CASE);
4782 int startloc;
4783
4784 name = p + 1;
4785
4786 while ((c = *++p) != '\0') {
4787 switch(c) {
4788 case CTLESC:
4789 return (startp);
4790 case CTLQUOTEMARK:
4791 return (startp);
4792 case ':':
4793 if (flag & EXP_VARTILDE)
4794 goto done;
4795 break;
4796 case '/':
4797 case CTLENDVAR:
4798 goto done;
4799 }
4800 }
4801done:
4802 *p = '\0';
4803 if (*name == '\0') {
4804 if ((home = lookupvar(homestr)) == NULL)
4805 goto lose;
4806 } else {
4807 if ((pw = getpwnam(name)) == NULL)
4808 goto lose;
4809 home = pw->pw_dir;
4810 }
4811 if (*home == '\0')
4812 goto lose;
4813 *p = c;
4814 startloc = expdest - (char *)stackblock();
4815 strtodest(home, SQSYNTAX, quotes);
4816 recordregion(startloc, expdest - (char *)stackblock(), 0);
4817 return (p);
4818lose:
4819 *p = c;
4820 return (startp);
4821}
4822
4823
4824static void
4825removerecordregions(int endoff)
4826{
4827 if (ifslastp == NULL)
4828 return;
4829
4830 if (ifsfirst.endoff > endoff) {
4831 while (ifsfirst.next != NULL) {
4832 struct ifsregion *ifsp;
4833 INTOFF;
4834 ifsp = ifsfirst.next->next;
4835 ckfree(ifsfirst.next);
4836 ifsfirst.next = ifsp;
4837 INTON;
4838 }
4839 if (ifsfirst.begoff > endoff)
4840 ifslastp = NULL;
4841 else {
4842 ifslastp = &ifsfirst;
4843 ifsfirst.endoff = endoff;
4844 }
4845 return;
4846 }
4847
4848 ifslastp = &ifsfirst;
4849 while (ifslastp->next && ifslastp->next->begoff < endoff)
4850 ifslastp=ifslastp->next;
4851 while (ifslastp->next != NULL) {
4852 struct ifsregion *ifsp;
4853 INTOFF;
4854 ifsp = ifslastp->next->next;
4855 ckfree(ifslastp->next);
4856 ifslastp->next = ifsp;
4857 INTON;
4858 }
4859 if (ifslastp->endoff > endoff)
4860 ifslastp->endoff = endoff;
4861}
4862
4863
4864#ifdef CONFIG_ASH_MATH_SUPPORT
4865/*
4866 * Expand arithmetic expression. Backup to start of expression,
4867 * evaluate, place result in (backed up) result, adjust string position.
4868 */
4869void
4870expari(int quotes)
4871{
4872 char *p, *start;
4873 int begoff;
4874 int flag;
4875 int len;
4876
4877 /* ifsfree(); */
4878
4879 /*
4880 * This routine is slightly over-complicated for
4881 * efficiency. Next we scan backwards looking for the
4882 * start of arithmetic.
4883 */
4884 start = stackblock();
4885 p = expdest - 1;
4886 *p = '\0';
4887 p--;
4888 do {
4889 int esc;
4890
4891 while (*p != CTLARI) {
4892 p--;
4893#ifdef DEBUG
4894 if (p < start) {
4895 error("missing CTLARI (shouldn't happen)");
4896 }
4897#endif
4898 }
4899
4900 esc = esclen(start, p);
4901 if (!(esc % 2)) {
4902 break;
4903 }
4904
4905 p -= esc + 1;
4906 } while (1);
4907
4908 begoff = p - start;
4909
4910 removerecordregions(begoff);
4911
4912 flag = p[1];
4913
4914 expdest = p;
4915
4916 if (quotes)
4917 rmescapes(p + 2);
4918
4919 len = cvtnum(dash_arith(p + 2));
4920
4921 if (flag != '"')
4922 recordregion(begoff, begoff + len, 0);
4923}
4924#endif
4925
4926/*
4927 * Expand stuff in backwards quotes.
4928 */
4929
4930static void
4931expbackq(union node *cmd, int quoted, int quotes)
4932{
4933 struct backcmd in;
4934 int i;
4935 char buf[128];
4936 char *p;
4937 char *dest;
4938 int startloc;
4939 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4940 struct stackmark smark;
4941
4942 INTOFF;
4943 setstackmark(&smark);
4944 dest = expdest;
4945 startloc = dest - (char *)stackblock();
4946 grabstackstr(dest);
4947 evalbackcmd(cmd, (struct backcmd *) &in);
4948 popstackmark(&smark);
4949
4950 p = in.buf;
4951 i = in.nleft;
4952 if (i == 0)
4953 goto read;
4954 for (;;) {
4955 memtodest(p, i, syntax, quotes);
4956read:
4957 if (in.fd < 0)
4958 break;
4959 i = safe_read(in.fd, buf, sizeof buf);
4960 TRACE(("expbackq: read returns %d\n", i));
4961 if (i <= 0)
4962 break;
4963 p = buf;
4964 }
4965
4966 if (in.buf)
4967 ckfree(in.buf);
4968 if (in.fd >= 0) {
4969 close(in.fd);
4970 back_exitstatus = waitforjob(in.jp);
4971 }
4972 INTON;
4973
4974 /* Eat all trailing newlines */
4975 dest = expdest;
4976 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4977 STUNPUTC(dest);
4978 expdest = dest;
4979
4980 if (quoted == 0)
4981 recordregion(startloc, dest - (char *)stackblock(), 0);
4982 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4983 (dest - (char *)stackblock()) - startloc,
4984 (dest - (char *)stackblock()) - startloc,
4985 stackblock() + startloc));
4986}
4987
4988
4989static char *
4990scanleft(
4991 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4992 int zero
4993) {
4994 char *loc;
4995 char *loc2;
4996 char c;
4997
4998 loc = startp;
4999 loc2 = rmesc;
5000 do {
5001 int match;
5002 const char *s = loc2;
5003 c = *loc2;
5004 if (zero) {
5005 *loc2 = '\0';
5006 s = rmesc;
5007 }
5008 match = pmatch(str, s);
5009 *loc2 = c;
5010 if (match)
5011 return loc;
5012 if (quotes && *loc == CTLESC)
5013 loc++;
5014 loc++;
5015 loc2++;
5016 } while (c);
5017 return 0;
5018}
5019
5020
5021static char *
5022scanright(
5023 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5024 int zero
5025) {
5026 int esc = 0;
5027 char *loc;
5028 char *loc2;
5029
5030 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5031 int match;
5032 char c = *loc2;
5033 const char *s = loc2;
5034 if (zero) {
5035 *loc2 = '\0';
5036 s = rmesc;
5037 }
5038 match = pmatch(str, s);
5039 *loc2 = c;
5040 if (match)
5041 return loc;
5042 loc--;
5043 if (quotes) {
5044 if (--esc < 0) {
5045 esc = esclen(startp, loc);
5046 }
5047 if (esc % 2) {
5048 esc--;
5049 loc--;
5050 }
5051 }
5052 }
5053 return 0;
5054}
5055
5056static const char *
5057subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5058{
5059 char *startp;
5060 char *loc;
5061 int saveherefd = herefd;
5062 struct nodelist *saveargbackq = argbackq;
5063 int amount;
5064 char *rmesc, *rmescend;
5065 int zero;
5066 char *(*scan)(char *, char *, char *, char *, int , int);
5067
5068 herefd = -1;
5069 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5070 STPUTC('\0', expdest);
5071 herefd = saveherefd;
5072 argbackq = saveargbackq;
5073 startp = stackblock() + startloc;
5074
5075 switch (subtype) {
5076 case VSASSIGN:
5077 setvar(str, startp, 0);
5078 amount = startp - expdest;
5079 STADJUST(amount, expdest);
5080 return startp;
5081
5082 case VSQUESTION:
5083 varunset(p, str, startp, varflags);
5084 /* NOTREACHED */
5085 }
5086
5087 subtype -= VSTRIMRIGHT;
5088#ifdef DEBUG
5089 if (subtype < 0 || subtype > 3)
5090 abort();
5091#endif
5092
5093 rmesc = startp;
5094 rmescend = stackblock() + strloc;
5095 if (quotes) {
5096 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5097 if (rmesc != startp) {
5098 rmescend = expdest;
5099 startp = stackblock() + startloc;
5100 }
5101 }
5102 rmescend--;
5103 str = stackblock() + strloc;
5104 preglob(str, varflags & VSQUOTE, 0);
5105
5106 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5107 zero = subtype >> 1;
5108 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5109 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5110
5111 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5112 if (loc) {
5113 if (zero) {
5114 memmove(startp, loc, str - loc);
5115 loc = startp + (str - loc) - 1;
5116 }
5117 *loc = '\0';
5118 amount = loc - expdest;
5119 STADJUST(amount, expdest);
5120 }
5121 return loc;
5122}
5123
5124
Eric Andersen62483552001-07-10 06:09:16 +00005125/*
5126 * Expand a variable, and return a pointer to the next character in the
5127 * input string.
5128 */
Eric Andersenc470f442003-07-28 09:56:35 +00005129static char *
5130evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005131{
5132 int subtype;
5133 int varflags;
5134 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005135 int patloc;
5136 int c;
5137 int set;
Eric Andersen62483552001-07-10 06:09:16 +00005138 int startloc;
Eric Andersenc470f442003-07-28 09:56:35 +00005139 size_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005140 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005141 int quotes;
5142 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005143
Eric Andersenc470f442003-07-28 09:56:35 +00005144 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005145 varflags = *p++;
5146 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005147 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005148 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005149 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersen62483552001-07-10 06:09:16 +00005150 varlen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00005151 startloc = expdest - (char *)stackblock();
5152 p = strchr(p, '=') + 1;
5153
5154 if (!is_name(*var)) {
5155 set = varisset(var, varflags & VSNUL);
5156 set--;
5157 if (subtype == VSPLUS)
5158 goto vsplus;
5159 if (++set) {
5160 varvalue(var, quoted, flag);
Eric Andersen62483552001-07-10 06:09:16 +00005161 if (subtype == VSLENGTH) {
Eric Andersenc470f442003-07-28 09:56:35 +00005162 varlen =
5163 expdest - (char *)stackblock() -
5164 startloc;
Eric Andersen62483552001-07-10 06:09:16 +00005165 STADJUST(-varlen, expdest);
Eric Andersenc470f442003-07-28 09:56:35 +00005166 goto vslen;
Eric Andersen62483552001-07-10 06:09:16 +00005167 }
Eric Andersenc470f442003-07-28 09:56:35 +00005168 }
5169 } else {
5170 const char *val;
5171again:
5172 /* jump here after setting a variable with ${var=text} */
5173 val = lookupvar(var);
5174 set = !val || ((varflags & VSNUL) && !*val);
5175 if (subtype == VSPLUS)
5176 goto vsplus;
5177 if (--set) {
5178 varlen = strlen(val);
5179 if (subtype == VSLENGTH)
5180 goto vslen;
5181 memtodest(
5182 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5183 quotes
5184 );
Eric Andersen62483552001-07-10 06:09:16 +00005185 }
5186 }
5187
Eric Andersen62483552001-07-10 06:09:16 +00005188
Eric Andersenc470f442003-07-28 09:56:35 +00005189 if (subtype == VSMINUS) {
5190vsplus:
Eric Andersen62483552001-07-10 06:09:16 +00005191 if (!set) {
Eric Andersenc470f442003-07-28 09:56:35 +00005192 argstr(
5193 p, flag | EXP_TILDE |
5194 (quoted ? EXP_QWORD : EXP_WORD)
5195 );
5196 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005197 }
5198 if (easy)
5199 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005200 goto end;
5201 }
Eric Andersen62483552001-07-10 06:09:16 +00005202
Eric Andersenc470f442003-07-28 09:56:35 +00005203 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Eric Andersen62483552001-07-10 06:09:16 +00005204 if (!set) {
Eric Andersenc470f442003-07-28 09:56:35 +00005205 if (subevalvar(p, var, 0, subtype, startloc,
5206 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005207 varflags &= ~VSNUL;
5208 /*
5209 * Remove any recorded regions beyond
5210 * start of variable
5211 */
5212 removerecordregions(startloc);
5213 goto again;
5214 }
Eric Andersenc470f442003-07-28 09:56:35 +00005215 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005216 }
5217 if (easy)
5218 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005219 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005220 }
5221
Eric Andersenc470f442003-07-28 09:56:35 +00005222 if (!set && uflag)
5223 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005224
Eric Andersenc470f442003-07-28 09:56:35 +00005225 if (subtype == VSLENGTH) {
5226vslen:
5227 cvtnum(varlen);
5228 goto record;
5229 }
5230
5231 if (subtype == VSNORMAL) {
5232 if (!easy)
5233 goto end;
5234record:
5235 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5236 goto end;
5237 }
5238
5239#ifdef DEBUG
5240 switch (subtype) {
5241 case VSTRIMLEFT:
5242 case VSTRIMLEFTMAX:
5243 case VSTRIMRIGHT:
5244 case VSTRIMRIGHTMAX:
5245 break;
5246 default:
5247 abort();
5248 }
5249#endif
5250
5251 if (set) {
5252 /*
5253 * Terminate the string and start recording the pattern
5254 * right after it
5255 */
5256 STPUTC('\0', expdest);
5257 patloc = expdest - (char *)stackblock();
5258 if (subevalvar(p, NULL, patloc, subtype,
5259 startloc, varflags, quotes) == 0) {
5260 int amount = expdest - (
5261 (char *)stackblock() + patloc - 1
5262 );
5263 STADJUST(-amount, expdest);
5264 }
5265 /* Remove any recorded regions beyond start of variable */
5266 removerecordregions(startloc);
5267 goto record;
5268 }
5269
5270end:
5271 if (subtype != VSNORMAL) { /* skip to end of alternative */
5272 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005273 for (;;) {
5274 if ((c = *p++) == CTLESC)
5275 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005276 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Eric Andersen62483552001-07-10 06:09:16 +00005277 if (set)
5278 argbackq = argbackq->next;
5279 } else if (c == CTLVAR) {
5280 if ((*p++ & VSTYPE) != VSNORMAL)
5281 nesting++;
5282 } else if (c == CTLENDVAR) {
5283 if (--nesting == 0)
5284 break;
5285 }
5286 }
5287 }
5288 return p;
5289}
5290
Eric Andersencb57d552001-06-28 07:25:16 +00005291
Eric Andersencb57d552001-06-28 07:25:16 +00005292
5293/*
Eric Andersencb57d552001-06-28 07:25:16 +00005294 * Test whether a specialized variable is set.
5295 */
5296
Eric Andersenc470f442003-07-28 09:56:35 +00005297static int
5298varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00005299{
5300 if (*name == '!')
Eric Andersenc470f442003-07-28 09:56:35 +00005301 return backgndpid != 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005302 else if (*name == '@' || *name == '*') {
5303 if (*shellparam.p == NULL)
5304 return 0;
5305
5306 if (nulok) {
5307 char **av;
5308
5309 for (av = shellparam.p; *av; av++)
5310 if (**av != '\0')
5311 return 1;
5312 return 0;
5313 }
5314 } else if (is_digit(*name)) {
5315 char *ap;
5316 int num = atoi(name);
5317
5318 if (num > shellparam.nparam)
5319 return 0;
5320
5321 if (num == 0)
5322 ap = arg0;
5323 else
5324 ap = shellparam.p[num - 1];
5325
5326 if (nulok && (ap == NULL || *ap == '\0'))
5327 return 0;
5328 }
5329 return 1;
5330}
5331
Eric Andersenc470f442003-07-28 09:56:35 +00005332
5333
Eric Andersencb57d552001-06-28 07:25:16 +00005334/*
5335 * Put a string on the stack.
5336 */
5337
Eric Andersenc470f442003-07-28 09:56:35 +00005338static void
5339memtodest(const char *p, size_t len, int syntax, int quotes) {
5340 char *q = expdest;
5341
5342 q = makestrspace(len * 2, q);
5343
5344 while (len--) {
5345 int c = *p++;
5346 if (!c)
5347 continue;
5348 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5349 USTPUTC(CTLESC, q);
5350 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005351 }
Eric Andersenc470f442003-07-28 09:56:35 +00005352
5353 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005354}
5355
Eric Andersenc470f442003-07-28 09:56:35 +00005356
5357static void
5358strtodest(const char *p, int syntax, int quotes)
5359{
5360 memtodest(p, strlen(p), syntax, quotes);
5361}
5362
5363
5364
Eric Andersencb57d552001-06-28 07:25:16 +00005365/*
5366 * Add the value of a specialized variable to the stack string.
5367 */
5368
Eric Andersenc470f442003-07-28 09:56:35 +00005369static void
5370varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005371{
5372 int num;
5373 char *p;
5374 int i;
5375 int sep;
5376 int sepq = 0;
5377 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005378 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005379 int allow_split = flags & EXP_FULL;
5380 int quotes = flags & (EXP_FULL | EXP_CASE);
5381
5382 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5383 switch (*name) {
5384 case '$':
5385 num = rootpid;
5386 goto numvar;
5387 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005388 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005389 goto numvar;
5390 case '#':
5391 num = shellparam.nparam;
5392 goto numvar;
5393 case '!':
5394 num = backgndpid;
Eric Andersenc470f442003-07-28 09:56:35 +00005395numvar:
5396 cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005397 break;
5398 case '-':
Eric Andersenc470f442003-07-28 09:56:35 +00005399 for (i = 0 ; i < NOPTS ; i++) {
5400 if (optlist[i])
5401 STPUTC(optletters(i), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005402 }
5403 break;
5404 case '@':
5405 if (allow_split && quoted) {
5406 sep = 1 << CHAR_BIT;
5407 goto param;
5408 }
5409 /* fall through */
5410 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005411 sep = ifsset() ? ifsval()[0] : ' ';
Eric Andersencb57d552001-06-28 07:25:16 +00005412 if (quotes) {
Eric Andersenc470f442003-07-28 09:56:35 +00005413 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
Eric Andersencb57d552001-06-28 07:25:16 +00005414 }
Eric Andersenc470f442003-07-28 09:56:35 +00005415param:
5416 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005417 strtodest(p, syntax, quotes);
5418 if (*ap && sep) {
Eric Andersenc470f442003-07-28 09:56:35 +00005419 p = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005420 if (sepq)
Eric Andersenc470f442003-07-28 09:56:35 +00005421 STPUTC(CTLESC, p);
5422 STPUTC(sep, p);
5423 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005424 }
5425 }
5426 break;
5427 case '0':
5428 strtodest(arg0, syntax, quotes);
5429 break;
5430 default:
5431 num = atoi(name);
5432 if (num > 0 && num <= shellparam.nparam) {
5433 strtodest(shellparam.p[num - 1], syntax, quotes);
5434 }
5435 break;
5436 }
5437}
5438
5439
Eric Andersenc470f442003-07-28 09:56:35 +00005440
Eric Andersencb57d552001-06-28 07:25:16 +00005441/*
5442 * Record the fact that we have to scan this region of the
5443 * string for IFS characters.
5444 */
5445
Eric Andersenc470f442003-07-28 09:56:35 +00005446static void
5447recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005448{
5449 struct ifsregion *ifsp;
5450
5451 if (ifslastp == NULL) {
5452 ifsp = &ifsfirst;
5453 } else {
5454 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005455 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005456 ifsp->next = NULL;
5457 ifslastp->next = ifsp;
5458 INTON;
5459 }
5460 ifslastp = ifsp;
5461 ifslastp->begoff = start;
5462 ifslastp->endoff = end;
5463 ifslastp->nulonly = nulonly;
5464}
5465
5466
5467
5468/*
5469 * Break the argument string into pieces based upon IFS and add the
5470 * strings to the argument list. The regions of the string to be
5471 * searched for IFS characters have been stored by recordregion.
5472 */
Eric Andersenc470f442003-07-28 09:56:35 +00005473static void
5474ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005475{
Eric Andersencb57d552001-06-28 07:25:16 +00005476 struct ifsregion *ifsp;
5477 struct strlist *sp;
5478 char *start;
5479 char *p;
5480 char *q;
5481 const char *ifs, *realifs;
5482 int ifsspc;
5483 int nulonly;
5484
5485
5486 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005487 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005488 ifsspc = 0;
5489 nulonly = 0;
5490 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005491 ifsp = &ifsfirst;
5492 do {
5493 p = string + ifsp->begoff;
5494 nulonly = ifsp->nulonly;
5495 ifs = nulonly ? nullstr : realifs;
5496 ifsspc = 0;
5497 while (p < string + ifsp->endoff) {
5498 q = p;
5499 if (*p == CTLESC)
5500 p++;
5501 if (strchr(ifs, *p)) {
5502 if (!nulonly)
5503 ifsspc = (strchr(defifs, *p) != NULL);
5504 /* Ignore IFS whitespace at start */
5505 if (q == start && ifsspc) {
5506 p++;
5507 start = p;
5508 continue;
5509 }
5510 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005511 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005512 sp->text = start;
5513 *arglist->lastp = sp;
5514 arglist->lastp = &sp->next;
5515 p++;
5516 if (!nulonly) {
5517 for (;;) {
5518 if (p >= string + ifsp->endoff) {
5519 break;
5520 }
5521 q = p;
5522 if (*p == CTLESC)
5523 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005524 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005525 p = q;
5526 break;
5527 } else if (strchr(defifs, *p) == NULL) {
5528 if (ifsspc) {
5529 p++;
5530 ifsspc = 0;
5531 } else {
5532 p = q;
5533 break;
5534 }
5535 } else
5536 p++;
5537 }
5538 }
5539 start = p;
5540 } else
5541 p++;
5542 }
5543 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005544 if (nulonly)
5545 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005546 }
5547
Eric Andersenc470f442003-07-28 09:56:35 +00005548 if (!*start)
5549 return;
5550
5551add:
5552 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005553 sp->text = start;
5554 *arglist->lastp = sp;
5555 arglist->lastp = &sp->next;
5556}
5557
Eric Andersenc470f442003-07-28 09:56:35 +00005558static void
5559ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005560{
Eric Andersenc470f442003-07-28 09:56:35 +00005561 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005562
Eric Andersenc470f442003-07-28 09:56:35 +00005563 INTOFF;
5564 p = ifsfirst.next;
5565 do {
5566 struct ifsregion *ifsp;
5567 ifsp = p->next;
5568 ckfree(p);
5569 p = ifsp;
5570 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005571 ifslastp = NULL;
5572 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005573 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005574}
5575
5576
5577
5578/*
5579 * Expand shell metacharacters. At this point, the only control characters
5580 * should be escapes. The results are stored in the list exparg.
5581 */
5582
Eric Andersenc470f442003-07-28 09:56:35 +00005583static void
5584expandmeta(str, flag)
5585 struct strlist *str;
5586 int flag;
Eric Andersencb57d552001-06-28 07:25:16 +00005587{
Eric Andersencb57d552001-06-28 07:25:16 +00005588 /* TODO - EXP_REDIR */
5589
5590 while (str) {
Eric Andersenc470f442003-07-28 09:56:35 +00005591 const char *p;
5592 glob_t pglob;
5593 int i;
5594
Eric Andersencb57d552001-06-28 07:25:16 +00005595 if (fflag)
5596 goto nometa;
Eric Andersencb57d552001-06-28 07:25:16 +00005597 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005598 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5599 i = glob(p, GLOB_NOMAGIC, 0, &pglob);
5600 if (p != str->text)
5601 ckfree(p);
5602 switch (i) {
Eric Andersencb57d552001-06-28 07:25:16 +00005603 case 0:
Eric Andersenc470f442003-07-28 09:56:35 +00005604 if (!(pglob.gl_flags & GLOB_MAGCHAR))
Eric Andersencb57d552001-06-28 07:25:16 +00005605 goto nometa2;
5606 addglob(&pglob);
5607 globfree(&pglob);
5608 INTON;
5609 break;
5610 case GLOB_NOMATCH:
Eric Andersenc470f442003-07-28 09:56:35 +00005611nometa2:
Eric Andersencb57d552001-06-28 07:25:16 +00005612 globfree(&pglob);
5613 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00005614nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005615 *exparg.lastp = str;
5616 rmescapes(str->text);
5617 exparg.lastp = &str->next;
5618 break;
Eric Andersenc470f442003-07-28 09:56:35 +00005619 default: /* GLOB_NOSPACE */
5620 error(bb_msg_memory_exhausted);
Eric Andersencb57d552001-06-28 07:25:16 +00005621 }
5622 str = str->next;
5623 }
5624}
5625
5626
5627/*
5628 * Add the result of glob(3) to the list.
5629 */
5630
Eric Andersenc470f442003-07-28 09:56:35 +00005631static void
5632addglob(pglob)
5633 const glob_t *pglob;
Eric Andersencb57d552001-06-28 07:25:16 +00005634{
5635 char **p = pglob->gl_pathv;
5636
5637 do {
5638 addfname(*p);
5639 } while (*++p);
5640}
5641
5642
Eric Andersencb57d552001-06-28 07:25:16 +00005643/*
Eric Andersenc470f442003-07-28 09:56:35 +00005644 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005645 */
5646
Eric Andersenc470f442003-07-28 09:56:35 +00005647static void
5648addfname(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005649{
Eric Andersencb57d552001-06-28 07:25:16 +00005650 struct strlist *sp;
5651
Eric Andersenc470f442003-07-28 09:56:35 +00005652 sp = (struct strlist *)stalloc(sizeof *sp);
5653 sp->text = sstrdup(name);
5654 *exparg.lastp = sp;
5655 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005656}
5657
5658
Eric Andersencb57d552001-06-28 07:25:16 +00005659/*
5660 * Returns true if the pattern matches the string.
5661 */
5662
Eric Andersenc470f442003-07-28 09:56:35 +00005663static inline int
5664patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005665{
Eric Andersenc470f442003-07-28 09:56:35 +00005666 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005667}
5668
5669
Eric Andersencb57d552001-06-28 07:25:16 +00005670/*
5671 * Remove any CTLESC characters from a string.
5672 */
5673
Eric Andersenc470f442003-07-28 09:56:35 +00005674static char *
5675_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005676{
5677 char *p, *q, *r;
5678 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005679 unsigned inquotes;
5680 int notescaped;
5681 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005682
5683 p = strpbrk(str, qchars);
5684 if (!p) {
5685 return str;
5686 }
5687 q = p;
5688 r = str;
5689 if (flag & RMESCAPE_ALLOC) {
5690 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005691 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005692
Eric Andersenc470f442003-07-28 09:56:35 +00005693 if (flag & RMESCAPE_GROW) {
5694 r = makestrspace(fulllen, expdest);
5695 } else if (flag & RMESCAPE_HEAP) {
5696 r = ckmalloc(fulllen);
5697 } else {
5698 r = stalloc(fulllen);
5699 }
5700 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005701 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005702 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005703 }
5704 }
Eric Andersenc470f442003-07-28 09:56:35 +00005705 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5706 globbing = flag & RMESCAPE_GLOB;
5707 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005708 while (*p) {
5709 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005710 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005711 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005712 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005713 continue;
5714 }
Eric Andersenc470f442003-07-28 09:56:35 +00005715 if (*p == '\\') {
5716 /* naked back slash */
5717 notescaped = 0;
5718 goto copy;
5719 }
Eric Andersencb57d552001-06-28 07:25:16 +00005720 if (*p == CTLESC) {
5721 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005722 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005723 *q++ = '\\';
5724 }
5725 }
Eric Andersenc470f442003-07-28 09:56:35 +00005726 notescaped = globbing;
5727copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005728 *q++ = *p++;
5729 }
5730 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005731 if (flag & RMESCAPE_GROW) {
5732 expdest = r;
5733 STADJUST(q - r + 1, expdest);
5734 }
Eric Andersencb57d552001-06-28 07:25:16 +00005735 return r;
5736}
Eric Andersencb57d552001-06-28 07:25:16 +00005737
5738
5739
5740/*
5741 * See if a pattern matches in a case statement.
5742 */
5743
Eric Andersenc470f442003-07-28 09:56:35 +00005744int
5745casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005746{
Eric Andersencb57d552001-06-28 07:25:16 +00005747 struct stackmark smark;
5748 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005749
5750 setstackmark(&smark);
5751 argbackq = pattern->narg.backquote;
5752 STARTSTACKSTR(expdest);
5753 ifslastp = NULL;
5754 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005755 STACKSTRNUL(expdest);
5756 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005757 popstackmark(&smark);
5758 return result;
5759}
5760
5761/*
5762 * Our own itoa().
5763 */
5764
Eric Andersenc470f442003-07-28 09:56:35 +00005765static int
5766cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005767{
Eric Andersencb57d552001-06-28 07:25:16 +00005768 int len;
5769
Eric Andersenc470f442003-07-28 09:56:35 +00005770 expdest = makestrspace(32, expdest);
5771 len = fmtstr(expdest, 32, "%ld", num);
5772 STADJUST(len, expdest);
5773 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005774}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005775
Eric Andersenc470f442003-07-28 09:56:35 +00005776static void
5777varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005778{
Eric Andersenc470f442003-07-28 09:56:35 +00005779 const char *msg;
5780 const char *tail;
5781
5782 tail = nullstr;
5783 msg = "parameter not set";
5784 if (umsg) {
5785 if (*end == CTLENDVAR) {
5786 if (varflags & VSNUL)
5787 tail = " or null";
5788 } else
5789 msg = umsg;
5790 }
5791 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005792}
Eric Andersenc470f442003-07-28 09:56:35 +00005793/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005794
5795
5796
5797/*
Eric Andersencb57d552001-06-28 07:25:16 +00005798 * This file implements the input routines used by the parser.
5799 */
5800
Eric Andersenc470f442003-07-28 09:56:35 +00005801#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5802#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005803
Eric Andersenc470f442003-07-28 09:56:35 +00005804static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005805
Eric Andersencb57d552001-06-28 07:25:16 +00005806/*
5807 * Read a line from the script.
5808 */
5809
Eric Andersenc470f442003-07-28 09:56:35 +00005810static inline char *
5811pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005812{
5813 char *p = line;
5814 int nleft = len;
5815 int c;
5816
5817 while (--nleft > 0) {
5818 c = pgetc2();
5819 if (c == PEOF) {
5820 if (p == line)
5821 return NULL;
5822 break;
5823 }
5824 *p++ = c;
5825 if (c == '\n')
5826 break;
5827 }
5828 *p = '\0';
5829 return line;
5830}
5831
Eric Andersenc470f442003-07-28 09:56:35 +00005832
5833/*
5834 * Read a character from the script, returning PEOF on end of file.
5835 * Nul characters in the input are silently discarded.
5836 */
5837
5838#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5839
5840#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5841#define pgetc_macro() pgetc()
5842static int
5843pgetc(void)
5844{
5845 return pgetc_as_macro();
5846}
5847#else
5848#define pgetc_macro() pgetc_as_macro()
5849static int
5850pgetc(void)
5851{
5852 return pgetc_macro();
5853}
5854#endif
5855
5856
5857/*
5858 * Same as pgetc(), but ignores PEOA.
5859 */
5860#ifdef CONFIG_ASH_ALIAS
5861static int pgetc2(void)
5862{
5863 int c;
5864
5865 do {
5866 c = pgetc_macro();
5867 } while (c == PEOA);
5868 return c;
5869}
5870#else
5871static inline int pgetc2(void)
5872{
5873 return pgetc_macro();
5874}
5875#endif
5876
5877
5878#ifdef CONFIG_FEATURE_COMMAND_EDITING
5879static const char *cmdedit_prompt;
5880static inline void putprompt(const char *s)
5881{
5882 cmdedit_prompt = s;
5883}
5884#else
5885static inline void putprompt(const char *s)
5886{
5887 out2str(s);
5888}
5889#endif
5890
5891static inline int
5892preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005893{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005894 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00005895 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005896 parsenextc = buf;
5897
Eric Andersenc470f442003-07-28 09:56:35 +00005898retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005899#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00005900 if (!iflag || parsefile->fd)
5901 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5902 else {
5903 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5904 if(nr == 0) {
5905 /* Ctrl+C presend */
5906 raise(SIGINT);
5907 goto retry;
5908 }
5909 if(nr < 0) {
5910 /* Ctrl+D presend */
5911 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005912 }
Eric Andersencb57d552001-06-28 07:25:16 +00005913 }
5914#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00005915 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00005916#endif
5917
5918 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00005919 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5920 int flags = fcntl(0, F_GETFL, 0);
5921 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005922 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00005923 if (fcntl(0, F_SETFL, flags) >= 0) {
5924 out2str("sh: turning off NDELAY mode\n");
5925 goto retry;
5926 }
5927 }
5928 }
5929 }
5930 return nr;
5931}
5932
5933/*
5934 * Refill the input buffer and return the next input character:
5935 *
5936 * 1) If a string was pushed back on the input, pop it;
5937 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5938 * from a string so we can't refill the buffer, return EOF.
5939 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5940 * 4) Process input up to the next newline, deleting nul characters.
5941 */
5942
Eric Andersenc470f442003-07-28 09:56:35 +00005943int
5944preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005945{
5946 char *p, *q;
5947 int more;
5948 char savec;
5949
5950 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00005951#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00005952 if (parsenleft == -1 && parsefile->strpush->ap &&
5953 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00005954 return PEOA;
5955 }
Eric Andersen2870d962001-07-02 17:27:21 +00005956#endif
Eric Andersencb57d552001-06-28 07:25:16 +00005957 popstring();
5958 if (--parsenleft >= 0)
5959 return (*parsenextc++);
5960 }
5961 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5962 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00005963 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00005964
Eric Andersenc470f442003-07-28 09:56:35 +00005965again:
Eric Andersencb57d552001-06-28 07:25:16 +00005966 if (parselleft <= 0) {
5967 if ((parselleft = preadfd()) <= 0) {
5968 parselleft = parsenleft = EOF_NLEFT;
5969 return PEOF;
5970 }
5971 }
5972
5973 q = p = parsenextc;
5974
5975 /* delete nul characters */
5976 for (more = 1; more;) {
5977 switch (*p) {
5978 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00005979 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00005980 goto check;
5981
Eric Andersencb57d552001-06-28 07:25:16 +00005982 case '\n':
5983 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00005984 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00005985 break;
Eric Andersenc470f442003-07-28 09:56:35 +00005986
Eric Andersencb57d552001-06-28 07:25:16 +00005987 }
5988
5989 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005990check:
Eric Andersencb57d552001-06-28 07:25:16 +00005991 if (--parselleft <= 0 && more) {
5992 parsenleft = q - parsenextc - 1;
5993 if (parsenleft < 0)
5994 goto again;
5995 more = 0;
5996 }
5997 }
5998
5999 savec = *q;
6000 *q = '\0';
6001
6002 if (vflag) {
6003 out2str(parsenextc);
Eric Andersenc470f442003-07-28 09:56:35 +00006004 flushout(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00006005 }
6006
6007 *q = savec;
6008
6009 return *parsenextc++;
6010}
6011
Eric Andersenc470f442003-07-28 09:56:35 +00006012/*
6013 * Undo the last call to pgetc. Only one character may be pushed back.
6014 * PEOF may be pushed back.
6015 */
6016
6017void
6018pungetc(void)
6019{
6020 parsenleft++;
6021 parsenextc--;
6022}
Eric Andersencb57d552001-06-28 07:25:16 +00006023
6024/*
6025 * Push a string back onto the input at this current parsefile level.
6026 * We handle aliases this way.
6027 */
Eric Andersenc470f442003-07-28 09:56:35 +00006028void
6029pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006030{
Eric Andersencb57d552001-06-28 07:25:16 +00006031 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006032 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006033
Eric Andersenc470f442003-07-28 09:56:35 +00006034 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006035 INTOFF;
6036/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6037 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006038 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006039 sp->prev = parsefile->strpush;
6040 parsefile->strpush = sp;
6041 } else
6042 sp = parsefile->strpush = &(parsefile->basestrpush);
6043 sp->prevstring = parsenextc;
6044 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006045#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006046 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006047 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006048 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006049 sp->string = s;
6050 }
Eric Andersen2870d962001-07-02 17:27:21 +00006051#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006052 parsenextc = s;
6053 parsenleft = len;
6054 INTON;
6055}
6056
Eric Andersenc470f442003-07-28 09:56:35 +00006057void
6058popstring(void)
6059{
6060 struct strpush *sp = parsefile->strpush;
6061
6062 INTOFF;
6063#ifdef CONFIG_ASH_ALIAS
6064 if (sp->ap) {
6065 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6066 checkkwd |= CHKALIAS;
6067 }
6068 if (sp->string != sp->ap->val) {
6069 ckfree(sp->string);
6070 }
6071 sp->ap->flag &= ~ALIASINUSE;
6072 if (sp->ap->flag & ALIASDEAD) {
6073 unalias(sp->ap->name);
6074 }
6075 }
6076#endif
6077 parsenextc = sp->prevstring;
6078 parsenleft = sp->prevnleft;
6079/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6080 parsefile->strpush = sp->prev;
6081 if (sp != &(parsefile->basestrpush))
6082 ckfree(sp);
6083 INTON;
6084}
6085
6086/*
6087 * Set the input to take input from a file. If push is set, push the
6088 * old input onto the stack first.
6089 */
6090
6091void
6092setinputfile(const char *fname, int push)
6093{
6094 int fd;
6095 int fd2;
6096
6097 INTOFF;
6098 if ((fd = open(fname, O_RDONLY)) < 0)
6099 error("Can't open %s", fname);
6100 if (fd < 10) {
6101 fd2 = copyfd(fd, 10);
6102 close(fd);
6103 if (fd2 < 0)
6104 error("Out of file descriptors");
6105 fd = fd2;
6106 }
6107 setinputfd(fd, push);
6108 INTON;
6109}
6110
6111
6112/*
6113 * Like setinputfile, but takes an open file descriptor. Call this with
6114 * interrupts off.
6115 */
6116
6117static void
6118setinputfd(int fd, int push)
6119{
6120 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6121 if (push) {
6122 pushfile();
6123 parsefile->buf = 0;
6124 }
6125 parsefile->fd = fd;
6126 if (parsefile->buf == NULL)
6127 parsefile->buf = ckmalloc(IBUFSIZ);
6128 parselleft = parsenleft = 0;
6129 plinno = 1;
6130}
6131
Eric Andersencb57d552001-06-28 07:25:16 +00006132
Eric Andersencb57d552001-06-28 07:25:16 +00006133/*
6134 * Like setinputfile, but takes input from a string.
6135 */
6136
Eric Andersenc470f442003-07-28 09:56:35 +00006137static void
6138setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006139{
Eric Andersencb57d552001-06-28 07:25:16 +00006140 INTOFF;
6141 pushfile();
6142 parsenextc = string;
6143 parsenleft = strlen(string);
6144 parsefile->buf = NULL;
6145 plinno = 1;
6146 INTON;
6147}
6148
6149
6150
6151/*
6152 * To handle the "." command, a stack of input files is used. Pushfile
6153 * adds a new entry to the stack and popfile restores the previous level.
6154 */
6155
Eric Andersenc470f442003-07-28 09:56:35 +00006156static void
6157pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006158{
Eric Andersencb57d552001-06-28 07:25:16 +00006159 struct parsefile *pf;
6160
6161 parsefile->nleft = parsenleft;
6162 parsefile->lleft = parselleft;
6163 parsefile->nextc = parsenextc;
6164 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006165 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006166 pf->prev = parsefile;
6167 pf->fd = -1;
6168 pf->strpush = NULL;
6169 pf->basestrpush.prev = NULL;
6170 parsefile = pf;
6171}
6172
Eric Andersenc470f442003-07-28 09:56:35 +00006173
6174static void
6175popfile(void)
6176{
6177 struct parsefile *pf = parsefile;
6178
6179 INTOFF;
6180 if (pf->fd >= 0)
6181 close(pf->fd);
6182 if (pf->buf)
6183 ckfree(pf->buf);
6184 while (pf->strpush)
6185 popstring();
6186 parsefile = pf->prev;
6187 ckfree(pf);
6188 parsenleft = parsefile->nleft;
6189 parselleft = parsefile->lleft;
6190 parsenextc = parsefile->nextc;
6191 plinno = parsefile->linno;
6192 INTON;
6193}
Eric Andersencb57d552001-06-28 07:25:16 +00006194
6195
Eric Andersen2870d962001-07-02 17:27:21 +00006196/*
Eric Andersenc470f442003-07-28 09:56:35 +00006197 * Return to top level.
6198 */
Eric Andersen2870d962001-07-02 17:27:21 +00006199
Eric Andersenc470f442003-07-28 09:56:35 +00006200static void
6201popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006202{
Eric Andersenc470f442003-07-28 09:56:35 +00006203 while (parsefile != &basepf)
6204 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006205}
6206
Eric Andersen2870d962001-07-02 17:27:21 +00006207
Eric Andersenc470f442003-07-28 09:56:35 +00006208
6209/*
6210 * Close the file(s) that the shell is reading commands from. Called
6211 * after a fork is done.
6212 */
6213
6214static void
6215closescript(void)
6216{
6217 popallfiles();
6218 if (parsefile->fd > 0) {
6219 close(parsefile->fd);
6220 parsefile->fd = 0;
6221 }
6222}
6223/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6224
6225
6226/* mode flags for set_curjob */
6227#define CUR_DELETE 2
6228#define CUR_RUNNING 1
6229#define CUR_STOPPED 0
6230
6231/* mode flags for dowait */
6232#define DOWAIT_NORMAL 0
6233#define DOWAIT_BLOCK 1
6234
6235/* array of jobs */
6236static struct job *jobtab;
6237/* size of array */
6238static unsigned njobs;
6239#if JOBS
6240/* pgrp of shell on invocation */
6241static int initialpgrp;
6242static int ttyfd = -1;
6243#endif
6244/* current job */
6245static struct job *curjob;
6246/* number of presumed living untracked jobs */
6247static int jobless;
6248
6249static void set_curjob(struct job *, unsigned);
6250#if JOBS
6251static int restartjob(struct job *, int);
6252static void xtcsetpgrp(int, pid_t);
6253static char *commandtext(union node *);
6254static void cmdlist(union node *, int);
6255static void cmdtxt(union node *);
6256static void cmdputs(const char *);
6257static void showpipe(struct job *, FILE *);
6258#endif
6259static int sprint_status(char *, int, int);
6260static void freejob(struct job *);
6261static struct job *getjob(const char *, int);
6262static struct job *growjobtab(void);
6263static void forkchild(struct job *, union node *, int);
6264static void forkparent(struct job *, union node *, int, pid_t);
6265static int dowait(int, struct job *);
6266static int getstatus(struct job *);
6267
6268static void
6269set_curjob(struct job *jp, unsigned mode)
6270{
6271 struct job *jp1;
6272 struct job **jpp, **curp;
6273
6274 /* first remove from list */
6275 jpp = curp = &curjob;
6276 do {
6277 jp1 = *jpp;
6278 if (jp1 == jp)
6279 break;
6280 jpp = &jp1->prev_job;
6281 } while (1);
6282 *jpp = jp1->prev_job;
6283
6284 /* Then re-insert in correct position */
6285 jpp = curp;
6286 switch (mode) {
6287 default:
6288#ifdef DEBUG
6289 abort();
6290#endif
6291 case CUR_DELETE:
6292 /* job being deleted */
6293 break;
6294 case CUR_RUNNING:
6295 /* newly created job or backgrounded job,
6296 put after all stopped jobs. */
6297 do {
6298 jp1 = *jpp;
6299#ifdef JOBS
6300 if (!jp1 || jp1->state != JOBSTOPPED)
6301#endif
6302 break;
6303 jpp = &jp1->prev_job;
6304 } while (1);
6305 /* FALLTHROUGH */
6306#ifdef JOBS
6307 case CUR_STOPPED:
6308#endif
6309 /* newly stopped job - becomes curjob */
6310 jp->prev_job = *jpp;
6311 *jpp = jp;
6312 break;
6313 }
6314}
6315
6316#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006317/*
6318 * Turn job control on and off.
6319 *
6320 * Note: This code assumes that the third arg to ioctl is a character
6321 * pointer, which is true on Berkeley systems but not System V. Since
6322 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006323 *
6324 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006325 */
6326
Eric Andersenc470f442003-07-28 09:56:35 +00006327void
6328setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006329{
Eric Andersenc470f442003-07-28 09:56:35 +00006330 int fd;
6331 int pgrp;
6332
6333 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006334 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006335 if (on) {
6336 int ofd;
6337 ofd = fd = open(_PATH_TTY, O_RDWR);
6338 if (fd < 0) {
6339 fd += 3;
6340 while (!isatty(fd) && --fd >= 0)
6341 ;
6342 }
6343 fd = fcntl(fd, F_DUPFD, 10);
6344 close(ofd);
6345 if (fd < 0)
6346 goto out;
6347 fcntl(fd, F_SETFD, FD_CLOEXEC);
6348 do { /* while we are in the background */
6349 if ((pgrp = tcgetpgrp(fd)) < 0) {
6350out:
6351 sh_warnx("can't access tty; job control turned off");
6352 mflag = on = 0;
6353 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006354 }
Eric Andersenc470f442003-07-28 09:56:35 +00006355 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006356 break;
6357 killpg(0, SIGTTIN);
6358 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006359 initialpgrp = pgrp;
6360
Eric Andersencb57d552001-06-28 07:25:16 +00006361 setsignal(SIGTSTP);
6362 setsignal(SIGTTOU);
6363 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006364 pgrp = rootpid;
6365 setpgid(0, pgrp);
6366 xtcsetpgrp(fd, pgrp);
6367 } else {
6368 /* turning job control off */
6369 fd = ttyfd;
6370 pgrp = initialpgrp;
6371 xtcsetpgrp(fd, pgrp);
6372 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006373 setsignal(SIGTSTP);
6374 setsignal(SIGTTOU);
6375 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006376close:
6377 close(fd);
6378 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006379 }
Eric Andersenc470f442003-07-28 09:56:35 +00006380 ttyfd = fd;
6381 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006382}
Eric Andersencb57d552001-06-28 07:25:16 +00006383
Eric Andersenc470f442003-07-28 09:56:35 +00006384static int
6385killcmd(argc, argv)
6386 int argc;
6387 char **argv;
Eric Andersencb57d552001-06-28 07:25:16 +00006388{
6389 int signo = -1;
6390 int list = 0;
6391 int i;
6392 pid_t pid;
6393 struct job *jp;
6394
6395 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006396usage:
6397 error(
6398"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6399"kill -l [exitstatus]"
6400 );
Eric Andersencb57d552001-06-28 07:25:16 +00006401 }
6402
Eric Andersenc470f442003-07-28 09:56:35 +00006403 if (**++argv == '-') {
6404 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006405 if (signo < 0) {
6406 int c;
6407
6408 while ((c = nextopt("ls:")) != '\0')
6409 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006410 default:
6411#ifdef DEBUG
6412 abort();
6413#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006414 case 'l':
6415 list = 1;
6416 break;
6417 case 's':
6418 signo = decode_signal(optionarg, 1);
6419 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006420 error(
6421 "invalid signal number or name: %s",
6422 optionarg
6423 );
Eric Andersencb57d552001-06-28 07:25:16 +00006424 }
Eric Andersen2870d962001-07-02 17:27:21 +00006425 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006426 }
Eric Andersenc470f442003-07-28 09:56:35 +00006427 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006428 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006429 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006430 }
6431
6432 if (!list && signo < 0)
6433 signo = SIGTERM;
6434
Eric Andersenc470f442003-07-28 09:56:35 +00006435 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006436 goto usage;
6437 }
6438
6439 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006440 const char *name;
6441
Eric Andersenc470f442003-07-28 09:56:35 +00006442 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006443 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006444 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006445 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006446 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006447 }
6448 return 0;
6449 }
Eric Andersen34506362001-08-02 05:02:46 +00006450 name = u_signal_names(*argptr, &signo, -1);
6451 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006452 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006453 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006454 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006455 return 0;
6456 }
6457
Eric Andersenc470f442003-07-28 09:56:35 +00006458 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006459 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006460 if (**argv == '%') {
6461 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006462 pid = -jp->ps[0].pid;
6463 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006464 pid = number(*argv);
6465 if (kill(pid, signo) != 0) {
6466 sh_warnx("%m\n");
6467 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006468 }
Eric Andersenc470f442003-07-28 09:56:35 +00006469 } while (*++argv);
6470
6471 return i;
6472}
6473#endif /* JOBS */
6474
6475#if defined(JOBS) || defined(DEBUG)
6476static int
6477jobno(const struct job *jp)
6478{
6479 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006480}
6481#endif
6482
Eric Andersenc470f442003-07-28 09:56:35 +00006483#ifdef JOBS
6484static int
6485fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006486{
Eric Andersenc470f442003-07-28 09:56:35 +00006487 struct job *jp;
6488 FILE *out;
6489 int mode;
6490 int retval;
6491
6492 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6493 nextopt(nullstr);
6494 argv = argptr;
6495 out = stdout;
6496 do {
6497 jp = getjob(*argv, 1);
6498 if (mode == FORK_BG) {
6499 set_curjob(jp, CUR_RUNNING);
6500 fprintf(out, "[%d] ", jobno(jp));
6501 }
6502 outstr(jp->ps->cmd, out);
6503 showpipe(jp, out);
6504 retval = restartjob(jp, mode);
6505 } while (*argv && *++argv);
6506 return retval;
6507}
6508
6509static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6510
6511
6512static int
6513restartjob(struct job *jp, int mode)
6514{
6515 struct procstat *ps;
6516 int i;
6517 int status;
6518 pid_t pgid;
6519
6520 INTOFF;
6521 if (jp->state == JOBDONE)
6522 goto out;
6523 jp->state = JOBRUNNING;
6524 pgid = jp->ps->pid;
6525 if (mode == FORK_FG)
6526 xtcsetpgrp(ttyfd, pgid);
6527 killpg(pgid, SIGCONT);
6528 ps = jp->ps;
6529 i = jp->nprocs;
6530 do {
6531 if (WIFSTOPPED(ps->status)) {
6532 ps->status = -1;
6533 }
6534 } while (ps++, --i);
6535out:
6536 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6537 INTON;
6538 return status;
6539}
6540#endif
6541
6542static int
6543sprint_status(char *s, int status, int sigonly)
6544{
6545 int col;
6546 int st;
6547
6548 col = 0;
6549 st = WEXITSTATUS(status);
6550 if (!WIFEXITED(status)) {
6551 st = WSTOPSIG(status);
6552#if JOBS
6553 if (!WIFSTOPPED(status))
6554 st = WTERMSIG(status);
6555#endif
6556 if (sigonly) {
6557 if (st == SIGINT || st == SIGPIPE)
6558 goto out;
6559 if (WIFSTOPPED(status))
6560 goto out;
6561 }
6562 st &= 0x7f;
6563 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6564 if (WCOREDUMP(status)) {
6565 col += fmtstr(s + col, 16, " (core dumped)");
6566 }
6567 } else if (!sigonly) {
6568 if (st)
6569 col = fmtstr(s, 16, "Done(%d)", st);
6570 else
6571 col = fmtstr(s, 16, "Done");
6572 }
6573
6574out:
6575 return col;
6576}
6577
6578#if JOBS
6579static void
6580showjob(FILE *out, struct job *jp, int mode)
6581{
6582 struct procstat *ps;
6583 struct procstat *psend;
6584 int col;
6585 int indent;
6586 char s[80];
6587
6588 ps = jp->ps;
6589
6590 if (mode & SHOW_PGID) {
6591 /* just output process (group) id of pipeline */
6592 fprintf(out, "%d\n", ps->pid);
6593 return;
6594 }
6595
6596 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6597 indent = col;
6598
6599 if (jp == curjob)
6600 s[col - 2] = '+';
6601 else if (curjob && jp == curjob->prev_job)
6602 s[col - 2] = '-';
6603
6604 if (mode & SHOW_PID)
6605 col += fmtstr(s + col, 16, "%d ", ps->pid);
6606
6607 psend = ps + jp->nprocs;
6608
6609 if (jp->state == JOBRUNNING) {
6610 scopy("Running", s + col);
6611 col += strlen("Running");
6612 } else {
6613 int status = psend[-1].status;
6614#if JOBS
6615 if (jp->state == JOBSTOPPED)
6616 status = jp->stopstatus;
6617#endif
6618 col += sprint_status(s + col, status, 0);
6619 }
6620
6621 goto start;
6622
6623 do {
6624 /* for each process */
6625 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6626
6627start:
6628 fprintf(
6629 out, "%s%*c%s",
6630 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6631 );
6632 if (!(mode & SHOW_PID)) {
6633 showpipe(jp, out);
6634 break;
6635 }
6636 if (++ps == psend) {
6637 outcslow('\n', out);
6638 break;
6639 }
6640 } while (1);
6641
6642 jp->changed = 0;
6643
6644 if (jp->state == JOBDONE) {
6645 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6646 freejob(jp);
6647 }
6648}
6649
6650
6651static int
6652jobscmd(int argc, char **argv)
6653{
6654 int mode, m;
6655 FILE *out;
6656
6657 mode = 0;
6658 while ((m = nextopt("lp")))
6659 if (m == 'l')
6660 mode = SHOW_PID;
6661 else
6662 mode = SHOW_PGID;
6663
6664 out = stdout;
6665 argv = argptr;
6666 if (*argv)
6667 do
6668 showjob(out, getjob(*argv,0), mode);
6669 while (*++argv);
6670 else
6671 showjobs(out, mode);
6672
Eric Andersencb57d552001-06-28 07:25:16 +00006673 return 0;
6674}
6675
6676
6677/*
6678 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6679 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006680 */
6681
Eric Andersenc470f442003-07-28 09:56:35 +00006682static void
6683showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006684{
Eric Andersencb57d552001-06-28 07:25:16 +00006685 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006686
Eric Andersenc470f442003-07-28 09:56:35 +00006687 TRACE(("showjobs(%x) called\n", mode));
6688
6689 /* If not even one one job changed, there is nothing to do */
6690 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6691 continue;
6692
6693 for (jp = curjob; jp; jp = jp->prev_job) {
6694 if (!(mode & SHOW_CHANGED) || jp->changed)
6695 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006696 }
6697}
Eric Andersenc470f442003-07-28 09:56:35 +00006698#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006699
6700/*
6701 * Mark a job structure as unused.
6702 */
6703
Eric Andersenc470f442003-07-28 09:56:35 +00006704static void
6705freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006706{
Eric Andersenc470f442003-07-28 09:56:35 +00006707 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006708 int i;
6709
6710 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006711 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006712 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006713 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006714 }
6715 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006716 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006717 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006718 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006719 INTON;
6720}
6721
6722
Eric Andersenc470f442003-07-28 09:56:35 +00006723static int
6724waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006725{
6726 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006727 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006728 struct job *jp;
6729
Eric Andersenc470f442003-07-28 09:56:35 +00006730 EXSIGON();
6731
6732 nextopt(nullstr);
6733 retval = 0;
6734
6735 argv = argptr;
6736 if (!*argv) {
6737 /* wait for all jobs */
6738 for (;;) {
6739 jp = curjob;
6740 while (1) {
6741 if (!jp) {
6742 /* no running procs */
6743 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006744 }
Eric Andersenc470f442003-07-28 09:56:35 +00006745 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006746 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006747 jp->waited = 1;
6748 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006749 }
Eric Andersenc470f442003-07-28 09:56:35 +00006750 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006751 }
6752 }
Eric Andersenc470f442003-07-28 09:56:35 +00006753
6754 retval = 127;
6755 do {
6756 if (**argv != '%') {
6757 pid_t pid = number(*argv);
6758 job = curjob;
6759 goto start;
6760 do {
6761 if (job->ps[job->nprocs - 1].pid == pid)
6762 break;
6763 job = job->prev_job;
6764start:
6765 if (!job)
6766 goto repeat;
6767 } while (1);
6768 } else
6769 job = getjob(*argv, 0);
6770 /* loop until process terminated or stopped */
6771 while (job->state == JOBRUNNING)
6772 dowait(DOWAIT_BLOCK, 0);
6773 job->waited = 1;
6774 retval = getstatus(job);
6775repeat:
6776 ;
6777 } while (*++argv);
6778
6779out:
6780 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006781}
6782
6783
6784
6785/*
6786 * Convert a job name to a job structure.
6787 */
6788
Eric Andersenc470f442003-07-28 09:56:35 +00006789static struct job *
6790getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006791{
Eric Andersencb57d552001-06-28 07:25:16 +00006792 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006793 struct job *found;
6794 const char *err_msg = "No such job: %s";
6795 unsigned num;
6796 int c;
6797 const char *p;
6798 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006799
Eric Andersenc470f442003-07-28 09:56:35 +00006800 jp = curjob;
6801 p = name;
6802 if (!p)
6803 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006804
Eric Andersenc470f442003-07-28 09:56:35 +00006805 if (*p != '%')
6806 goto err;
6807
6808 c = *++p;
6809 if (!c)
6810 goto currentjob;
6811
6812 if (!p[1]) {
6813 if (c == '+' || c == '%') {
6814currentjob:
6815 err_msg = "No current job";
6816 goto check;
6817 } else if (c == '-') {
6818 if (jp)
6819 jp = jp->prev_job;
6820 err_msg = "No previous job";
6821check:
6822 if (!jp)
6823 goto err;
6824 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006825 }
6826 }
Eric Andersenc470f442003-07-28 09:56:35 +00006827
6828 if (is_number(p)) {
6829 num = atoi(p);
6830 if (num < njobs) {
6831 jp = jobtab + num - 1;
6832 if (jp->used)
6833 goto gotit;
6834 goto err;
6835 }
6836 }
6837
6838 match = prefix;
6839 if (*p == '?') {
6840 match = strstr;
6841 p++;
6842 }
6843
6844 found = 0;
6845 while (1) {
6846 if (!jp)
6847 goto err;
6848 if (match(jp->ps[0].cmd, p)) {
6849 if (found)
6850 goto err;
6851 found = jp;
6852 err_msg = "%s: ambiguous";
6853 }
6854 jp = jp->prev_job;
6855 }
6856
6857gotit:
6858#if JOBS
6859 err_msg = "job %s not created under job control";
6860 if (getctl && jp->jobctl == 0)
6861 goto err;
6862#endif
6863 return jp;
6864err:
6865 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006866}
6867
6868
6869
6870/*
Eric Andersenc470f442003-07-28 09:56:35 +00006871 * Return a new job structure.
6872 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006873 */
6874
Eric Andersenc470f442003-07-28 09:56:35 +00006875static struct job *
6876makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00006877{
6878 int i;
6879 struct job *jp;
6880
Eric Andersenc470f442003-07-28 09:56:35 +00006881 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006882 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006883 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00006884 break;
6885 }
6886 if (jp->used == 0)
6887 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006888 if (jp->state != JOBDONE || !jp->waited)
6889 continue;
6890#if JOBS
6891 if (jobctl)
6892 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00006893#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006894 freejob(jp);
6895 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006896 }
Eric Andersenc470f442003-07-28 09:56:35 +00006897 memset(jp, 0, sizeof(*jp));
6898#if JOBS
6899 if (jobctl)
6900 jp->jobctl = 1;
6901#endif
6902 jp->prev_job = curjob;
6903 curjob = jp;
6904 jp->used = 1;
6905 jp->ps = &jp->ps0;
6906 if (nprocs > 1) {
6907 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6908 }
6909 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6910 jobno(jp)));
6911 return jp;
6912}
6913
6914static struct job *
6915growjobtab(void)
6916{
6917 size_t len;
6918 ptrdiff_t offset;
6919 struct job *jp, *jq;
6920
6921 len = njobs * sizeof(*jp);
6922 jq = jobtab;
6923 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
6924
6925 offset = (char *)jp - (char *)jq;
6926 if (offset) {
6927 /* Relocate pointers */
6928 size_t l = len;
6929
6930 jq = (struct job *)((char *)jq + l);
6931 while (l) {
6932 l -= sizeof(*jp);
6933 jq--;
6934#define joff(p) ((struct job *)((char *)(p) + l))
6935#define jmove(p) (p) = (void *)((char *)(p) + offset)
6936 if (likely(joff(jp)->ps == &jq->ps0))
6937 jmove(joff(jp)->ps);
6938 if (joff(jp)->prev_job)
6939 jmove(joff(jp)->prev_job);
6940 }
6941 if (curjob)
6942 jmove(curjob);
6943#undef joff
6944#undef jmove
6945 }
6946
6947 njobs += 4;
6948 jobtab = jp;
6949 jp = (struct job *)((char *)jp + len);
6950 jq = jp + 3;
6951 do {
6952 jq->used = 0;
6953 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00006954 return jp;
6955}
6956
6957
6958/*
Eric Andersenc470f442003-07-28 09:56:35 +00006959 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00006960 * own process group. Jp is a job structure that the job is to be added to.
6961 * N is the command that will be evaluated by the child. Both jp and n may
6962 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00006963 * FORK_FG - Fork off a foreground process.
6964 * FORK_BG - Fork off a background process.
6965 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6966 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00006967 *
6968 * When job control is turned off, background processes have their standard
6969 * input redirected to /dev/null (except for the second and later processes
6970 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00006971 *
6972 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006973 */
6974
Eric Andersenc470f442003-07-28 09:56:35 +00006975static inline void
6976forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006977{
Eric Andersenc470f442003-07-28 09:56:35 +00006978 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006979
Eric Andersenc470f442003-07-28 09:56:35 +00006980 TRACE(("Child shell %d\n", getpid()));
6981 wasroot = rootshell;
6982 rootshell = 0;
6983
6984 closescript();
6985 clear_traps();
6986#if JOBS
6987 /* do job control only in root shell */
6988 jobctl = 0;
6989 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
6990 pid_t pgrp;
6991
6992 if (jp->nprocs == 0)
6993 pgrp = getpid();
6994 else
6995 pgrp = jp->ps[0].pid;
6996 /* This can fail because we are doing it in the parent also */
6997 (void)setpgid(0, pgrp);
6998 if (mode == FORK_FG)
6999 xtcsetpgrp(ttyfd, pgrp);
7000 setsignal(SIGTSTP);
7001 setsignal(SIGTTOU);
7002 } else
Eric Andersen62483552001-07-10 06:09:16 +00007003#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007004 if (mode == FORK_BG) {
7005 ignoresig(SIGINT);
7006 ignoresig(SIGQUIT);
7007 if (jp->nprocs == 0) {
7008 close(0);
7009 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7010 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007011 }
Eric Andersencb57d552001-06-28 07:25:16 +00007012 }
Eric Andersenc470f442003-07-28 09:56:35 +00007013 if (wasroot && iflag) {
7014 setsignal(SIGINT);
7015 setsignal(SIGQUIT);
7016 setsignal(SIGTERM);
7017 }
7018 for (jp = curjob; jp; jp = jp->prev_job)
7019 freejob(jp);
7020 jobless = 0;
7021}
7022
7023static inline void
7024forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7025{
7026 TRACE(("In parent shell: child = %d\n", pid));
7027 if (!jp) {
7028 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7029 jobless++;
7030 return;
7031 }
7032#if JOBS
7033 if (mode != FORK_NOJOB && jp->jobctl) {
7034 int pgrp;
7035
7036 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007037 pgrp = pid;
7038 else
7039 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007040 /* This can fail because we are doing it in the child also */
7041 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007042 }
Eric Andersen62483552001-07-10 06:09:16 +00007043#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007044 if (mode == FORK_BG) {
7045 backgndpid = pid; /* set $! */
7046 set_curjob(jp, CUR_RUNNING);
7047 }
Eric Andersencb57d552001-06-28 07:25:16 +00007048 if (jp) {
7049 struct procstat *ps = &jp->ps[jp->nprocs++];
7050 ps->pid = pid;
7051 ps->status = -1;
7052 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007053#if JOBS
7054 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007055 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007056#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007057 }
Eric Andersencb57d552001-06-28 07:25:16 +00007058}
7059
Eric Andersenc470f442003-07-28 09:56:35 +00007060static int
7061forkshell(struct job *jp, union node *n, int mode)
7062{
7063 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007064
Eric Andersenc470f442003-07-28 09:56:35 +00007065 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7066 pid = fork();
7067 if (pid < 0) {
7068 TRACE(("Fork failed, errno=%d", errno));
7069 if (jp)
7070 freejob(jp);
7071 error("Cannot fork");
7072 }
7073 if (pid == 0)
7074 forkchild(jp, n, mode);
7075 else
7076 forkparent(jp, n, mode, pid);
7077 return pid;
7078}
Eric Andersencb57d552001-06-28 07:25:16 +00007079
7080/*
7081 * Wait for job to finish.
7082 *
7083 * Under job control we have the problem that while a child process is
7084 * running interrupts generated by the user are sent to the child but not
7085 * to the shell. This means that an infinite loop started by an inter-
7086 * active user may be hard to kill. With job control turned off, an
7087 * interactive user may place an interactive program inside a loop. If
7088 * the interactive program catches interrupts, the user doesn't want
7089 * these interrupts to also abort the loop. The approach we take here
7090 * is to have the shell ignore interrupt signals while waiting for a
7091 * forground process to terminate, and then send itself an interrupt
7092 * signal if the child process was terminated by an interrupt signal.
7093 * Unfortunately, some programs want to do a bit of cleanup and then
7094 * exit on interrupt; unless these processes terminate themselves by
7095 * sending a signal to themselves (instead of calling exit) they will
7096 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007097 *
7098 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007099 */
7100
Eric Andersenc470f442003-07-28 09:56:35 +00007101int
7102waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007103{
Eric Andersencb57d552001-06-28 07:25:16 +00007104 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007105
Eric Andersenc470f442003-07-28 09:56:35 +00007106 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7107 while (jp->state == JOBRUNNING) {
7108 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007109 }
Eric Andersenc470f442003-07-28 09:56:35 +00007110 st = getstatus(jp);
7111#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007112 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007113 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007114 /*
7115 * This is truly gross.
7116 * If we're doing job control, then we did a TIOCSPGRP which
7117 * caused us (the shell) to no longer be in the controlling
7118 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7119 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007120 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007121 */
Eric Andersenc470f442003-07-28 09:56:35 +00007122 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007123 raise(SIGINT);
7124 }
Eric Andersen2870d962001-07-02 17:27:21 +00007125 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007126#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007127 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007128 return st;
7129}
7130
7131
Eric Andersen62483552001-07-10 06:09:16 +00007132/*
7133 * Do a wait system call. If job control is compiled in, we accept
7134 * stopped processes. If block is zero, we return a value of zero
7135 * rather than blocking.
7136 *
7137 * System V doesn't have a non-blocking wait system call. It does
7138 * have a SIGCLD signal that is sent to a process when one of it's
7139 * children dies. The obvious way to use SIGCLD would be to install
7140 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7141 * was received, and have waitproc bump another counter when it got
7142 * the status of a process. Waitproc would then know that a wait
7143 * system call would not block if the two counters were different.
7144 * This approach doesn't work because if a process has children that
7145 * have not been waited for, System V will send it a SIGCLD when it
7146 * installs a signal handler for SIGCLD. What this means is that when
7147 * a child exits, the shell will be sent SIGCLD signals continuously
7148 * until is runs out of stack space, unless it does a wait call before
7149 * restoring the signal handler. The code below takes advantage of
7150 * this (mis)feature by installing a signal handler for SIGCLD and
7151 * then checking to see whether it was called. If there are any
7152 * children to be waited for, it will be.
7153 *
Eric Andersenc470f442003-07-28 09:56:35 +00007154 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7155 * waits at all. In this case, the user will not be informed when
7156 * a background process until the next time she runs a real program
7157 * (as opposed to running a builtin command or just typing return),
7158 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007159 */
7160
Eric Andersenc470f442003-07-28 09:56:35 +00007161static inline int
7162waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007163{
Eric Andersenc470f442003-07-28 09:56:35 +00007164 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007165
Eric Andersenc470f442003-07-28 09:56:35 +00007166#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007167 if (jobctl)
7168 flags |= WUNTRACED;
7169#endif
7170 if (block == 0)
7171 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007172 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007173}
7174
Eric Andersenc470f442003-07-28 09:56:35 +00007175/*
7176 * Wait for a process to terminate.
7177 */
7178
7179static int
7180dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007181{
7182 int pid;
7183 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007184 struct job *jp;
7185 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007186 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007187
7188 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007189 pid = waitproc(block, &status);
7190 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007191 if (pid <= 0)
7192 return pid;
7193 INTOFF;
7194 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007195 for (jp = curjob; jp; jp = jp->prev_job) {
7196 struct procstat *sp;
7197 struct procstat *spend;
7198 if (jp->state == JOBDONE)
7199 continue;
7200 state = JOBDONE;
7201 spend = jp->ps + jp->nprocs;
7202 sp = jp->ps;
7203 do {
7204 if (sp->pid == pid) {
7205 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7206 sp->status = status;
7207 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007208 }
Eric Andersenc470f442003-07-28 09:56:35 +00007209 if (sp->status == -1)
7210 state = JOBRUNNING;
7211#ifdef JOBS
7212 if (state == JOBRUNNING)
7213 continue;
7214 if (WIFSTOPPED(sp->status)) {
7215 jp->stopstatus = sp->status;
7216 state = JOBSTOPPED;
7217 }
Eric Andersencb57d552001-06-28 07:25:16 +00007218#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007219 } while (++sp < spend);
7220 if (thisjob)
7221 goto gotjob;
7222 }
7223#ifdef JOBS
7224 if (!WIFSTOPPED(status))
7225#endif
7226
7227 jobless--;
7228 goto out;
7229
7230gotjob:
7231 if (state != JOBRUNNING) {
7232 thisjob->changed = 1;
7233
7234 if (thisjob->state != state) {
7235 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7236 thisjob->state = state;
7237#ifdef JOBS
7238 if (state == JOBSTOPPED) {
7239 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007240 }
Eric Andersenc470f442003-07-28 09:56:35 +00007241#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007242 }
7243 }
Eric Andersencb57d552001-06-28 07:25:16 +00007244
Eric Andersenc470f442003-07-28 09:56:35 +00007245out:
7246 INTON;
7247
7248 if (thisjob && thisjob == job) {
7249 char s[48 + 1];
7250 int len;
7251
7252 len = sprint_status(s, status, 1);
7253 if (len) {
7254 s[len] = '\n';
7255 s[len + 1] = 0;
7256 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007257 }
Eric Andersencb57d552001-06-28 07:25:16 +00007258 }
7259 return pid;
7260}
7261
7262
7263
Eric Andersencb57d552001-06-28 07:25:16 +00007264/*
7265 * return 1 if there are stopped jobs, otherwise 0
7266 */
Eric Andersenc470f442003-07-28 09:56:35 +00007267int
7268stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007269{
Eric Andersencb57d552001-06-28 07:25:16 +00007270 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007271 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007272
Eric Andersenc470f442003-07-28 09:56:35 +00007273 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007274 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007275 goto out;
7276 jp = curjob;
7277 if (jp && jp->state == JOBSTOPPED) {
7278 out2str("You have stopped jobs.\n");
7279 job_warning = 2;
7280 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007281 }
7282
Eric Andersenc470f442003-07-28 09:56:35 +00007283out:
7284 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007285}
7286
7287/*
7288 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007289 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007290 */
7291
Eric Andersenc470f442003-07-28 09:56:35 +00007292#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007293static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007294
Eric Andersenc470f442003-07-28 09:56:35 +00007295static char *
7296commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007297{
Eric Andersenc470f442003-07-28 09:56:35 +00007298 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007299
Eric Andersenc470f442003-07-28 09:56:35 +00007300 STARTSTACKSTR(cmdnextc);
7301 cmdtxt(n);
7302 name = stackblock();
7303 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7304 name, cmdnextc, cmdnextc));
7305 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007306}
7307
Eric Andersenc470f442003-07-28 09:56:35 +00007308static void
7309cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007310{
Eric Andersencb57d552001-06-28 07:25:16 +00007311 union node *np;
7312 struct nodelist *lp;
7313 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007314 char s[2];
7315
Eric Andersencb57d552001-06-28 07:25:16 +00007316 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007317 default:
7318#if DEBUG
7319 abort();
7320#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007321 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007322 lp = n->npipe.cmdlist;
7323 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007324 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007325 lp = lp->next;
7326 if (!lp)
7327 break;
7328 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007329 }
7330 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007331 case NSEMI:
7332 p = "; ";
7333 goto binop;
7334 case NAND:
7335 p = " && ";
7336 goto binop;
7337 case NOR:
7338 p = " || ";
7339binop:
7340 cmdtxt(n->nbinary.ch1);
7341 cmdputs(p);
7342 n = n->nbinary.ch2;
7343 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007344 case NREDIR:
7345 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007346 n = n->nredir.n;
7347 goto donode;
7348 case NNOT:
7349 cmdputs("!");
7350 n = n->nnot.com;
7351donode:
7352 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007353 break;
7354 case NIF:
7355 cmdputs("if ");
7356 cmdtxt(n->nif.test);
7357 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007358 n = n->nif.ifpart;
7359 if (n->nif.elsepart) {
7360 cmdtxt(n);
7361 cmdputs("; else ");
7362 n = n->nif.elsepart;
7363 }
7364 p = "; fi";
7365 goto dotail;
7366 case NSUBSHELL:
7367 cmdputs("(");
7368 n = n->nredir.n;
7369 p = ")";
7370 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007371 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007372 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007373 goto until;
7374 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007375 p = "until ";
7376until:
7377 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007378 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007379 n = n->nbinary.ch2;
7380 p = "; done";
7381dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007382 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007383dotail:
7384 cmdtxt(n);
7385 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007386 case NFOR:
7387 cmdputs("for ");
7388 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007389 cmdputs(" in ");
7390 cmdlist(n->nfor.args, 1);
7391 n = n->nfor.body;
7392 p = "; done";
7393 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007394 case NDEFUN:
7395 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007396 p = "() { ... }";
7397 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007398 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007399 cmdlist(n->ncmd.args, 1);
7400 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007401 break;
7402 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007403 p = n->narg.text;
7404dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007405 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007406 break;
7407 case NHERE:
7408 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007409 p = "<<...";
7410 goto dotail2;
7411 case NCASE:
7412 cmdputs("case ");
7413 cmdputs(n->ncase.expr->narg.text);
7414 cmdputs(" in ");
7415 for (np = n->ncase.cases; np; np = np->nclist.next) {
7416 cmdtxt(np->nclist.pattern);
7417 cmdputs(") ");
7418 cmdtxt(np->nclist.body);
7419 cmdputs(";; ");
7420 }
7421 p = "esac";
7422 goto dotail2;
7423 case NTO:
7424 p = ">";
7425 goto redir;
7426 case NCLOBBER:
7427 p = ">|";
7428 goto redir;
7429 case NAPPEND:
7430 p = ">>";
7431 goto redir;
7432 case NTOFD:
7433 p = ">&";
7434 goto redir;
7435 case NFROM:
7436 p = "<";
7437 goto redir;
7438 case NFROMFD:
7439 p = "<&";
7440 goto redir;
7441 case NFROMTO:
7442 p = "<>";
7443redir:
7444 s[0] = n->nfile.fd + '0';
7445 s[1] = '\0';
7446 cmdputs(s);
7447 cmdputs(p);
7448 if (n->type == NTOFD || n->type == NFROMFD) {
7449 s[0] = n->ndup.dupfd + '0';
7450 p = s;
7451 goto dotail2;
7452 } else {
7453 n = n->nfile.fname;
7454 goto donode;
7455 }
Eric Andersencb57d552001-06-28 07:25:16 +00007456 }
7457}
Eric Andersencb57d552001-06-28 07:25:16 +00007458
Eric Andersenc470f442003-07-28 09:56:35 +00007459static void
7460cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007461{
Eric Andersenc470f442003-07-28 09:56:35 +00007462 for (; np; np = np->narg.next) {
7463 if (!sep)
7464 cmdputs(spcstr);
7465 cmdtxt(np);
7466 if (sep && np->narg.next)
7467 cmdputs(spcstr);
7468 }
Eric Andersencb57d552001-06-28 07:25:16 +00007469}
7470
Eric Andersen2870d962001-07-02 17:27:21 +00007471
Eric Andersenc470f442003-07-28 09:56:35 +00007472static void
7473cmdputs(const char *s)
7474{
7475 const char *p, *str;
7476 char c, cc[2] = " ";
7477 char *nextc;
7478 int subtype = 0;
7479 int quoted = 0;
7480 static const char *const vstype[16] = {
7481 nullstr, "}", "-", "+", "?", "=",
7482 "#", "##", "%", "%%"
7483 };
7484
7485 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7486 p = s;
7487 while ((c = *p++) != 0) {
7488 str = 0;
7489 switch (c) {
7490 case CTLESC:
7491 c = *p++;
7492 break;
7493 case CTLVAR:
7494 subtype = *p++;
7495 if ((subtype & VSTYPE) == VSLENGTH)
7496 str = "${#";
7497 else
7498 str = "${";
7499 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7500 quoted ^= 1;
7501 c = '"';
7502 } else
7503 goto dostr;
7504 break;
7505 case CTLENDVAR:
7506 quoted >>= 1;
7507 subtype = 0;
7508 if (quoted & 1) {
7509 str = "\"}";
7510 goto dostr;
7511 }
7512 c = '}';
7513 break;
7514 case CTLBACKQ:
7515 str = "$(...)";
7516 goto dostr;
7517 case CTLBACKQ+CTLQUOTE:
7518 str = "\"$(...)\"";
7519 goto dostr;
7520#ifdef CONFIG_ASH_MATH_SUPPORT
7521 case CTLARI:
7522 str = "$((";
7523 goto dostr;
7524 case CTLENDARI:
7525 str = "))";
7526 goto dostr;
7527#endif
7528 case CTLQUOTEMARK:
7529 quoted ^= 1;
7530 c = '"';
7531 break;
7532 case '=':
7533 if (subtype == 0)
7534 break;
7535 str = vstype[subtype & VSTYPE];
7536 if (subtype & VSNUL)
7537 c = ':';
7538 else
7539 c = *str++;
7540 if (c != '}')
7541 quoted <<= 1;
7542 break;
7543 case '\'':
7544 case '\\':
7545 case '"':
7546 case '$':
7547 /* These can only happen inside quotes */
7548 cc[0] = c;
7549 str = cc;
7550 c = '\\';
7551 break;
7552 default:
7553 break;
7554 }
7555 USTPUTC(c, nextc);
7556 if (!str)
7557 continue;
7558dostr:
7559 while ((c = *str++)) {
7560 USTPUTC(c, nextc);
7561 }
7562 }
7563 if (quoted & 1) {
7564 USTPUTC('"', nextc);
7565 }
7566 *nextc = 0;
7567 cmdnextc = nextc;
7568}
7569
7570
7571static void
7572showpipe(struct job *jp, FILE *out)
7573{
7574 struct procstat *sp;
7575 struct procstat *spend;
7576
7577 spend = jp->ps + jp->nprocs;
7578 for (sp = jp->ps + 1; sp < spend; sp++)
7579 fprintf(out, " | %s", sp->cmd);
7580 outcslow('\n', out);
7581 flushall();
7582}
7583
7584static void
7585xtcsetpgrp(int fd, pid_t pgrp)
7586{
7587 if (tcsetpgrp(fd, pgrp))
7588 error("Cannot set tty process group (%m)");
7589}
7590#endif /* JOBS */
7591
7592static int
7593getstatus(struct job *job) {
7594 int status;
7595 int retval;
7596
7597 status = job->ps[job->nprocs - 1].status;
7598 retval = WEXITSTATUS(status);
7599 if (!WIFEXITED(status)) {
7600#if JOBS
7601 retval = WSTOPSIG(status);
7602 if (!WIFSTOPPED(status))
7603#endif
7604 {
7605 /* XXX: limits number of signals */
7606 retval = WTERMSIG(status);
7607#if JOBS
7608 if (retval == SIGINT)
7609 job->sigint = 1;
7610#endif
7611 }
7612 retval += 128;
7613 }
7614 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7615 jobno(job), job->nprocs, status, retval));
7616 return retval;
7617}
7618
Eric Andersend35c5df2002-01-09 15:37:36 +00007619#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007620/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007621
Eric Andersencb57d552001-06-28 07:25:16 +00007622/*
Eric Andersenc470f442003-07-28 09:56:35 +00007623 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007624 */
7625
Eric Andersencb57d552001-06-28 07:25:16 +00007626#define MAXMBOXES 10
7627
Eric Andersenc470f442003-07-28 09:56:35 +00007628/* times of mailboxes */
7629static time_t mailtime[MAXMBOXES];
7630/* Set if MAIL or MAILPATH is changed. */
7631static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007632
7633
7634
7635/*
Eric Andersenc470f442003-07-28 09:56:35 +00007636 * Print appropriate message(s) if mail has arrived.
7637 * If mail_var_path_changed is set,
7638 * then the value of MAIL has mail_var_path_changed,
7639 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007640 */
7641
Eric Andersenc470f442003-07-28 09:56:35 +00007642static void
7643chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007644{
Eric Andersencb57d552001-06-28 07:25:16 +00007645 const char *mpath;
7646 char *p;
7647 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007648 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007649 struct stackmark smark;
7650 struct stat statb;
7651
Eric Andersencb57d552001-06-28 07:25:16 +00007652 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007653 mpath = mpathset() ? mpathval() : mailval();
7654 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007655 p = padvance(&mpath, nullstr);
7656 if (p == NULL)
7657 break;
7658 if (*p == '\0')
7659 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007660 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007661#ifdef DEBUG
7662 if (q[-1] != '/')
7663 abort();
7664#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007665 q[-1] = '\0'; /* delete trailing '/' */
7666 if (stat(p, &statb) < 0) {
7667 *mtp = 0;
7668 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007669 }
Eric Andersenc470f442003-07-28 09:56:35 +00007670 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7671 fprintf(
7672 stderr, snlfmt,
7673 pathopt ? pathopt : "you have mail"
7674 );
7675 }
7676 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007677 }
Eric Andersenc470f442003-07-28 09:56:35 +00007678 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007679 popstackmark(&smark);
7680}
Eric Andersencb57d552001-06-28 07:25:16 +00007681
Eric Andersenec074692001-10-31 11:05:49 +00007682
Eric Andersenc470f442003-07-28 09:56:35 +00007683static void
7684changemail(const char *val)
7685{
7686 mail_var_path_changed++;
7687}
7688
7689#endif /* CONFIG_ASH_MAIL */
7690
7691/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7692
Eric Andersencb57d552001-06-28 07:25:16 +00007693
Eric Andersencb57d552001-06-28 07:25:16 +00007694#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007695static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007696extern int etext();
7697#endif
7698
Eric Andersenc470f442003-07-28 09:56:35 +00007699static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007700
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007701static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007702
Eric Andersencb57d552001-06-28 07:25:16 +00007703/*
7704 * Main routine. We initialize things, parse the arguments, execute
7705 * profiles if we're a login shell, and then call cmdloop to execute
7706 * commands. The setjmp call sets up the location to jump to when an
7707 * exception occurs. When an exception occurs the variable "state"
7708 * is used to figure out how far we had gotten.
7709 */
7710
Eric Andersenc470f442003-07-28 09:56:35 +00007711int
7712ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007713{
Eric Andersenc470f442003-07-28 09:56:35 +00007714 char *shinit;
7715 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007716 struct jmploc jmploc;
7717 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007718
Eric Andersenc470f442003-07-28 09:56:35 +00007719#ifdef __GLIBC__
7720 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007721#endif
7722
Eric Andersencb57d552001-06-28 07:25:16 +00007723#if PROFILE
7724 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7725#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007726 state = 0;
7727 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007728 int status;
7729 int e;
7730
Eric Andersencb57d552001-06-28 07:25:16 +00007731 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007732
7733 e = exception;
7734 switch (exception) {
7735 case EXEXEC:
7736 status = exerrno;
7737 break;
7738
7739 case EXERROR:
7740 status = 2;
7741 break;
7742
7743 default:
7744 status = exitstatus;
7745 break;
7746 }
7747 exitstatus = status;
7748
7749 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7750 exitshell();
7751
7752 if (e == EXINT ) {
7753 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007754 }
7755 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007756 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007757 if (state == 1)
7758 goto state1;
7759 else if (state == 2)
7760 goto state2;
7761 else if (state == 3)
7762 goto state3;
7763 else
7764 goto state4;
7765 }
7766 handler = &jmploc;
7767#ifdef DEBUG
7768 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007769 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007770#endif
7771 rootpid = getpid();
7772 rootshell = 1;
7773 init();
7774 setstackmark(&smark);
7775 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007776#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7777 if ( iflag ) {
7778 const char *hp = lookupvar("HISTFILE");
7779
7780 if(hp == NULL ) {
7781 hp = lookupvar("HOME");
7782 if(hp != NULL) {
7783 char *defhp = concat_path_file(hp, ".ash_history");
7784 setvar("HISTFILE", defhp, 0);
7785 free(defhp);
7786 }
7787 }
7788 }
7789#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007790 if (argv[0] && argv[0][0] == '-')
7791 isloginsh = 1;
7792 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007793 state = 1;
7794 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007795state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007796 state = 2;
7797 read_profile(".profile");
7798 }
Eric Andersenc470f442003-07-28 09:56:35 +00007799state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007800 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007801 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007802#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007803 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007804#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007805 iflag
7806 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007807 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007808 read_profile(shinit);
7809 }
Eric Andersencb57d552001-06-28 07:25:16 +00007810 }
Eric Andersenc470f442003-07-28 09:56:35 +00007811state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007812 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007813 if (minusc)
7814 evalstring(minusc, 0);
7815
7816 if (sflag || minusc == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00007817state4: /* XXX ??? - why isn't this before the "if" statement */
Robert Griebl350d26b2002-12-03 22:45:46 +00007818#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007819 if ( iflag ) {
7820 const char *hp = lookupvar("HISTFILE");
7821
7822 if(hp != NULL )
7823 load_history ( hp );
7824 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007825#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007826 cmdloop(1);
7827 }
7828#if PROFILE
7829 monitor(0);
7830#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007831#if GPROF
7832 {
7833 extern void _mcleanup(void);
7834 _mcleanup();
7835 }
7836#endif
7837 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007838 /* NOTREACHED */
7839}
7840
7841
7842/*
7843 * Read and execute commands. "Top" is nonzero for the top level command
7844 * loop; it turns on prompting if the shell is interactive.
7845 */
7846
Eric Andersenc470f442003-07-28 09:56:35 +00007847static void
7848cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007849{
7850 union node *n;
7851 struct stackmark smark;
7852 int inter;
7853 int numeof = 0;
7854
7855 TRACE(("cmdloop(%d) called\n", top));
7856 setstackmark(&smark);
7857 for (;;) {
7858 if (pendingsigs)
7859 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00007860#if JOBS
7861 if (jobctl)
7862 showjobs(stderr, SHOW_CHANGED);
7863#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007864 inter = 0;
7865 if (iflag && top) {
7866 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007867#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007868 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007869#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007870 }
7871 n = parsecmd(inter);
7872 /* showtree(n); DEBUG */
7873 if (n == NEOF) {
7874 if (!top || numeof >= 50)
7875 break;
7876 if (!stoppedjobs()) {
7877 if (!Iflag)
7878 break;
7879 out2str("\nUse \"exit\" to leave shell.\n");
7880 }
7881 numeof++;
7882 } else if (n != NULL && nflag == 0) {
7883 job_warning = (job_warning == 2) ? 1 : 0;
7884 numeof = 0;
7885 evaltree(n, 0);
7886 }
7887 popstackmark(&smark);
7888 setstackmark(&smark);
7889 if (evalskip == SKIPFILE) {
7890 evalskip = 0;
7891 break;
7892 }
7893 }
7894 popstackmark(&smark);
7895}
7896
7897
7898
7899/*
7900 * Read /etc/profile or .profile. Return on error.
7901 */
7902
Eric Andersenc470f442003-07-28 09:56:35 +00007903static void
7904read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007905{
7906 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00007907 int xflag_set = 0;
7908 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007909
7910 INTOFF;
7911 if ((fd = open(name, O_RDONLY)) >= 0)
7912 setinputfd(fd, 1);
7913 INTON;
7914 if (fd < 0)
7915 return;
7916 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00007917 if (qflag) {
7918 if (xflag)
7919 xflag = 0, xflag_set = 1;
7920 if (vflag)
7921 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00007922 }
7923 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00007924 if (qflag) {
7925 if (xflag_set)
7926 xflag = 1;
7927 if (vflag_set)
7928 vflag = 1;
7929 }
Eric Andersencb57d552001-06-28 07:25:16 +00007930 popfile();
7931}
7932
7933
7934
7935/*
7936 * Read a file containing shell functions.
7937 */
7938
Eric Andersenc470f442003-07-28 09:56:35 +00007939static void
7940readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007941{
7942 int fd;
7943
7944 INTOFF;
7945 if ((fd = open(name, O_RDONLY)) >= 0)
7946 setinputfd(fd, 1);
7947 else
7948 error("Can't open %s", name);
7949 INTON;
7950 cmdloop(0);
7951 popfile();
7952}
7953
7954
Eric Andersencb57d552001-06-28 07:25:16 +00007955/*
Eric Andersenc470f442003-07-28 09:56:35 +00007956 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00007957 * search for the file, which is necessary to find sub-commands.
7958 */
7959
Eric Andersenc470f442003-07-28 09:56:35 +00007960static inline char *
7961find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007962{
7963 char *fullname;
7964 const char *path = pathval();
7965 struct stat statb;
7966
7967 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00007968 if (strchr(name, '/'))
7969 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007970
Eric Andersenc470f442003-07-28 09:56:35 +00007971 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00007972 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7973 /*
7974 * Don't bother freeing here, since it will
7975 * be freed by the caller.
7976 */
7977 return fullname;
7978 }
7979 stunalloc(fullname);
7980 }
7981
7982 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00007983 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007984 /* NOTREACHED */
7985}
7986
Eric Andersenc470f442003-07-28 09:56:35 +00007987int
7988dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007989{
Eric Andersencb57d552001-06-28 07:25:16 +00007990 exitstatus = 0;
7991
Eric Andersenc470f442003-07-28 09:56:35 +00007992 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00007993 char *fullname;
7994 struct stackmark smark;
7995
7996 setstackmark(&smark);
7997 fullname = find_dot_file(argv[1]);
7998 setinputfile(fullname, 1);
7999 commandname = fullname;
8000 cmdloop(0);
8001 popfile();
8002 popstackmark(&smark);
8003 }
8004 return exitstatus;
8005}
8006
8007
Eric Andersenc470f442003-07-28 09:56:35 +00008008static int
8009exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008010{
8011 if (stoppedjobs())
8012 return 0;
8013 if (argc > 1)
8014 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008015 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008016 /* NOTREACHED */
8017}
Eric Andersen62483552001-07-10 06:09:16 +00008018
Eric Andersenc470f442003-07-28 09:56:35 +00008019/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8020
8021/*
8022 * Like malloc, but returns an error when out of space.
8023 */
8024
8025static pointer
8026ckmalloc(size_t nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008027{
Eric Andersenc470f442003-07-28 09:56:35 +00008028 pointer p;
Eric Andersencb57d552001-06-28 07:25:16 +00008029
Eric Andersenc470f442003-07-28 09:56:35 +00008030 p = malloc(nbytes);
8031 if (p == NULL)
8032 error(bb_msg_memory_exhausted);
Eric Andersencb57d552001-06-28 07:25:16 +00008033 return p;
8034}
8035
8036
Eric Andersenc470f442003-07-28 09:56:35 +00008037/*
8038 * Same for realloc.
8039 */
8040
8041static pointer
8042ckrealloc(pointer p, size_t nbytes)
8043{
8044 p = realloc(p, nbytes);
8045 if (p == NULL)
8046 error(bb_msg_memory_exhausted);
8047 return p;
8048}
8049
8050
8051/*
8052 * Make a copy of a string in safe storage.
8053 */
8054
8055static char *
8056savestr(const char *s)
8057{
8058 char *p = strdup(s);
8059 if (!p)
8060 error(bb_msg_memory_exhausted);
8061 return p;
8062}
8063
8064
8065/*
8066 * Parse trees for commands are allocated in lifo order, so we use a stack
8067 * to make this more efficient, and also to avoid all sorts of exception
8068 * handling code to handle interrupts in the middle of a parse.
8069 *
8070 * The size 504 was chosen because the Ultrix malloc handles that size
8071 * well.
8072 */
8073
8074
8075static pointer
8076stalloc(size_t nbytes)
8077{
8078 char *p;
8079 size_t aligned;
8080
8081 aligned = SHELL_ALIGN(nbytes);
8082 if (aligned > stacknleft) {
8083 size_t len;
8084 size_t blocksize;
8085 struct stack_block *sp;
8086
8087 blocksize = aligned;
8088 if (blocksize < MINSIZE)
8089 blocksize = MINSIZE;
8090 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8091 if (len < blocksize)
8092 error(bb_msg_memory_exhausted);
8093 INTOFF;
8094 sp = ckmalloc(len);
8095 sp->prev = stackp;
8096 stacknxt = sp->space;
8097 stacknleft = blocksize;
8098 sstrend = stacknxt + blocksize;
8099 stackp = sp;
8100 INTON;
8101 }
8102 p = stacknxt;
8103 stacknxt += aligned;
8104 stacknleft -= aligned;
8105 return p;
8106}
8107
8108
8109void
8110stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008111{
Eric Andersencb57d552001-06-28 07:25:16 +00008112#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008113 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008114 write(2, "stunalloc\n", 10);
8115 abort();
8116 }
8117#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008118 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008119 stacknxt = p;
8120}
8121
8122
Eric Andersenc470f442003-07-28 09:56:35 +00008123
8124void
8125setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008126{
Eric Andersencb57d552001-06-28 07:25:16 +00008127 mark->stackp = stackp;
8128 mark->stacknxt = stacknxt;
8129 mark->stacknleft = stacknleft;
8130 mark->marknext = markp;
8131 markp = mark;
8132}
8133
8134
Eric Andersenc470f442003-07-28 09:56:35 +00008135void
8136popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008137{
Eric Andersencb57d552001-06-28 07:25:16 +00008138 struct stack_block *sp;
8139
8140 INTOFF;
8141 markp = mark->marknext;
8142 while (stackp != mark->stackp) {
8143 sp = stackp;
8144 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008145 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008146 }
8147 stacknxt = mark->stacknxt;
8148 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008149 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008150 INTON;
8151}
8152
8153
8154/*
8155 * When the parser reads in a string, it wants to stick the string on the
8156 * stack and only adjust the stack pointer when it knows how big the
8157 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8158 * of space on top of the stack and stackblocklen returns the length of
8159 * this block. Growstackblock will grow this space by at least one byte,
8160 * possibly moving it (like realloc). Grabstackblock actually allocates the
8161 * part of the block that has been used.
8162 */
8163
Eric Andersenc470f442003-07-28 09:56:35 +00008164void
8165growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008166{
Eric Andersenc470f442003-07-28 09:56:35 +00008167 size_t newlen;
8168
8169 newlen = stacknleft * 2;
8170 if (newlen < stacknleft)
8171 error(bb_msg_memory_exhausted);
8172 if (newlen < 128)
8173 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008174
8175 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008176 struct stack_block *oldstackp;
8177 struct stackmark *xmark;
8178 struct stack_block *sp;
8179 struct stack_block *prevstackp;
8180 size_t grosslen;
8181
Eric Andersencb57d552001-06-28 07:25:16 +00008182 INTOFF;
8183 oldstackp = stackp;
8184 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008185 prevstackp = sp->prev;
8186 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8187 sp = ckrealloc((pointer)sp, grosslen);
8188 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008189 stackp = sp;
8190 stacknxt = sp->space;
8191 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008192 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008193
Eric Andersenc470f442003-07-28 09:56:35 +00008194 /*
8195 * Stack marks pointing to the start of the old block
8196 * must be relocated to point to the new block
8197 */
8198 xmark = markp;
8199 while (xmark != NULL && xmark->stackp == oldstackp) {
8200 xmark->stackp = stackp;
8201 xmark->stacknxt = stacknxt;
8202 xmark->stacknleft = stacknleft;
8203 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008204 }
8205 INTON;
8206 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008207 char *oldspace = stacknxt;
8208 int oldlen = stacknleft;
8209 char *p = stalloc(newlen);
8210
8211 /* free the space we just allocated */
8212 stacknxt = memcpy(p, oldspace, oldlen);
8213 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008214 }
8215}
8216
Eric Andersenc470f442003-07-28 09:56:35 +00008217static inline void
8218grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008219{
Eric Andersenc470f442003-07-28 09:56:35 +00008220 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008221 stacknxt += len;
8222 stacknleft -= len;
8223}
8224
Eric Andersencb57d552001-06-28 07:25:16 +00008225/*
Eric Andersenc470f442003-07-28 09:56:35 +00008226 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008227 * The user declares a variable of type STACKSTR, which may be declared
8228 * to be a register. The macro STARTSTACKSTR initializes things. Then
8229 * the user uses the macro STPUTC to add characters to the string. In
8230 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8231 * grown as necessary. When the user is done, she can just leave the
8232 * string there and refer to it using stackblock(). Or she can allocate
8233 * the space for it using grabstackstr(). If it is necessary to allow
8234 * someone else to use the stack temporarily and then continue to grow
8235 * the string, the user should use grabstack to allocate the space, and
8236 * then call ungrabstr(p) to return to the previous mode of operation.
8237 *
8238 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8239 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8240 * is space for at least one character.
8241 */
8242
Eric Andersenc470f442003-07-28 09:56:35 +00008243void *
8244growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008245{
Eric Andersenc470f442003-07-28 09:56:35 +00008246 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008247 if (herefd >= 0 && len >= 1024) {
8248 xwrite(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008249 return stackblock();
8250 }
8251 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008252 return stackblock() + len;
8253}
8254
Eric Andersencb57d552001-06-28 07:25:16 +00008255/*
8256 * Called from CHECKSTRSPACE.
8257 */
8258
Eric Andersenc470f442003-07-28 09:56:35 +00008259char *
8260makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008261{
Eric Andersenc470f442003-07-28 09:56:35 +00008262 size_t len = p - stacknxt;
8263 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008264
Eric Andersenc470f442003-07-28 09:56:35 +00008265 for (;;) {
8266 size_t nleft;
8267
8268 size = stackblocksize();
8269 nleft = size - len;
8270 if (nleft >= newlen)
8271 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008272 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008273 }
Eric Andersencb57d552001-06-28 07:25:16 +00008274 return stackblock() + len;
8275}
8276
Eric Andersenc470f442003-07-28 09:56:35 +00008277char *
8278stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008279{
Eric Andersenc470f442003-07-28 09:56:35 +00008280 p = makestrspace(n, p);
8281 p = mempcpy(p, s, n);
8282 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008283}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008284
Eric Andersenc470f442003-07-28 09:56:35 +00008285char *
8286stputs(const char *s, char *p)
8287{
8288 return stnputs(s, strlen(s), p);
8289}
8290
8291/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8292
Eric Andersencb57d552001-06-28 07:25:16 +00008293/*
Eric Andersenc470f442003-07-28 09:56:35 +00008294 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008295 *
Eric Andersenc470f442003-07-28 09:56:35 +00008296 * number(s) Convert a string of digits to an integer.
8297 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008298 */
8299
Eric Andersencb57d552001-06-28 07:25:16 +00008300/*
8301 * prefix -- see if pfx is a prefix of string.
8302 */
8303
Eric Andersenc470f442003-07-28 09:56:35 +00008304char *
8305prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008306{
Eric Andersencb57d552001-06-28 07:25:16 +00008307 while (*pfx) {
8308 if (*pfx++ != *string++)
8309 return 0;
8310 }
Eric Andersenc470f442003-07-28 09:56:35 +00008311 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008312}
8313
8314
8315/*
8316 * Convert a string of digits to an integer, printing an error message on
8317 * failure.
8318 */
8319
Eric Andersenc470f442003-07-28 09:56:35 +00008320int
8321number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008322{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008323
Eric Andersenc470f442003-07-28 09:56:35 +00008324 if (! is_number(s))
8325 error(illnum, s);
8326 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008327}
8328
Eric Andersenc470f442003-07-28 09:56:35 +00008329
8330
8331/*
8332 * Check for a valid number. This should be elsewhere.
8333 */
8334
8335int
8336is_number(const char *p)
8337{
8338 do {
8339 if (! is_digit(*p))
8340 return 0;
8341 } while (*++p != '\0');
8342 return 1;
8343}
8344
8345
Eric Andersencb57d552001-06-28 07:25:16 +00008346/*
8347 * Produce a possibly single quoted string suitable as input to the shell.
8348 * The return string is allocated on the stack.
8349 */
8350
Eric Andersenc470f442003-07-28 09:56:35 +00008351char *
8352single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008353 char *p;
8354
8355 STARTSTACKSTR(p);
8356
8357 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008358 char *q;
8359 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008360
Eric Andersenc470f442003-07-28 09:56:35 +00008361 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008362
Eric Andersenc470f442003-07-28 09:56:35 +00008363 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008364
Eric Andersenc470f442003-07-28 09:56:35 +00008365 *q++ = '\'';
8366 q = mempcpy(q, s, len);
8367 *q++ = '\'';
8368 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008369
Eric Andersenc470f442003-07-28 09:56:35 +00008370 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008371
Eric Andersenc470f442003-07-28 09:56:35 +00008372 len = strspn(s, "'");
8373 if (!len)
8374 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008375
Eric Andersenc470f442003-07-28 09:56:35 +00008376 q = p = makestrspace(len + 3, p);
8377
8378 *q++ = '"';
8379 q = mempcpy(q, s, len);
8380 *q++ = '"';
8381 s += len;
8382
8383 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008384 } while (*s);
8385
8386 USTPUTC(0, p);
8387
Eric Andersenc470f442003-07-28 09:56:35 +00008388 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008389}
8390
8391/*
Eric Andersenc470f442003-07-28 09:56:35 +00008392 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008393 */
8394
Eric Andersenc470f442003-07-28 09:56:35 +00008395char *
8396sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008397{
Eric Andersenc470f442003-07-28 09:56:35 +00008398 size_t len = strlen(p) + 1;
8399 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008400}
Eric Andersenc470f442003-07-28 09:56:35 +00008401
8402
8403static void
8404calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008405{
Eric Andersenc470f442003-07-28 09:56:35 +00008406 if (n == NULL)
8407 return;
8408 funcblocksize += nodesize[n->type];
8409 switch (n->type) {
8410 case NCMD:
8411 calcsize(n->ncmd.redirect);
8412 calcsize(n->ncmd.args);
8413 calcsize(n->ncmd.assign);
8414 break;
8415 case NPIPE:
8416 sizenodelist(n->npipe.cmdlist);
8417 break;
8418 case NREDIR:
8419 case NBACKGND:
8420 case NSUBSHELL:
8421 calcsize(n->nredir.redirect);
8422 calcsize(n->nredir.n);
8423 break;
8424 case NAND:
8425 case NOR:
8426 case NSEMI:
8427 case NWHILE:
8428 case NUNTIL:
8429 calcsize(n->nbinary.ch2);
8430 calcsize(n->nbinary.ch1);
8431 break;
8432 case NIF:
8433 calcsize(n->nif.elsepart);
8434 calcsize(n->nif.ifpart);
8435 calcsize(n->nif.test);
8436 break;
8437 case NFOR:
8438 funcstringsize += strlen(n->nfor.var) + 1;
8439 calcsize(n->nfor.body);
8440 calcsize(n->nfor.args);
8441 break;
8442 case NCASE:
8443 calcsize(n->ncase.cases);
8444 calcsize(n->ncase.expr);
8445 break;
8446 case NCLIST:
8447 calcsize(n->nclist.body);
8448 calcsize(n->nclist.pattern);
8449 calcsize(n->nclist.next);
8450 break;
8451 case NDEFUN:
8452 case NARG:
8453 sizenodelist(n->narg.backquote);
8454 funcstringsize += strlen(n->narg.text) + 1;
8455 calcsize(n->narg.next);
8456 break;
8457 case NTO:
8458 case NCLOBBER:
8459 case NFROM:
8460 case NFROMTO:
8461 case NAPPEND:
8462 calcsize(n->nfile.fname);
8463 calcsize(n->nfile.next);
8464 break;
8465 case NTOFD:
8466 case NFROMFD:
8467 calcsize(n->ndup.vname);
8468 calcsize(n->ndup.next);
8469 break;
8470 case NHERE:
8471 case NXHERE:
8472 calcsize(n->nhere.doc);
8473 calcsize(n->nhere.next);
8474 break;
8475 case NNOT:
8476 calcsize(n->nnot.com);
8477 break;
8478 };
Eric Andersencb57d552001-06-28 07:25:16 +00008479}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008480
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008481
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008482
Eric Andersenc470f442003-07-28 09:56:35 +00008483static void
8484sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008485{
8486 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008487 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008488 calcsize(lp->n);
8489 lp = lp->next;
8490 }
8491}
Eric Andersencb57d552001-06-28 07:25:16 +00008492
8493
Eric Andersenc470f442003-07-28 09:56:35 +00008494
8495static union node *
8496copynode(union node *n)
8497{
8498 union node *new;
8499
8500 if (n == NULL)
8501 return NULL;
8502 new = funcblock;
8503 funcblock = (char *) funcblock + nodesize[n->type];
8504 switch (n->type) {
8505 case NCMD:
8506 new->ncmd.redirect = copynode(n->ncmd.redirect);
8507 new->ncmd.args = copynode(n->ncmd.args);
8508 new->ncmd.assign = copynode(n->ncmd.assign);
8509 break;
8510 case NPIPE:
8511 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8512 new->npipe.backgnd = n->npipe.backgnd;
8513 break;
8514 case NREDIR:
8515 case NBACKGND:
8516 case NSUBSHELL:
8517 new->nredir.redirect = copynode(n->nredir.redirect);
8518 new->nredir.n = copynode(n->nredir.n);
8519 break;
8520 case NAND:
8521 case NOR:
8522 case NSEMI:
8523 case NWHILE:
8524 case NUNTIL:
8525 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8526 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8527 break;
8528 case NIF:
8529 new->nif.elsepart = copynode(n->nif.elsepart);
8530 new->nif.ifpart = copynode(n->nif.ifpart);
8531 new->nif.test = copynode(n->nif.test);
8532 break;
8533 case NFOR:
8534 new->nfor.var = nodesavestr(n->nfor.var);
8535 new->nfor.body = copynode(n->nfor.body);
8536 new->nfor.args = copynode(n->nfor.args);
8537 break;
8538 case NCASE:
8539 new->ncase.cases = copynode(n->ncase.cases);
8540 new->ncase.expr = copynode(n->ncase.expr);
8541 break;
8542 case NCLIST:
8543 new->nclist.body = copynode(n->nclist.body);
8544 new->nclist.pattern = copynode(n->nclist.pattern);
8545 new->nclist.next = copynode(n->nclist.next);
8546 break;
8547 case NDEFUN:
8548 case NARG:
8549 new->narg.backquote = copynodelist(n->narg.backquote);
8550 new->narg.text = nodesavestr(n->narg.text);
8551 new->narg.next = copynode(n->narg.next);
8552 break;
8553 case NTO:
8554 case NCLOBBER:
8555 case NFROM:
8556 case NFROMTO:
8557 case NAPPEND:
8558 new->nfile.fname = copynode(n->nfile.fname);
8559 new->nfile.fd = n->nfile.fd;
8560 new->nfile.next = copynode(n->nfile.next);
8561 break;
8562 case NTOFD:
8563 case NFROMFD:
8564 new->ndup.vname = copynode(n->ndup.vname);
8565 new->ndup.dupfd = n->ndup.dupfd;
8566 new->ndup.fd = n->ndup.fd;
8567 new->ndup.next = copynode(n->ndup.next);
8568 break;
8569 case NHERE:
8570 case NXHERE:
8571 new->nhere.doc = copynode(n->nhere.doc);
8572 new->nhere.fd = n->nhere.fd;
8573 new->nhere.next = copynode(n->nhere.next);
8574 break;
8575 case NNOT:
8576 new->nnot.com = copynode(n->nnot.com);
8577 break;
8578 };
8579 new->type = n->type;
8580 return new;
8581}
8582
8583
8584static struct nodelist *
8585copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008586{
8587 struct nodelist *start;
8588 struct nodelist **lpp;
8589
8590 lpp = &start;
8591 while (lp) {
8592 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008593 funcblock = (char *) funcblock +
8594 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008595 (*lpp)->n = copynode(lp->n);
8596 lp = lp->next;
8597 lpp = &(*lpp)->next;
8598 }
8599 *lpp = NULL;
8600 return start;
8601}
8602
8603
Eric Andersencb57d552001-06-28 07:25:16 +00008604
Eric Andersenc470f442003-07-28 09:56:35 +00008605static char *
8606nodesavestr(char *s)
8607{
8608 char *rtn = funcstring;
8609
8610 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008611 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008612}
8613
Eric Andersenc470f442003-07-28 09:56:35 +00008614
8615
8616/*
8617 * Free a parse tree.
8618 */
8619
8620static void
8621freefunc(struct funcnode *f)
8622{
8623 if (f && --f->count < 0)
8624 ckfree(f);
8625}
8626
8627
8628static void options(int);
8629static void setoption(int, int);
8630
Eric Andersencb57d552001-06-28 07:25:16 +00008631
Eric Andersencb57d552001-06-28 07:25:16 +00008632/*
8633 * Process the shell command line arguments.
8634 */
8635
Eric Andersenc470f442003-07-28 09:56:35 +00008636void
8637procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008638{
8639 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008640 const char *xminusc;
8641 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008642
Eric Andersenc470f442003-07-28 09:56:35 +00008643 xargv = argv;
8644 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008645 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008646 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008647 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008648 optlist[i] = 2;
8649 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008650 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008651 xargv = argptr;
8652 xminusc = minusc;
8653 if (*xargv == NULL) {
8654 if (xminusc)
8655 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008656 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008657 }
Eric Andersencb57d552001-06-28 07:25:16 +00008658 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8659 iflag = 1;
8660 if (mflag == 2)
8661 mflag = iflag;
8662 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008663 if (optlist[i] == 2)
8664 optlist[i] = 0;
8665#if DEBUG == 2
8666 debug = 1;
8667#endif
8668 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8669 if (xminusc) {
8670 minusc = *xargv++;
8671 if (*xargv)
8672 goto setarg0;
8673 } else if (!sflag) {
8674 setinputfile(*xargv, 0);
8675setarg0:
8676 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008677 commandname = arg0;
8678 }
Eric Andersencb57d552001-06-28 07:25:16 +00008679
Eric Andersenc470f442003-07-28 09:56:35 +00008680 shellparam.p = xargv;
8681#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008682 shellparam.optind = 1;
8683 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008684#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008685 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008686 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008687 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008688 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008689 }
8690 optschanged();
8691}
8692
8693
Eric Andersenc470f442003-07-28 09:56:35 +00008694void
8695optschanged(void)
8696{
8697#ifdef DEBUG
8698 opentrace();
8699#endif
8700 setinteractive(iflag);
8701 setjobctl(mflag);
8702}
Eric Andersencb57d552001-06-28 07:25:16 +00008703
Eric Andersenc470f442003-07-28 09:56:35 +00008704static inline void
8705minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008706{
8707 int i;
8708
8709 if (name == NULL) {
8710 out1str("Current option settings\n");
8711 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008712 out1fmt("%-16s%s\n", optnames(i),
8713 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008714 } else {
8715 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008716 if (equal(name, optnames(i))) {
8717 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008718 return;
8719 }
8720 error("Illegal option -o %s", name);
8721 }
8722}
8723
Eric Andersenc470f442003-07-28 09:56:35 +00008724/*
8725 * Process shell options. The global variable argptr contains a pointer
8726 * to the argument list; we advance it past the options.
8727 */
Eric Andersen62483552001-07-10 06:09:16 +00008728
Eric Andersenc470f442003-07-28 09:56:35 +00008729static void
8730options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008731{
8732 char *p;
8733 int val;
8734 int c;
8735
8736 if (cmdline)
8737 minusc = NULL;
8738 while ((p = *argptr) != NULL) {
8739 argptr++;
8740 if ((c = *p++) == '-') {
8741 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008742 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8743 if (!cmdline) {
8744 /* "-" means turn off -x and -v */
8745 if (p[0] == '\0')
8746 xflag = vflag = 0;
8747 /* "--" means reset params */
8748 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008749 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008750 }
Eric Andersenc470f442003-07-28 09:56:35 +00008751 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008752 }
8753 } else if (c == '+') {
8754 val = 0;
8755 } else {
8756 argptr--;
8757 break;
8758 }
8759 while ((c = *p++) != '\0') {
8760 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008761 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008762 } else if (c == 'o') {
8763 minus_o(*argptr, val);
8764 if (*argptr)
8765 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008766 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008767 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008768 isloginsh = 1;
8769 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008770 } else {
8771 setoption(c, val);
8772 }
8773 }
8774 }
8775}
8776
Eric Andersencb57d552001-06-28 07:25:16 +00008777
Eric Andersenc470f442003-07-28 09:56:35 +00008778
8779static void
8780setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008781{
Eric Andersencb57d552001-06-28 07:25:16 +00008782 int i;
8783
8784 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008785 if (optletters(i) == flag) {
8786 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008787 return;
8788 }
8789 error("Illegal option -%c", flag);
8790 /* NOTREACHED */
8791}
8792
8793
8794
Eric Andersencb57d552001-06-28 07:25:16 +00008795/*
8796 * Set the shell parameters.
8797 */
8798
Eric Andersenc470f442003-07-28 09:56:35 +00008799void
8800setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008801{
Eric Andersencb57d552001-06-28 07:25:16 +00008802 char **newparam;
8803 char **ap;
8804 int nparam;
8805
Eric Andersenc470f442003-07-28 09:56:35 +00008806 for (nparam = 0 ; argv[nparam] ; nparam++);
8807 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008808 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008809 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008810 }
8811 *ap = NULL;
8812 freeparam(&shellparam);
8813 shellparam.malloc = 1;
8814 shellparam.nparam = nparam;
8815 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008816#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008817 shellparam.optind = 1;
8818 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008819#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008820}
8821
8822
8823/*
8824 * Free the list of positional parameters.
8825 */
8826
Eric Andersenc470f442003-07-28 09:56:35 +00008827void
8828freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008829{
Eric Andersencb57d552001-06-28 07:25:16 +00008830 char **ap;
8831
8832 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008833 for (ap = param->p ; *ap ; ap++)
8834 ckfree(*ap);
8835 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008836 }
8837}
8838
8839
8840
8841/*
8842 * The shift builtin command.
8843 */
8844
Eric Andersenc470f442003-07-28 09:56:35 +00008845int
8846shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008847{
8848 int n;
8849 char **ap1, **ap2;
8850
8851 n = 1;
8852 if (argc > 1)
8853 n = number(argv[1]);
8854 if (n > shellparam.nparam)
8855 error("can't shift that many");
8856 INTOFF;
8857 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008858 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008859 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008860 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008861 }
8862 ap2 = shellparam.p;
8863 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008864#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008865 shellparam.optind = 1;
8866 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008867#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008868 INTON;
8869 return 0;
8870}
8871
8872
8873
8874/*
8875 * The set command builtin.
8876 */
8877
Eric Andersenc470f442003-07-28 09:56:35 +00008878int
8879setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008880{
8881 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008882 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008883 INTOFF;
8884 options(0);
8885 optschanged();
8886 if (*argptr != NULL) {
8887 setparam(argptr);
8888 }
8889 INTON;
8890 return 0;
8891}
8892
8893
Eric Andersenc470f442003-07-28 09:56:35 +00008894#ifdef CONFIG_ASH_GETOPTS
8895static void
8896getoptsreset(value)
8897 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00008898{
8899 shellparam.optind = number(value);
8900 shellparam.optoff = -1;
8901}
Eric Andersenc470f442003-07-28 09:56:35 +00008902#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008903
Eric Andersenbdfd0d72001-10-24 05:00:29 +00008904#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00008905static void change_lc_all(const char *value)
8906{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008907 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008908 setlocale(LC_ALL, value);
8909}
8910
8911static void change_lc_ctype(const char *value)
8912{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008913 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008914 setlocale(LC_CTYPE, value);
8915}
8916
8917#endif
8918
Eric Andersend35c5df2002-01-09 15:37:36 +00008919#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008920static int
Eric Andersenc470f442003-07-28 09:56:35 +00008921getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008922{
8923 char *p, *q;
8924 char c = '?';
8925 int done = 0;
8926 int err = 0;
8927 char s[10];
Eric Andersenc470f442003-07-28 09:56:35 +00008928 char **optnext = optfirst + *param_optind - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008929
Eric Andersenc470f442003-07-28 09:56:35 +00008930 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8931 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00008932 p = NULL;
8933 else
8934 p = *(optnext - 1) + *optoff;
8935 if (p == NULL || *p == '\0') {
8936 /* Current word is done, advance */
8937 if (optnext == NULL)
8938 return 1;
8939 p = *optnext;
8940 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00008941atend:
Eric Andersencb57d552001-06-28 07:25:16 +00008942 p = NULL;
8943 done = 1;
8944 goto out;
8945 }
8946 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00008947 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00008948 goto atend;
8949 }
8950
8951 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00008952 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00008953 if (*q == '\0') {
8954 if (optstr[0] == ':') {
8955 s[0] = c;
8956 s[1] = '\0';
8957 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008958 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008959 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008960 (void) unsetvar("OPTARG");
8961 }
8962 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00008963 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00008964 }
8965 if (*++q == ':')
8966 q++;
8967 }
8968
8969 if (*++q == ':') {
8970 if (*p == '\0' && (p = *optnext) == NULL) {
8971 if (optstr[0] == ':') {
8972 s[0] = c;
8973 s[1] = '\0';
8974 err |= setvarsafe("OPTARG", s, 0);
8975 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008976 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008977 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00008978 (void) unsetvar("OPTARG");
8979 c = '?';
8980 }
Eric Andersenc470f442003-07-28 09:56:35 +00008981 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00008982 }
8983
8984 if (p == *optnext)
8985 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00008986 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00008987 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008988 } else
Eric Andersenc470f442003-07-28 09:56:35 +00008989 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00008990
Eric Andersenc470f442003-07-28 09:56:35 +00008991out:
Eric Andersencb57d552001-06-28 07:25:16 +00008992 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008993 *param_optind = optnext - optfirst + 1;
8994 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00008995 err |= setvarsafe("OPTIND", s, VNOFUNC);
8996 s[0] = c;
8997 s[1] = '\0';
8998 err |= setvarsafe(optvar, s, 0);
8999 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009000 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009001 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009002 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009003 exraise(EXERROR);
9004 }
9005 return done;
9006}
Eric Andersenc470f442003-07-28 09:56:35 +00009007
9008/*
9009 * The getopts builtin. Shellparam.optnext points to the next argument
9010 * to be processed. Shellparam.optptr points to the next character to
9011 * be processed in the current argument. If shellparam.optnext is NULL,
9012 * then it's the first time getopts has been called.
9013 */
9014
9015int
9016getoptscmd(int argc, char **argv)
9017{
9018 char **optbase;
9019
9020 if (argc < 3)
9021 error("Usage: getopts optstring var [arg]");
9022 else if (argc == 3) {
9023 optbase = shellparam.p;
9024 if (shellparam.optind > shellparam.nparam + 1) {
9025 shellparam.optind = 1;
9026 shellparam.optoff = -1;
9027 }
9028 }
9029 else {
9030 optbase = &argv[3];
9031 if (shellparam.optind > argc - 2) {
9032 shellparam.optind = 1;
9033 shellparam.optoff = -1;
9034 }
9035 }
9036
9037 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9038 &shellparam.optoff);
9039}
9040#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009041
9042/*
9043 * XXX - should get rid of. have all builtins use getopt(3). the
9044 * library getopt must have the BSD extension static variable "optreset"
9045 * otherwise it can't be used within the shell safely.
9046 *
9047 * Standard option processing (a la getopt) for builtin routines. The
9048 * only argument that is passed to nextopt is the option string; the
9049 * other arguments are unnecessary. It return the character, or '\0' on
9050 * end of input.
9051 */
9052
Eric Andersenc470f442003-07-28 09:56:35 +00009053static int
9054nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009055{
Eric Andersencb57d552001-06-28 07:25:16 +00009056 char *p;
9057 const char *q;
9058 char c;
9059
9060 if ((p = optptr) == NULL || *p == '\0') {
9061 p = *argptr;
9062 if (p == NULL || *p != '-' || *++p == '\0')
9063 return '\0';
9064 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009065 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009066 return '\0';
9067 }
9068 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009069 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009070 if (*q == '\0')
9071 error("Illegal option -%c", c);
9072 if (*++q == ':')
9073 q++;
9074 }
9075 if (*++q == ':') {
9076 if (*p == '\0' && (p = *argptr++) == NULL)
9077 error("No arg for -%c option", c);
9078 optionarg = p;
9079 p = NULL;
9080 }
9081 optptr = p;
9082 return c;
9083}
9084
Eric Andersenc470f442003-07-28 09:56:35 +00009085/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9086
9087
9088
9089void
9090outstr(const char *p, FILE *file)
9091{
9092 INTOFF;
9093 fputs(p, file);
9094 INTON;
9095}
9096
9097void
9098flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009099{
Eric Andersencb57d552001-06-28 07:25:16 +00009100 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009101 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009102 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009103 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009104}
9105
9106
Eric Andersenc470f442003-07-28 09:56:35 +00009107void
9108flushout(FILE *dest)
9109{
9110 INTOFF;
9111 fflush(dest);
9112 INTON;
9113}
9114
9115static void
9116outcslow(int c, FILE *dest)
9117{
9118 INTOFF;
9119 putc(c, dest);
9120 fflush(dest);
9121 INTON;
9122}
9123
9124
9125static int
9126out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009127{
9128 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009129 int r;
9130
9131 INTOFF;
9132 va_start(ap, fmt);
9133 r = vprintf(fmt, ap);
9134 va_end(ap);
9135 INTON;
9136 return r;
9137}
9138
9139
9140int
9141fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9142{
9143 va_list ap;
9144 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009145
Eric Andersencb57d552001-06-28 07:25:16 +00009146 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009147 INTOFF;
9148 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009149 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009150 INTON;
9151 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009152}
9153
Eric Andersenc470f442003-07-28 09:56:35 +00009154
Eric Andersencb57d552001-06-28 07:25:16 +00009155/*
9156 * Version of write which resumes after a signal is caught.
9157 */
9158
Eric Andersenc470f442003-07-28 09:56:35 +00009159static void
9160xwrite(int fd, const void *p, size_t n)
Eric Andersen2870d962001-07-02 17:27:21 +00009161{
Eric Andersenc470f442003-07-28 09:56:35 +00009162 ssize_t i;
Eric Andersencb57d552001-06-28 07:25:16 +00009163
Eric Andersenc470f442003-07-28 09:56:35 +00009164 do {
9165 i = bb_full_write(fd, p, n);
9166 } while (i < 0 && errno == EINTR);
Eric Andersencb57d552001-06-28 07:25:16 +00009167}
9168
9169
Eric Andersenc470f442003-07-28 09:56:35 +00009170/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9171
9172
Eric Andersencb57d552001-06-28 07:25:16 +00009173/*
9174 * Shell command parser.
9175 */
9176
9177#define EOFMARKLEN 79
9178
9179
Eric Andersencb57d552001-06-28 07:25:16 +00009180struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009181 struct heredoc *next; /* next here document in list */
9182 union node *here; /* redirection node */
9183 char *eofmark; /* string indicating end of input */
9184 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009185};
9186
9187
9188
Eric Andersenc470f442003-07-28 09:56:35 +00009189static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009190
9191
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009192static union node *list(int);
9193static union node *andor(void);
9194static union node *pipeline(void);
9195static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009196static union node *simplecmd(void);
9197static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009198static void parsefname(void);
9199static void parseheredoc(void);
9200static char peektoken(void);
9201static int readtoken(void);
9202static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009203static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009204static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009205static void synexpect(int) __attribute__((__noreturn__));
9206static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009207static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009208
9209
Eric Andersenc470f442003-07-28 09:56:35 +00009210static inline int
9211goodname(const char *p)
9212{
9213 return !*endofname(p);
9214}
9215
9216static inline int
9217isassignment(const char *p)
9218{
9219 const char *q = endofname(p);
9220 if (p == q)
9221 return 0;
9222 return *q == '=';
9223}
9224
9225
Eric Andersencb57d552001-06-28 07:25:16 +00009226/*
9227 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9228 * valid parse tree indicating a blank line.)
9229 */
9230
Eric Andersenc470f442003-07-28 09:56:35 +00009231union node *
9232parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009233{
9234 int t;
9235
9236 tokpushback = 0;
9237 doprompt = interact;
9238 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009239 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009240 needprompt = 0;
9241 t = readtoken();
9242 if (t == TEOF)
9243 return NEOF;
9244 if (t == TNL)
9245 return NULL;
9246 tokpushback++;
9247 return list(1);
9248}
9249
9250
Eric Andersenc470f442003-07-28 09:56:35 +00009251static union node *
9252list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009253{
9254 union node *n1, *n2, *n3;
9255 int tok;
9256
Eric Andersenc470f442003-07-28 09:56:35 +00009257 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9258 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009259 return NULL;
9260 n1 = NULL;
9261 for (;;) {
9262 n2 = andor();
9263 tok = readtoken();
9264 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009265 if (n2->type == NPIPE) {
9266 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009267 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009268 if (n2->type != NREDIR) {
9269 n3 = stalloc(sizeof(struct nredir));
9270 n3->nredir.n = n2;
9271 n3->nredir.redirect = NULL;
9272 n2 = n3;
9273 }
9274 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009275 }
9276 }
9277 if (n1 == NULL) {
9278 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009279 }
9280 else {
9281 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009282 n3->type = NSEMI;
9283 n3->nbinary.ch1 = n1;
9284 n3->nbinary.ch2 = n2;
9285 n1 = n3;
9286 }
9287 switch (tok) {
9288 case TBACKGND:
9289 case TSEMI:
9290 tok = readtoken();
9291 /* fall through */
9292 case TNL:
9293 if (tok == TNL) {
9294 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009295 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009296 return n1;
9297 } else {
9298 tokpushback++;
9299 }
Eric Andersenc470f442003-07-28 09:56:35 +00009300 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009301 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009302 return n1;
9303 break;
9304 case TEOF:
9305 if (heredoclist)
9306 parseheredoc();
9307 else
Eric Andersenc470f442003-07-28 09:56:35 +00009308 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009309 return n1;
9310 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009311 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009312 synexpect(-1);
9313 tokpushback++;
9314 return n1;
9315 }
9316 }
9317}
9318
9319
9320
Eric Andersenc470f442003-07-28 09:56:35 +00009321static union node *
9322andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009323{
Eric Andersencb57d552001-06-28 07:25:16 +00009324 union node *n1, *n2, *n3;
9325 int t;
9326
Eric Andersencb57d552001-06-28 07:25:16 +00009327 n1 = pipeline();
9328 for (;;) {
9329 if ((t = readtoken()) == TAND) {
9330 t = NAND;
9331 } else if (t == TOR) {
9332 t = NOR;
9333 } else {
9334 tokpushback++;
9335 return n1;
9336 }
Eric Andersenc470f442003-07-28 09:56:35 +00009337 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009338 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009339 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009340 n3->type = t;
9341 n3->nbinary.ch1 = n1;
9342 n3->nbinary.ch2 = n2;
9343 n1 = n3;
9344 }
9345}
9346
9347
9348
Eric Andersenc470f442003-07-28 09:56:35 +00009349static union node *
9350pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009351{
Eric Andersencb57d552001-06-28 07:25:16 +00009352 union node *n1, *n2, *pipenode;
9353 struct nodelist *lp, *prev;
9354 int negate;
9355
9356 negate = 0;
9357 TRACE(("pipeline: entered\n"));
9358 if (readtoken() == TNOT) {
9359 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009360 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009361 } else
9362 tokpushback++;
9363 n1 = command();
9364 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009365 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009366 pipenode->type = NPIPE;
9367 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009368 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009369 pipenode->npipe.cmdlist = lp;
9370 lp->n = n1;
9371 do {
9372 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009373 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9374 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009375 lp->n = command();
9376 prev->next = lp;
9377 } while (readtoken() == TPIPE);
9378 lp->next = NULL;
9379 n1 = pipenode;
9380 }
9381 tokpushback++;
9382 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009383 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009384 n2->type = NNOT;
9385 n2->nnot.com = n1;
9386 return n2;
9387 } else
9388 return n1;
9389}
9390
9391
9392
Eric Andersenc470f442003-07-28 09:56:35 +00009393static union node *
9394command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009395{
Eric Andersencb57d552001-06-28 07:25:16 +00009396 union node *n1, *n2;
9397 union node *ap, **app;
9398 union node *cp, **cpp;
9399 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009400 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009401 int t;
9402
9403 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009404 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009405
Eric Andersencb57d552001-06-28 07:25:16 +00009406 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009407 default:
9408 synexpect(-1);
9409 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009410 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009411 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009412 n1->type = NIF;
9413 n1->nif.test = list(0);
9414 if (readtoken() != TTHEN)
9415 synexpect(TTHEN);
9416 n1->nif.ifpart = list(0);
9417 n2 = n1;
9418 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009419 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009420 n2 = n2->nif.elsepart;
9421 n2->type = NIF;
9422 n2->nif.test = list(0);
9423 if (readtoken() != TTHEN)
9424 synexpect(TTHEN);
9425 n2->nif.ifpart = list(0);
9426 }
9427 if (lasttoken == TELSE)
9428 n2->nif.elsepart = list(0);
9429 else {
9430 n2->nif.elsepart = NULL;
9431 tokpushback++;
9432 }
Eric Andersenc470f442003-07-28 09:56:35 +00009433 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009434 break;
9435 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009436 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009437 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009438 n1 = (union node *)stalloc(sizeof (struct nbinary));
9439 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009440 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009441 if ((got=readtoken()) != TDO) {
9442TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009443 synexpect(TDO);
9444 }
9445 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009446 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009447 break;
9448 }
9449 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009450 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009451 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009452 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009453 n1->type = NFOR;
9454 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009455 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009456 if (readtoken() == TIN) {
9457 app = &ap;
9458 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009459 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009460 n2->type = NARG;
9461 n2->narg.text = wordtext;
9462 n2->narg.backquote = backquotelist;
9463 *app = n2;
9464 app = &n2->narg.next;
9465 }
9466 *app = NULL;
9467 n1->nfor.args = ap;
9468 if (lasttoken != TNL && lasttoken != TSEMI)
9469 synexpect(-1);
9470 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009471 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009472 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009473 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009474 n2->narg.backquote = NULL;
9475 n2->narg.next = NULL;
9476 n1->nfor.args = n2;
9477 /*
9478 * Newline or semicolon here is optional (but note
9479 * that the original Bourne shell only allowed NL).
9480 */
9481 if (lasttoken != TNL && lasttoken != TSEMI)
9482 tokpushback++;
9483 }
Eric Andersenc470f442003-07-28 09:56:35 +00009484 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009485 if (readtoken() != TDO)
9486 synexpect(TDO);
9487 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009488 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009489 break;
9490 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009491 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009492 n1->type = NCASE;
9493 if (readtoken() != TWORD)
9494 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009495 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009496 n2->type = NARG;
9497 n2->narg.text = wordtext;
9498 n2->narg.backquote = backquotelist;
9499 n2->narg.next = NULL;
9500 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009501 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009502 } while (readtoken() == TNL);
9503 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009504 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009505 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009506next_case:
9507 checkkwd = CHKNL | CHKKWD;
9508 t = readtoken();
9509 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009510 if (lasttoken == TLP)
9511 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009512 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009513 cp->type = NCLIST;
9514 app = &cp->nclist.pattern;
9515 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009516 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009517 ap->type = NARG;
9518 ap->narg.text = wordtext;
9519 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009520 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009521 break;
9522 app = &ap->narg.next;
9523 readtoken();
9524 }
9525 ap->narg.next = NULL;
9526 if (lasttoken != TRP)
9527 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009528 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009529
Eric Andersenc470f442003-07-28 09:56:35 +00009530 cpp = &cp->nclist.next;
9531
9532 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009533 if ((t = readtoken()) != TESAC) {
9534 if (t != TENDCASE)
9535 synexpect(TENDCASE);
9536 else
Eric Andersenc470f442003-07-28 09:56:35 +00009537 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009538 }
Eric Andersenc470f442003-07-28 09:56:35 +00009539 }
Eric Andersencb57d552001-06-28 07:25:16 +00009540 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009541 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009542 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009543 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009544 n1->type = NSUBSHELL;
9545 n1->nredir.n = list(0);
9546 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009547 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009548 break;
9549 case TBEGIN:
9550 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009551 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009552 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009553 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009554 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009555 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009556 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009557 }
9558
Eric Andersenc470f442003-07-28 09:56:35 +00009559 if (readtoken() != t)
9560 synexpect(t);
9561
9562redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009563 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009564 checkkwd = CHKKWD | CHKALIAS;
9565 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009566 while (readtoken() == TREDIR) {
9567 *rpp = n2 = redirnode;
9568 rpp = &n2->nfile.next;
9569 parsefname();
9570 }
9571 tokpushback++;
9572 *rpp = NULL;
9573 if (redir) {
9574 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009575 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009576 n2->type = NREDIR;
9577 n2->nredir.n = n1;
9578 n1 = n2;
9579 }
9580 n1->nredir.redirect = redir;
9581 }
9582
9583 return n1;
9584}
9585
9586
Eric Andersenc470f442003-07-28 09:56:35 +00009587static union node *
9588simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009589 union node *args, **app;
9590 union node *n = NULL;
9591 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009592 union node **rpp, *redir;
9593 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009594
9595 args = NULL;
9596 app = &args;
9597 vars = NULL;
9598 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009599 redir = NULL;
9600 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009601
Eric Andersenc470f442003-07-28 09:56:35 +00009602 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009603 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009604 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009605 switch (readtoken()) {
9606 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009607 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009608 n->type = NARG;
9609 n->narg.text = wordtext;
9610 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009611 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009612 *vpp = n;
9613 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009614 } else {
9615 *app = n;
9616 app = &n->narg.next;
9617 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009618 }
9619 break;
9620 case TREDIR:
9621 *rpp = n = redirnode;
9622 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009623 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009624 break;
9625 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009626 if (
9627 args && app == &args->narg.next &&
9628 !vars && !redir
9629 ) {
9630 struct builtincmd *bcmd;
9631 const char *name;
9632
Eric Andersencb57d552001-06-28 07:25:16 +00009633 /* We have a function */
9634 if (readtoken() != TRP)
9635 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009636 name = n->narg.text;
9637 if (
9638 !goodname(name) || (
9639 (bcmd = find_builtin(name)) &&
9640 IS_BUILTIN_SPECIAL(bcmd)
9641 )
9642 )
9643 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009644 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009645 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009646 n->narg.next = command();
9647 return n;
9648 }
9649 /* fall through */
9650 default:
9651 tokpushback++;
9652 goto out;
9653 }
9654 }
Eric Andersenc470f442003-07-28 09:56:35 +00009655out:
Eric Andersencb57d552001-06-28 07:25:16 +00009656 *app = NULL;
9657 *vpp = NULL;
9658 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009659 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009660 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009661 n->ncmd.args = args;
9662 n->ncmd.assign = vars;
9663 n->ncmd.redirect = redir;
9664 return n;
9665}
9666
Eric Andersenc470f442003-07-28 09:56:35 +00009667static union node *
9668makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009669{
Eric Andersencb57d552001-06-28 07:25:16 +00009670 union node *n;
9671
Eric Andersenc470f442003-07-28 09:56:35 +00009672 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009673 n->type = NARG;
9674 n->narg.next = NULL;
9675 n->narg.text = wordtext;
9676 n->narg.backquote = backquotelist;
9677 return n;
9678}
9679
Eric Andersenc470f442003-07-28 09:56:35 +00009680void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009681{
Eric Andersencb57d552001-06-28 07:25:16 +00009682 TRACE(("Fix redir %s %d\n", text, err));
9683 if (!err)
9684 n->ndup.vname = NULL;
9685
9686 if (is_digit(text[0]) && text[1] == '\0')
9687 n->ndup.dupfd = digit_val(text[0]);
9688 else if (text[0] == '-' && text[1] == '\0')
9689 n->ndup.dupfd = -1;
9690 else {
9691
9692 if (err)
9693 synerror("Bad fd number");
9694 else
9695 n->ndup.vname = makename();
9696 }
9697}
9698
9699
Eric Andersenc470f442003-07-28 09:56:35 +00009700static void
9701parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009702{
Eric Andersencb57d552001-06-28 07:25:16 +00009703 union node *n = redirnode;
9704
9705 if (readtoken() != TWORD)
9706 synexpect(-1);
9707 if (n->type == NHERE) {
9708 struct heredoc *here = heredoc;
9709 struct heredoc *p;
9710 int i;
9711
9712 if (quoteflag == 0)
9713 n->type = NXHERE;
9714 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009715 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009716 synerror("Illegal eof marker for << redirection");
9717 rmescapes(wordtext);
9718 here->eofmark = wordtext;
9719 here->next = NULL;
9720 if (heredoclist == NULL)
9721 heredoclist = here;
9722 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009723 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009724 p->next = here;
9725 }
9726 } else if (n->type == NTOFD || n->type == NFROMFD) {
9727 fixredir(n, wordtext, 0);
9728 } else {
9729 n->nfile.fname = makename();
9730 }
9731}
9732
9733
9734/*
9735 * Input any here documents.
9736 */
9737
Eric Andersenc470f442003-07-28 09:56:35 +00009738static void
9739parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009740{
Eric Andersencb57d552001-06-28 07:25:16 +00009741 struct heredoc *here;
9742 union node *n;
9743
Eric Andersenc470f442003-07-28 09:56:35 +00009744 here = heredoclist;
9745 heredoclist = 0;
9746
9747 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009748 if (needprompt) {
9749 setprompt(2);
9750 needprompt = 0;
9751 }
Eric Andersenc470f442003-07-28 09:56:35 +00009752 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9753 here->eofmark, here->striptabs);
9754 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009755 n->narg.type = NARG;
9756 n->narg.next = NULL;
9757 n->narg.text = wordtext;
9758 n->narg.backquote = backquotelist;
9759 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009760 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009761 }
9762}
9763
Eric Andersenc470f442003-07-28 09:56:35 +00009764static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009765{
Eric Andersencb57d552001-06-28 07:25:16 +00009766 int t;
9767
9768 t = readtoken();
9769 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009770 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009771}
9772
Eric Andersenc470f442003-07-28 09:56:35 +00009773static int
9774readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009775{
Eric Andersencb57d552001-06-28 07:25:16 +00009776 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009777#ifdef DEBUG
9778 int alreadyseen = tokpushback;
9779#endif
9780
Eric Andersend35c5df2002-01-09 15:37:36 +00009781#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009782top:
Eric Andersen2870d962001-07-02 17:27:21 +00009783#endif
9784
Eric Andersencb57d552001-06-28 07:25:16 +00009785 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009786
Eric Andersenc470f442003-07-28 09:56:35 +00009787 /*
9788 * eat newlines
9789 */
9790 if (checkkwd & CHKNL) {
9791 while (t == TNL) {
9792 parseheredoc();
9793 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009794 }
9795 }
9796
Eric Andersenc470f442003-07-28 09:56:35 +00009797 if (t != TWORD || quoteflag) {
9798 goto out;
9799 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009800
Eric Andersenc470f442003-07-28 09:56:35 +00009801 /*
9802 * check for keywords
9803 */
9804 if (checkkwd & CHKKWD) {
9805 const char *const *pp;
9806
9807 if ((pp = findkwd(wordtext))) {
9808 lasttoken = t = pp - tokname_array;
9809 TRACE(("keyword %s recognized\n", tokname(t)));
9810 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009811 }
Eric Andersenc470f442003-07-28 09:56:35 +00009812 }
9813
9814 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009815#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009816 struct alias *ap;
9817 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009818 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009819 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009820 }
Eric Andersencb57d552001-06-28 07:25:16 +00009821 goto top;
9822 }
Eric Andersen2870d962001-07-02 17:27:21 +00009823#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009824 }
Eric Andersenc470f442003-07-28 09:56:35 +00009825out:
9826 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009827#ifdef DEBUG
9828 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009829 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009830 else
Eric Andersenc470f442003-07-28 09:56:35 +00009831 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009832#endif
9833 return (t);
9834}
9835
9836
9837/*
9838 * Read the next input token.
9839 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009840 * backquotes. We set quoteflag to true if any part of the word was
9841 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009842 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009843 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009844 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009845 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009846 *
9847 * [Change comment: here documents and internal procedures]
9848 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9849 * word parsing code into a separate routine. In this case, readtoken
9850 * doesn't need to have any internal procedures, but parseword does.
9851 * We could also make parseoperator in essence the main routine, and
9852 * have parseword (readtoken1?) handle both words and redirection.]
9853 */
9854
Eric Andersen81fe1232003-07-29 06:38:40 +00009855#define NEW_xxreadtoken
9856#ifdef NEW_xxreadtoken
9857
9858/* singles must be first! */
9859static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9860
9861static const char xxreadtoken_tokens[] = {
9862 TNL, TLP, TRP, /* only single occurrence allowed */
9863 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9864 TEOF, /* corresponds to trailing nul */
9865 TAND, TOR, TENDCASE, /* if double occurrence */
9866};
9867
9868#define xxreadtoken_doubles \
9869 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9870#define xxreadtoken_singles \
9871 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9872
9873static int xxreadtoken()
9874{
9875 int c;
9876
9877 if (tokpushback) {
9878 tokpushback = 0;
9879 return lasttoken;
9880 }
9881 if (needprompt) {
9882 setprompt(2);
9883 needprompt = 0;
9884 }
9885 startlinno = plinno;
9886 for (;;) { /* until token or start of word found */
9887 c = pgetc_macro();
9888
9889 if ((c != ' ') && (c != '\t')
9890#ifdef CONFIG_ASH_ALIAS
9891 && (c != PEOA)
9892#endif
9893 ) {
9894 if (c == '#') {
9895 while ((c = pgetc()) != '\n' && c != PEOF);
9896 pungetc();
9897 } else if (c == '\\') {
9898 if (pgetc() != '\n') {
9899 pungetc();
9900 goto READTOKEN1;
9901 }
9902 startlinno = ++plinno;
9903 if (doprompt)
9904 setprompt(2);
9905 } else {
9906 const char *p
9907 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9908
9909 if (c != PEOF) {
9910 if (c == '\n') {
9911 plinno++;
9912 needprompt = doprompt;
9913 }
9914
9915 p = strchr(xxreadtoken_chars, c);
9916 if (p == NULL) {
9917 READTOKEN1:
9918 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
9919 }
9920
9921 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9922 if (pgetc() == *p) { /* double occurrence? */
9923 p += xxreadtoken_doubles + 1;
9924 } else {
9925 pungetc();
9926 }
9927 }
9928 }
9929
9930 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
9931 }
9932 }
9933 }
9934}
9935
9936
9937#else
Eric Andersen2870d962001-07-02 17:27:21 +00009938#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +00009939
Eric Andersenc470f442003-07-28 09:56:35 +00009940static int
9941xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009942{
Eric Andersencb57d552001-06-28 07:25:16 +00009943 int c;
9944
9945 if (tokpushback) {
9946 tokpushback = 0;
9947 return lasttoken;
9948 }
9949 if (needprompt) {
9950 setprompt(2);
9951 needprompt = 0;
9952 }
9953 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00009954 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +00009955 c = pgetc_macro();
9956 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00009957 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +00009958#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00009959 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +00009960#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009961 continue;
9962 case '#':
9963 while ((c = pgetc()) != '\n' && c != PEOF);
9964 pungetc();
9965 continue;
9966 case '\\':
9967 if (pgetc() == '\n') {
9968 startlinno = ++plinno;
9969 if (doprompt)
9970 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009971 continue;
9972 }
9973 pungetc();
9974 goto breakloop;
9975 case '\n':
9976 plinno++;
9977 needprompt = doprompt;
9978 RETURN(TNL);
9979 case PEOF:
9980 RETURN(TEOF);
9981 case '&':
9982 if (pgetc() == '&')
9983 RETURN(TAND);
9984 pungetc();
9985 RETURN(TBACKGND);
9986 case '|':
9987 if (pgetc() == '|')
9988 RETURN(TOR);
9989 pungetc();
9990 RETURN(TPIPE);
9991 case ';':
9992 if (pgetc() == ';')
9993 RETURN(TENDCASE);
9994 pungetc();
9995 RETURN(TSEMI);
9996 case '(':
9997 RETURN(TLP);
9998 case ')':
9999 RETURN(TRP);
10000 default:
10001 goto breakloop;
10002 }
10003 }
Eric Andersenc470f442003-07-28 09:56:35 +000010004breakloop:
10005 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010006#undef RETURN
10007}
Eric Andersen81fe1232003-07-29 06:38:40 +000010008#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010009
Eric Andersencb57d552001-06-28 07:25:16 +000010010
Eric Andersencb57d552001-06-28 07:25:16 +000010011/*
10012 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10013 * is not NULL, read a here document. In the latter case, eofmark is the
10014 * word which marks the end of the document and striptabs is true if
10015 * leading tabs should be stripped from the document. The argument firstc
10016 * is the first character of the input token or document.
10017 *
10018 * Because C does not have internal subroutines, I have simulated them
10019 * using goto's to implement the subroutine linkage. The following macros
10020 * will run code that appears at the end of readtoken1.
10021 */
10022
Eric Andersen2870d962001-07-02 17:27:21 +000010023#define CHECKEND() {goto checkend; checkend_return:;}
10024#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10025#define PARSESUB() {goto parsesub; parsesub_return:;}
10026#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10027#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10028#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010029
10030static int
Eric Andersenc470f442003-07-28 09:56:35 +000010031readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010032{
Eric Andersencb57d552001-06-28 07:25:16 +000010033 int c = firstc;
10034 char *out;
10035 int len;
10036 char line[EOFMARKLEN + 1];
10037 struct nodelist *bqlist;
10038 int quotef;
10039 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010040 int varnest; /* levels of variables expansion */
10041 int arinest; /* levels of arithmetic expansion */
10042 int parenlevel; /* levels of parens in arithmetic */
10043 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010044 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010045 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010046#if __GNUC__
10047 /* Avoid longjmp clobbering */
10048 (void) &out;
10049 (void) &quotef;
10050 (void) &dblquote;
10051 (void) &varnest;
10052 (void) &arinest;
10053 (void) &parenlevel;
10054 (void) &dqvarnest;
10055 (void) &oldstyle;
10056 (void) &prevsyntax;
10057 (void) &syntax;
10058#endif
10059
10060 startlinno = plinno;
10061 dblquote = 0;
10062 if (syntax == DQSYNTAX)
10063 dblquote = 1;
10064 quotef = 0;
10065 bqlist = NULL;
10066 varnest = 0;
10067 arinest = 0;
10068 parenlevel = 0;
10069 dqvarnest = 0;
10070
10071 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010072 loop: { /* for each line, until end of word */
10073 CHECKEND(); /* set c to PEOF if at end of here document */
10074 for (;;) { /* until end of line or end of word */
10075 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10076 switch(SIT(c, syntax)) {
10077 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010078 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010079 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010080 USTPUTC(c, out);
10081 plinno++;
10082 if (doprompt)
10083 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010084 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010085 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010086 case CWORD:
10087 USTPUTC(c, out);
10088 break;
10089 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010090 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010091 USTPUTC(CTLESC, out);
10092 USTPUTC(c, out);
10093 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010094 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010095 c = pgetc2();
10096 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010097 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010098 USTPUTC('\\', out);
10099 pungetc();
10100 } else if (c == '\n') {
10101 if (doprompt)
10102 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010103 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010104 if (
10105 dblquote &&
10106 c != '\\' && c != '`' &&
10107 c != '$' && (
10108 c != '"' ||
10109 eofmark != NULL
10110 )
10111 ) {
10112 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010113 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010114 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010115 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010116 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010117 USTPUTC(c, out);
10118 quotef++;
10119 }
10120 break;
10121 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010122 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010123quotemark:
10124 if (eofmark == NULL) {
10125 USTPUTC(CTLQUOTEMARK, out);
10126 }
Eric Andersencb57d552001-06-28 07:25:16 +000010127 break;
10128 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010129 syntax = DQSYNTAX;
10130 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010131 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010132 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010133 if (eofmark != NULL && arinest == 0 &&
10134 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010135 USTPUTC(c, out);
10136 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010137 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010138 syntax = BASESYNTAX;
10139 dblquote = 0;
10140 }
10141 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010142 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010143 }
10144 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010145 case CVAR: /* '$' */
10146 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010147 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010148 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010149 if (varnest > 0) {
10150 varnest--;
10151 if (dqvarnest > 0) {
10152 dqvarnest--;
10153 }
10154 USTPUTC(CTLENDVAR, out);
10155 } else {
10156 USTPUTC(c, out);
10157 }
10158 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010159#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010160 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010161 parenlevel++;
10162 USTPUTC(c, out);
10163 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010164 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010165 if (parenlevel > 0) {
10166 USTPUTC(c, out);
10167 --parenlevel;
10168 } else {
10169 if (pgetc() == ')') {
10170 if (--arinest == 0) {
10171 USTPUTC(CTLENDARI, out);
10172 syntax = prevsyntax;
10173 if (syntax == DQSYNTAX)
10174 dblquote = 1;
10175 else
10176 dblquote = 0;
10177 } else
10178 USTPUTC(')', out);
10179 } else {
10180 /*
10181 * unbalanced parens
10182 * (don't 2nd guess - no error)
10183 */
10184 pungetc();
10185 USTPUTC(')', out);
10186 }
10187 }
10188 break;
10189#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010190 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010191 PARSEBACKQOLD();
10192 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010193 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010194 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010195 case CIGN:
10196 break;
10197 default:
10198 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010199 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010200#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010201 if (c != PEOA)
10202#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010203 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010204
Eric Andersencb57d552001-06-28 07:25:16 +000010205 }
10206 c = pgetc_macro();
10207 }
10208 }
Eric Andersenc470f442003-07-28 09:56:35 +000010209endword:
10210#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010211 if (syntax == ARISYNTAX)
10212 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010213#endif
10214 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010215 synerror("Unterminated quoted string");
10216 if (varnest != 0) {
10217 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010218 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010219 synerror("Missing '}'");
10220 }
10221 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010222 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010223 out = stackblock();
10224 if (eofmark == NULL) {
10225 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010226 && quotef == 0
10227 && len <= 2
10228 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010229 PARSEREDIR();
10230 return lasttoken = TREDIR;
10231 } else {
10232 pungetc();
10233 }
10234 }
10235 quoteflag = quotef;
10236 backquotelist = bqlist;
10237 grabstackblock(len);
10238 wordtext = out;
10239 return lasttoken = TWORD;
10240/* end of readtoken routine */
10241
10242
10243
10244/*
10245 * Check to see whether we are at the end of the here document. When this
10246 * is called, c is set to the first character of the next input line. If
10247 * we are at the end of the here document, this routine sets the c to PEOF.
10248 */
10249
Eric Andersenc470f442003-07-28 09:56:35 +000010250checkend: {
10251 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010252#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010253 if (c == PEOA) {
10254 c = pgetc2();
10255 }
10256#endif
10257 if (striptabs) {
10258 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010259 c = pgetc2();
10260 }
Eric Andersenc470f442003-07-28 09:56:35 +000010261 }
10262 if (c == *eofmark) {
10263 if (pfgets(line, sizeof line) != NULL) {
10264 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010265
Eric Andersenc470f442003-07-28 09:56:35 +000010266 p = line;
10267 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10268 if (*p == '\n' && *q == '\0') {
10269 c = PEOF;
10270 plinno++;
10271 needprompt = doprompt;
10272 } else {
10273 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010274 }
10275 }
10276 }
10277 }
Eric Andersenc470f442003-07-28 09:56:35 +000010278 goto checkend_return;
10279}
Eric Andersencb57d552001-06-28 07:25:16 +000010280
10281
10282/*
10283 * Parse a redirection operator. The variable "out" points to a string
10284 * specifying the fd to be redirected. The variable "c" contains the
10285 * first character of the redirection operator.
10286 */
10287
Eric Andersenc470f442003-07-28 09:56:35 +000010288parseredir: {
10289 char fd = *out;
10290 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010291
Eric Andersenc470f442003-07-28 09:56:35 +000010292 np = (union node *)stalloc(sizeof (struct nfile));
10293 if (c == '>') {
10294 np->nfile.fd = 1;
10295 c = pgetc();
10296 if (c == '>')
10297 np->type = NAPPEND;
10298 else if (c == '|')
10299 np->type = NCLOBBER;
10300 else if (c == '&')
10301 np->type = NTOFD;
10302 else {
10303 np->type = NTO;
10304 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010305 }
Eric Andersenc470f442003-07-28 09:56:35 +000010306 } else { /* c == '<' */
10307 np->nfile.fd = 0;
10308 switch (c = pgetc()) {
10309 case '<':
10310 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10311 np = (union node *)stalloc(sizeof (struct nhere));
10312 np->nfile.fd = 0;
10313 }
10314 np->type = NHERE;
10315 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10316 heredoc->here = np;
10317 if ((c = pgetc()) == '-') {
10318 heredoc->striptabs = 1;
10319 } else {
10320 heredoc->striptabs = 0;
10321 pungetc();
10322 }
10323 break;
10324
10325 case '&':
10326 np->type = NFROMFD;
10327 break;
10328
10329 case '>':
10330 np->type = NFROMTO;
10331 break;
10332
10333 default:
10334 np->type = NFROM;
10335 pungetc();
10336 break;
10337 }
Eric Andersencb57d552001-06-28 07:25:16 +000010338 }
Eric Andersenc470f442003-07-28 09:56:35 +000010339 if (fd != '\0')
10340 np->nfile.fd = digit_val(fd);
10341 redirnode = np;
10342 goto parseredir_return;
10343}
Eric Andersencb57d552001-06-28 07:25:16 +000010344
10345
10346/*
10347 * Parse a substitution. At this point, we have read the dollar sign
10348 * and nothing else.
10349 */
10350
Eric Andersenc470f442003-07-28 09:56:35 +000010351parsesub: {
10352 int subtype;
10353 int typeloc;
10354 int flags;
10355 char *p;
10356 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010357
Eric Andersenc470f442003-07-28 09:56:35 +000010358 c = pgetc();
10359 if (
10360 c <= PEOA_OR_PEOF ||
10361 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10362 ) {
10363 USTPUTC('$', out);
10364 pungetc();
10365 } else if (c == '(') { /* $(command) or $((arith)) */
10366 if (pgetc() == '(') {
10367#ifdef CONFIG_ASH_MATH_SUPPORT
10368 PARSEARITH();
10369#else
10370 synerror("We unsupport $((arith))");
10371#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010372 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010373 pungetc();
10374 PARSEBACKQNEW();
10375 }
10376 } else {
10377 USTPUTC(CTLVAR, out);
10378 typeloc = out - (char *)stackblock();
10379 USTPUTC(VSNORMAL, out);
10380 subtype = VSNORMAL;
10381 if (c == '{') {
10382 c = pgetc();
10383 if (c == '#') {
10384 if ((c = pgetc()) == '}')
10385 c = '#';
10386 else
10387 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010388 }
Eric Andersenc470f442003-07-28 09:56:35 +000010389 else
10390 subtype = 0;
10391 }
10392 if (c > PEOA_OR_PEOF && is_name(c)) {
10393 do {
10394 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010395 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010396 } while (c > PEOA_OR_PEOF && is_in_name(c));
10397 } else if (is_digit(c)) {
10398 do {
10399 STPUTC(c, out);
10400 c = pgetc();
10401 } while (is_digit(c));
10402 }
10403 else if (is_special(c)) {
10404 USTPUTC(c, out);
10405 c = pgetc();
10406 }
10407 else
10408badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010409
Eric Andersenc470f442003-07-28 09:56:35 +000010410 STPUTC('=', out);
10411 flags = 0;
10412 if (subtype == 0) {
10413 switch (c) {
10414 case ':':
10415 flags = VSNUL;
10416 c = pgetc();
10417 /*FALLTHROUGH*/
10418 default:
10419 p = strchr(types, c);
10420 if (p == NULL)
10421 goto badsub;
10422 subtype = p - types + VSNORMAL;
10423 break;
10424 case '%':
10425 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010426 {
10427 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010428 subtype = c == '#' ? VSTRIMLEFT :
10429 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010430 c = pgetc();
10431 if (c == cc)
10432 subtype++;
10433 else
10434 pungetc();
10435 break;
10436 }
10437 }
Eric Andersenc470f442003-07-28 09:56:35 +000010438 } else {
10439 pungetc();
10440 }
10441 if (dblquote || arinest)
10442 flags |= VSQUOTE;
10443 *((char *)stackblock() + typeloc) = subtype | flags;
10444 if (subtype != VSNORMAL) {
10445 varnest++;
10446 if (dblquote || arinest) {
10447 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010448 }
10449 }
10450 }
Eric Andersenc470f442003-07-28 09:56:35 +000010451 goto parsesub_return;
10452}
Eric Andersencb57d552001-06-28 07:25:16 +000010453
10454
10455/*
10456 * Called to parse command substitutions. Newstyle is set if the command
10457 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10458 * list of commands (passed by reference), and savelen is the number of
10459 * characters on the top of the stack which must be preserved.
10460 */
10461
Eric Andersenc470f442003-07-28 09:56:35 +000010462parsebackq: {
10463 struct nodelist **nlpp;
10464 int savepbq;
10465 union node *n;
10466 char *volatile str;
10467 struct jmploc jmploc;
10468 struct jmploc *volatile savehandler;
10469 size_t savelen;
10470 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010471#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010472 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010473#endif
10474
Eric Andersenc470f442003-07-28 09:56:35 +000010475 savepbq = parsebackquote;
10476 if (setjmp(jmploc.loc)) {
10477 if (str)
10478 ckfree(str);
10479 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010480 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010481 longjmp(handler->loc, 1);
10482 }
10483 INTOFF;
10484 str = NULL;
10485 savelen = out - (char *)stackblock();
10486 if (savelen > 0) {
10487 str = ckmalloc(savelen);
10488 memcpy(str, stackblock(), savelen);
10489 }
10490 savehandler = handler;
10491 handler = &jmploc;
10492 INTON;
10493 if (oldstyle) {
10494 /* We must read until the closing backquote, giving special
10495 treatment to some slashes, and then push the string and
10496 reread it as input, interpreting it normally. */
10497 char *pout;
10498 int pc;
10499 size_t psavelen;
10500 char *pstr;
10501
10502
10503 STARTSTACKSTR(pout);
10504 for (;;) {
10505 if (needprompt) {
10506 setprompt(2);
10507 needprompt = 0;
10508 }
10509 switch (pc = pgetc()) {
10510 case '`':
10511 goto done;
10512
10513 case '\\':
10514 if ((pc = pgetc()) == '\n') {
10515 plinno++;
10516 if (doprompt)
10517 setprompt(2);
10518 /*
10519 * If eating a newline, avoid putting
10520 * the newline into the new character
10521 * stream (via the STPUTC after the
10522 * switch).
10523 */
10524 continue;
10525 }
10526 if (pc != '\\' && pc != '`' && pc != '$'
10527 && (!dblquote || pc != '"'))
10528 STPUTC('\\', pout);
10529 if (pc > PEOA_OR_PEOF) {
10530 break;
10531 }
10532 /* fall through */
10533
10534 case PEOF:
10535#ifdef CONFIG_ASH_ALIAS
10536 case PEOA:
10537#endif
10538 startlinno = plinno;
10539 synerror("EOF in backquote substitution");
10540
10541 case '\n':
10542 plinno++;
10543 needprompt = doprompt;
10544 break;
10545
10546 default:
10547 break;
10548 }
10549 STPUTC(pc, pout);
10550 }
10551done:
10552 STPUTC('\0', pout);
10553 psavelen = pout - (char *)stackblock();
10554 if (psavelen > 0) {
10555 pstr = grabstackstr(pout);
10556 setinputstring(pstr);
10557 }
10558 }
10559 nlpp = &bqlist;
10560 while (*nlpp)
10561 nlpp = &(*nlpp)->next;
10562 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10563 (*nlpp)->next = NULL;
10564 parsebackquote = oldstyle;
10565
10566 if (oldstyle) {
10567 saveprompt = doprompt;
10568 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010569 }
10570
Eric Andersenc470f442003-07-28 09:56:35 +000010571 n = list(2);
10572
10573 if (oldstyle)
10574 doprompt = saveprompt;
10575 else {
10576 if (readtoken() != TRP)
10577 synexpect(TRP);
10578 }
10579
10580 (*nlpp)->n = n;
10581 if (oldstyle) {
10582 /*
10583 * Start reading from old file again, ignoring any pushed back
10584 * tokens left from the backquote parsing
10585 */
10586 popfile();
10587 tokpushback = 0;
10588 }
10589 while (stackblocksize() <= savelen)
10590 growstackblock();
10591 STARTSTACKSTR(out);
10592 if (str) {
10593 memcpy(out, str, savelen);
10594 STADJUST(savelen, out);
10595 INTOFF;
10596 ckfree(str);
10597 str = NULL;
10598 INTON;
10599 }
10600 parsebackquote = savepbq;
10601 handler = savehandler;
10602 if (arinest || dblquote)
10603 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10604 else
10605 USTPUTC(CTLBACKQ, out);
10606 if (oldstyle)
10607 goto parsebackq_oldreturn;
10608 else
10609 goto parsebackq_newreturn;
10610}
10611
10612#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010613/*
10614 * Parse an arithmetic expansion (indicate start of one and set state)
10615 */
Eric Andersenc470f442003-07-28 09:56:35 +000010616parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010617
Eric Andersenc470f442003-07-28 09:56:35 +000010618 if (++arinest == 1) {
10619 prevsyntax = syntax;
10620 syntax = ARISYNTAX;
10621 USTPUTC(CTLARI, out);
10622 if (dblquote)
10623 USTPUTC('"',out);
10624 else
10625 USTPUTC(' ',out);
10626 } else {
10627 /*
10628 * we collapse embedded arithmetic expansion to
10629 * parenthesis, which should be equivalent
10630 */
10631 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010632 }
Eric Andersenc470f442003-07-28 09:56:35 +000010633 goto parsearith_return;
10634}
10635#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010636
Eric Andersenc470f442003-07-28 09:56:35 +000010637} /* end of readtoken */
10638
Eric Andersencb57d552001-06-28 07:25:16 +000010639
10640
Eric Andersencb57d552001-06-28 07:25:16 +000010641/*
10642 * Returns true if the text contains nothing to expand (no dollar signs
10643 * or backquotes).
10644 */
10645
Eric Andersenc470f442003-07-28 09:56:35 +000010646static int
10647noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010648{
Eric Andersencb57d552001-06-28 07:25:16 +000010649 char *p;
10650 char c;
10651
10652 p = text;
10653 while ((c = *p++) != '\0') {
10654 if (c == CTLQUOTEMARK)
10655 continue;
10656 if (c == CTLESC)
10657 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010658 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010659 return 0;
10660 }
10661 return 1;
10662}
10663
10664
10665/*
Eric Andersenc470f442003-07-28 09:56:35 +000010666 * Return of a legal variable name (a letter or underscore followed by zero or
10667 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010668 */
10669
Eric Andersenc470f442003-07-28 09:56:35 +000010670char *
10671endofname(const char *name)
10672 {
10673 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010674
Eric Andersenc470f442003-07-28 09:56:35 +000010675 p = (char *) name;
10676 if (! is_name(*p))
10677 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010678 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010679 if (! is_in_name(*p))
10680 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010681 }
Eric Andersenc470f442003-07-28 09:56:35 +000010682 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010683}
10684
10685
10686/*
10687 * Called when an unexpected token is read during the parse. The argument
10688 * is the token that is expected, or -1 if more than one type of token can
10689 * occur at this point.
10690 */
10691
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010692static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010693{
10694 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010695 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010696
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010697 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10698 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010699 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010700 synerror(msg);
10701 /* NOTREACHED */
10702}
10703
Eric Andersenc470f442003-07-28 09:56:35 +000010704static void
10705synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010706{
Eric Andersenc470f442003-07-28 09:56:35 +000010707 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010708 /* NOTREACHED */
10709}
10710
Eric Andersencb57d552001-06-28 07:25:16 +000010711
10712/*
10713 * called by editline -- any expansions to the prompt
10714 * should be added here.
10715 */
Eric Andersenc470f442003-07-28 09:56:35 +000010716
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010717static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010718{
Eric Andersenc470f442003-07-28 09:56:35 +000010719 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010720
10721 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010722 case 1:
10723 prompt = ps1val();
10724 break;
10725 case 2:
10726 prompt = ps2val();
10727 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010728 default: /* 0 */
10729 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010730 }
10731 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010732}
10733
Eric Andersencb57d552001-06-28 07:25:16 +000010734
Eric Andersenc470f442003-07-28 09:56:35 +000010735static const char *const *findkwd(const char *s)
10736{
10737 return bsearch(s, tokname_array + KWDOFFSET,
10738 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10739 sizeof(const char *), pstrcmp);
10740}
10741
10742/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10743
Eric Andersencb57d552001-06-28 07:25:16 +000010744/*
10745 * Code for dealing with input/output redirection.
10746 */
10747
Eric Andersenc470f442003-07-28 09:56:35 +000010748#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010749#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010750# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010751#else
10752# define PIPESIZE PIPE_BUF
10753#endif
10754
Eric Andersen62483552001-07-10 06:09:16 +000010755/*
10756 * Open a file in noclobber mode.
10757 * The code was copied from bash.
10758 */
Eric Andersenc470f442003-07-28 09:56:35 +000010759static inline int
10760noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010761{
10762 int r, fd;
10763 struct stat finfo, finfo2;
10764
10765 /*
10766 * If the file exists and is a regular file, return an error
10767 * immediately.
10768 */
10769 r = stat(fname, &finfo);
10770 if (r == 0 && S_ISREG(finfo.st_mode)) {
10771 errno = EEXIST;
10772 return -1;
10773 }
10774
10775 /*
10776 * If the file was not present (r != 0), make sure we open it
10777 * exclusively so that if it is created before we open it, our open
10778 * will fail. Make sure that we do not truncate an existing file.
10779 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10780 * file was not a regular file, we leave O_EXCL off.
10781 */
10782 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010783 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10784 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010785
10786 /* If the open failed, return the file descriptor right away. */
10787 if (fd < 0)
10788 return fd;
10789
10790 /*
10791 * OK, the open succeeded, but the file may have been changed from a
10792 * non-regular file to a regular file between the stat and the open.
10793 * We are assuming that the O_EXCL open handles the case where FILENAME
10794 * did not exist and is symlinked to an existing file between the stat
10795 * and open.
10796 */
10797
10798 /*
10799 * If we can open it and fstat the file descriptor, and neither check
10800 * revealed that it was a regular file, and the file has not been
10801 * replaced, return the file descriptor.
10802 */
Eric Andersenc470f442003-07-28 09:56:35 +000010803 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10804 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010805 return fd;
10806
10807 /* The file has been replaced. badness. */
10808 close(fd);
10809 errno = EEXIST;
10810 return -1;
10811}
Eric Andersencb57d552001-06-28 07:25:16 +000010812
10813/*
Eric Andersen62483552001-07-10 06:09:16 +000010814 * Handle here documents. Normally we fork off a process to write the
10815 * data to a pipe. If the document is short, we can stuff the data in
10816 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010817 */
10818
Eric Andersenc470f442003-07-28 09:56:35 +000010819static inline int
10820openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010821{
10822 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010823 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010824
Eric Andersen62483552001-07-10 06:09:16 +000010825 if (pipe(pip) < 0)
10826 error("Pipe call failed");
10827 if (redir->type == NHERE) {
10828 len = strlen(redir->nhere.doc->narg.text);
10829 if (len <= PIPESIZE) {
10830 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10831 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010832 }
Eric Andersencb57d552001-06-28 07:25:16 +000010833 }
Eric Andersenc470f442003-07-28 09:56:35 +000010834 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010835 close(pip[0]);
10836 signal(SIGINT, SIG_IGN);
10837 signal(SIGQUIT, SIG_IGN);
10838 signal(SIGHUP, SIG_IGN);
10839#ifdef SIGTSTP
10840 signal(SIGTSTP, SIG_IGN);
10841#endif
10842 signal(SIGPIPE, SIG_DFL);
10843 if (redir->type == NHERE)
10844 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10845 else
10846 expandhere(redir->nhere.doc, pip[1]);
10847 _exit(0);
10848 }
Eric Andersenc470f442003-07-28 09:56:35 +000010849out:
Eric Andersen62483552001-07-10 06:09:16 +000010850 close(pip[1]);
10851 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010852}
10853
Eric Andersenc470f442003-07-28 09:56:35 +000010854static int
10855openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010856{
Eric Andersencb57d552001-06-28 07:25:16 +000010857 char *fname;
10858 int f;
10859
10860 switch (redir->nfile.type) {
10861 case NFROM:
10862 fname = redir->nfile.expfname;
10863 if ((f = open(fname, O_RDONLY)) < 0)
10864 goto eopen;
10865 break;
10866 case NFROMTO:
10867 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010868 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010869 goto ecreate;
10870 break;
10871 case NTO:
10872 /* Take care of noclobber mode. */
10873 if (Cflag) {
10874 fname = redir->nfile.expfname;
10875 if ((f = noclobberopen(fname)) < 0)
10876 goto ecreate;
10877 break;
10878 }
Eric Andersenc470f442003-07-28 09:56:35 +000010879 /* FALLTHROUGH */
10880 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000010881 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010882 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010883 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010884 break;
10885 case NAPPEND:
10886 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010887 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010888 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010889 break;
10890 default:
10891#ifdef DEBUG
10892 abort();
10893#endif
10894 /* Fall through to eliminate warning. */
10895 case NTOFD:
10896 case NFROMFD:
10897 f = -1;
10898 break;
10899 case NHERE:
10900 case NXHERE:
10901 f = openhere(redir);
10902 break;
10903 }
10904
10905 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000010906ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000010907 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000010908eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000010909 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10910}
10911
Eric Andersenc470f442003-07-28 09:56:35 +000010912static inline void
10913dupredirect(union node *redir, int f)
10914{
10915 int fd = redir->nfile.fd;
10916
10917 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
10918 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10919 copyfd(redir->ndup.dupfd, fd);
10920 }
10921 return;
10922 }
10923
10924 if (f != fd) {
10925 copyfd(f, fd);
10926 close(f);
10927 }
10928 return;
10929}
Eric Andersencb57d552001-06-28 07:25:16 +000010930
Eric Andersen62483552001-07-10 06:09:16 +000010931/*
10932 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10933 * old file descriptors are stashed away so that the redirection can be
10934 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10935 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000010936 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000010937 */
10938
Eric Andersenc470f442003-07-28 09:56:35 +000010939static void
10940redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000010941{
10942 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000010943 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000010944 int i;
Eric Andersen62483552001-07-10 06:09:16 +000010945 int fd;
10946 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000010947 int *p;
10948 nullredirs++;
10949 if (!redir) {
10950 return;
Eric Andersen62483552001-07-10 06:09:16 +000010951 }
Eric Andersenc470f442003-07-28 09:56:35 +000010952 sv = NULL;
10953 INTOFF;
10954 if (flags & REDIR_PUSH) {
10955 struct redirtab *q;
10956 q = ckmalloc(sizeof (struct redirtab));
10957 q->next = redirlist;
10958 redirlist = q;
10959 q->nullredirs = nullredirs - 1;
10960 for (i = 0 ; i < 10 ; i++)
10961 q->renamed[i] = EMPTY;
10962 nullredirs = 0;
10963 sv = q;
10964 }
10965 n = redir;
10966 do {
Eric Andersen62483552001-07-10 06:09:16 +000010967 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000010968 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000010969 n->ndup.dupfd == fd)
10970 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000010971
Eric Andersen62483552001-07-10 06:09:16 +000010972 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000010973 if (fd == newfd)
10974 continue;
10975 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
10976 i = fcntl(fd, F_DUPFD, 10);
10977
10978 if (i == -1) {
10979 i = errno;
10980 if (i != EBADF) {
10981 close(newfd);
10982 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000010983 error("%d: %m", fd);
10984 /* NOTREACHED */
10985 }
Eric Andersenc470f442003-07-28 09:56:35 +000010986 } else {
10987 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000010988 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000010989 }
Eric Andersenc470f442003-07-28 09:56:35 +000010990 } else {
Eric Andersen62483552001-07-10 06:09:16 +000010991 close(fd);
10992 }
Eric Andersenc470f442003-07-28 09:56:35 +000010993 dupredirect(n, newfd);
10994 } while ((n = n->nfile.next));
10995 INTON;
Eric Andersen62483552001-07-10 06:09:16 +000010996}
10997
10998
Eric Andersencb57d552001-06-28 07:25:16 +000010999/*
11000 * Undo the effects of the last redirection.
11001 */
11002
Eric Andersenc470f442003-07-28 09:56:35 +000011003void
11004popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011005{
Eric Andersenc470f442003-07-28 09:56:35 +000011006 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011007 int i;
11008
Eric Andersenc470f442003-07-28 09:56:35 +000011009 if (--nullredirs >= 0)
11010 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011011 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011012 rp = redirlist;
11013 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011014 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011015 if (!drop) {
11016 close(i);
11017 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011018 }
Eric Andersenc470f442003-07-28 09:56:35 +000011019 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011020 }
11021 }
11022 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011023 nullredirs = rp->nullredirs;
11024 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011025 INTON;
11026}
11027
11028/*
Eric Andersenc470f442003-07-28 09:56:35 +000011029 * Undo all redirections. Called on error or interrupt.
11030 */
11031
11032/*
Eric Andersencb57d552001-06-28 07:25:16 +000011033 * Discard all saved file descriptors.
11034 */
11035
Eric Andersenc470f442003-07-28 09:56:35 +000011036void
11037clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011038{
Eric Andersenc470f442003-07-28 09:56:35 +000011039 for (;;) {
11040 nullredirs = 0;
11041 if (!redirlist)
11042 break;
11043 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011044 }
Eric Andersencb57d552001-06-28 07:25:16 +000011045}
11046
11047
Eric Andersencb57d552001-06-28 07:25:16 +000011048/*
11049 * Copy a file descriptor to be >= to. Returns -1
11050 * if the source file descriptor is closed, EMPTY if there are no unused
11051 * file descriptors left.
11052 */
11053
Eric Andersenc470f442003-07-28 09:56:35 +000011054int
11055copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011056{
11057 int newfd;
11058
11059 newfd = fcntl(from, F_DUPFD, to);
11060 if (newfd < 0) {
11061 if (errno == EMFILE)
11062 return EMPTY;
11063 else
Eric Andersen2870d962001-07-02 17:27:21 +000011064 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011065 }
11066 return newfd;
11067}
11068
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011069
Eric Andersenc470f442003-07-28 09:56:35 +000011070int
11071redirectsafe(union node *redir, int flags)
11072{
11073 int err;
11074 volatile int saveint;
11075 struct jmploc *volatile savehandler = handler;
11076 struct jmploc jmploc;
11077
11078 SAVEINT(saveint);
11079 if (!(err = setjmp(jmploc.loc) * 2)) {
11080 handler = &jmploc;
11081 redirect(redir, flags);
11082 }
11083 handler = savehandler;
11084 if (err && exception != EXERROR)
11085 longjmp(handler->loc, 1);
11086 RESTOREINT(saveint);
11087 return err;
11088}
11089
11090/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11091
11092#ifdef DEBUG
11093static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011094static void shcmd(union node *, FILE *);
11095static void sharg(union node *, FILE *);
11096static void indent(int, char *, FILE *);
11097static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011098
11099
Eric Andersenc470f442003-07-28 09:56:35 +000011100void
11101showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011102{
11103 trputs("showtree called\n");
11104 shtree(n, 1, NULL, stdout);
11105}
Eric Andersencb57d552001-06-28 07:25:16 +000011106
Eric Andersenc470f442003-07-28 09:56:35 +000011107
11108static void
11109shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011110{
11111 struct nodelist *lp;
11112 const char *s;
11113
11114 if (n == NULL)
11115 return;
11116
11117 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011118 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011119 case NSEMI:
11120 s = "; ";
11121 goto binop;
11122 case NAND:
11123 s = " && ";
11124 goto binop;
11125 case NOR:
11126 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011127binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011128 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011129 /* if (ind < 0) */
11130 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011131 shtree(n->nbinary.ch2, ind, NULL, fp);
11132 break;
11133 case NCMD:
11134 shcmd(n, fp);
11135 if (ind >= 0)
11136 putc('\n', fp);
11137 break;
11138 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011139 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011140 shcmd(lp->n, fp);
11141 if (lp->next)
11142 fputs(" | ", fp);
11143 }
11144 if (n->npipe.backgnd)
11145 fputs(" &", fp);
11146 if (ind >= 0)
11147 putc('\n', fp);
11148 break;
11149 default:
11150 fprintf(fp, "<node type %d>", n->type);
11151 if (ind >= 0)
11152 putc('\n', fp);
11153 break;
11154 }
11155}
11156
11157
Eric Andersenc470f442003-07-28 09:56:35 +000011158static void
11159shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011160{
11161 union node *np;
11162 int first;
11163 const char *s;
11164 int dftfd;
11165
11166 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011167 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11168 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011169 putchar(' ');
11170 sharg(np, fp);
11171 first = 0;
11172 }
Eric Andersenc470f442003-07-28 09:56:35 +000011173 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11174 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011175 putchar(' ');
11176 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011177 case NTO: s = ">"; dftfd = 1; break;
11178 case NCLOBBER: s = ">|"; dftfd = 1; break;
11179 case NAPPEND: s = ">>"; dftfd = 1; break;
11180 case NTOFD: s = ">&"; dftfd = 1; break;
11181 case NFROM: s = "<"; dftfd = 0; break;
11182 case NFROMFD: s = "<&"; dftfd = 0; break;
11183 case NFROMTO: s = "<>"; dftfd = 0; break;
11184 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011185 }
11186 if (np->nfile.fd != dftfd)
11187 fprintf(fp, "%d", np->nfile.fd);
11188 fputs(s, fp);
11189 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11190 fprintf(fp, "%d", np->ndup.dupfd);
11191 } else {
11192 sharg(np->nfile.fname, fp);
11193 }
11194 first = 0;
11195 }
11196}
11197
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011198
Eric Andersenc470f442003-07-28 09:56:35 +000011199
11200static void
11201sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011202{
Eric Andersencb57d552001-06-28 07:25:16 +000011203 char *p;
11204 struct nodelist *bqlist;
11205 int subtype;
11206
11207 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011208 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011209 abort();
11210 }
11211 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011212 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011213 switch (*p) {
11214 case CTLESC:
11215 putc(*++p, fp);
11216 break;
11217 case CTLVAR:
11218 putc('$', fp);
11219 putc('{', fp);
11220 subtype = *++p;
11221 if (subtype == VSLENGTH)
11222 putc('#', fp);
11223
11224 while (*p != '=')
11225 putc(*p++, fp);
11226
11227 if (subtype & VSNUL)
11228 putc(':', fp);
11229
11230 switch (subtype & VSTYPE) {
11231 case VSNORMAL:
11232 putc('}', fp);
11233 break;
11234 case VSMINUS:
11235 putc('-', fp);
11236 break;
11237 case VSPLUS:
11238 putc('+', fp);
11239 break;
11240 case VSQUESTION:
11241 putc('?', fp);
11242 break;
11243 case VSASSIGN:
11244 putc('=', fp);
11245 break;
11246 case VSTRIMLEFT:
11247 putc('#', fp);
11248 break;
11249 case VSTRIMLEFTMAX:
11250 putc('#', fp);
11251 putc('#', fp);
11252 break;
11253 case VSTRIMRIGHT:
11254 putc('%', fp);
11255 break;
11256 case VSTRIMRIGHTMAX:
11257 putc('%', fp);
11258 putc('%', fp);
11259 break;
11260 case VSLENGTH:
11261 break;
11262 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011263 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011264 }
11265 break;
11266 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011267 putc('}', fp);
11268 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011269 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011270 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011271 putc('$', fp);
11272 putc('(', fp);
11273 shtree(bqlist->n, -1, NULL, fp);
11274 putc(')', fp);
11275 break;
11276 default:
11277 putc(*p, fp);
11278 break;
11279 }
11280 }
11281}
11282
11283
Eric Andersenc470f442003-07-28 09:56:35 +000011284static void
11285indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011286{
11287 int i;
11288
Eric Andersenc470f442003-07-28 09:56:35 +000011289 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011290 if (pfx && i == amount - 1)
11291 fputs(pfx, fp);
11292 putc('\t', fp);
11293 }
11294}
Eric Andersencb57d552001-06-28 07:25:16 +000011295
Eric Andersenc470f442003-07-28 09:56:35 +000011296
11297
11298/*
11299 * Debugging stuff.
11300 */
11301
11302
Eric Andersencb57d552001-06-28 07:25:16 +000011303FILE *tracefile;
11304
Eric Andersencb57d552001-06-28 07:25:16 +000011305
Eric Andersenc470f442003-07-28 09:56:35 +000011306void
11307trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011308{
Eric Andersenc470f442003-07-28 09:56:35 +000011309 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011310 return;
11311 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011312}
11313
Eric Andersenc470f442003-07-28 09:56:35 +000011314void
11315trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011316{
11317 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011318
Eric Andersenc470f442003-07-28 09:56:35 +000011319 if (debug != 1)
11320 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011321 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011322 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011323 va_end(va);
11324}
11325
Eric Andersenc470f442003-07-28 09:56:35 +000011326void
11327tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011328{
Eric Andersenc470f442003-07-28 09:56:35 +000011329 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011330 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011331 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011332}
11333
11334
Eric Andersenc470f442003-07-28 09:56:35 +000011335void
11336trputs(const char *s)
11337{
11338 if (debug != 1)
11339 return;
11340 fputs(s, tracefile);
11341}
11342
11343
11344static void
11345trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011346{
11347 char *p;
11348 char c;
11349
Eric Andersenc470f442003-07-28 09:56:35 +000011350 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011351 return;
11352 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011353 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011354 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011355 case '\n': c = 'n'; goto backslash;
11356 case '\t': c = 't'; goto backslash;
11357 case '\r': c = 'r'; goto backslash;
11358 case '"': c = '"'; goto backslash;
11359 case '\\': c = '\\'; goto backslash;
11360 case CTLESC: c = 'e'; goto backslash;
11361 case CTLVAR: c = 'v'; goto backslash;
11362 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11363 case CTLBACKQ: c = 'q'; goto backslash;
11364 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11365backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011366 putc(c, tracefile);
11367 break;
11368 default:
11369 if (*p >= ' ' && *p <= '~')
11370 putc(*p, tracefile);
11371 else {
11372 putc('\\', tracefile);
11373 putc(*p >> 6 & 03, tracefile);
11374 putc(*p >> 3 & 07, tracefile);
11375 putc(*p & 07, tracefile);
11376 }
11377 break;
11378 }
11379 }
11380 putc('"', tracefile);
11381}
11382
11383
Eric Andersenc470f442003-07-28 09:56:35 +000011384void
11385trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011386{
Eric Andersenc470f442003-07-28 09:56:35 +000011387 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011388 return;
11389 while (*ap) {
11390 trstring(*ap++);
11391 if (*ap)
11392 putc(' ', tracefile);
11393 else
11394 putc('\n', tracefile);
11395 }
Eric Andersencb57d552001-06-28 07:25:16 +000011396}
11397
11398
Eric Andersenc470f442003-07-28 09:56:35 +000011399void
11400opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011401{
Eric Andersencb57d552001-06-28 07:25:16 +000011402 char s[100];
11403#ifdef O_APPEND
11404 int flags;
11405#endif
11406
Eric Andersenc470f442003-07-28 09:56:35 +000011407 if (debug != 1) {
11408 if (tracefile)
11409 fflush(tracefile);
11410 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011411 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011412 }
Eric Andersenc470f442003-07-28 09:56:35 +000011413 scopy("./trace", s);
11414 if (tracefile) {
11415 if (!freopen(s, "a", tracefile)) {
11416 fprintf(stderr, "Can't re-open %s\n", s);
11417 debug = 0;
11418 return;
11419 }
11420 } else {
11421 if ((tracefile = fopen(s, "a")) == NULL) {
11422 fprintf(stderr, "Can't open %s\n", s);
11423 debug = 0;
11424 return;
11425 }
11426 }
Eric Andersencb57d552001-06-28 07:25:16 +000011427#ifdef O_APPEND
11428 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11429 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11430#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011431 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011432 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011433}
Eric Andersenc470f442003-07-28 09:56:35 +000011434#endif /* DEBUG */
11435
11436
11437/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11438
11439/*
11440 * Sigmode records the current value of the signal handlers for the various
11441 * modes. A value of zero means that the current handler is not known.
11442 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11443 */
11444
11445#define S_DFL 1 /* default signal handling (SIG_DFL) */
11446#define S_CATCH 2 /* signal is caught */
11447#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11448#define S_HARD_IGN 4 /* signal is ignored permenantly */
11449#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11450
Eric Andersencb57d552001-06-28 07:25:16 +000011451
11452
11453/*
Eric Andersencb57d552001-06-28 07:25:16 +000011454 * The trap builtin.
11455 */
11456
Eric Andersenc470f442003-07-28 09:56:35 +000011457int
11458trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011459{
11460 char *action;
11461 char **ap;
11462 int signo;
11463
Eric Andersenc470f442003-07-28 09:56:35 +000011464 nextopt(nullstr);
11465 ap = argptr;
11466 if (!*ap) {
11467 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011468 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011469 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011470
Eric Andersenc470f442003-07-28 09:56:35 +000011471 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011472 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011473 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011474 out1fmt("trap -- %s %s\n",
11475 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011476 }
11477 }
11478 return 0;
11479 }
Eric Andersenc470f442003-07-28 09:56:35 +000011480 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011481 action = NULL;
11482 else
11483 action = *ap++;
11484 while (*ap) {
11485 if ((signo = decode_signal(*ap, 0)) < 0)
11486 error("%s: bad trap", *ap);
11487 INTOFF;
11488 if (action) {
11489 if (action[0] == '-' && action[1] == '\0')
11490 action = NULL;
11491 else
Eric Andersenc470f442003-07-28 09:56:35 +000011492 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011493 }
Eric Andersenc470f442003-07-28 09:56:35 +000011494 if (trap[signo])
11495 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011496 trap[signo] = action;
11497 if (signo != 0)
11498 setsignal(signo);
11499 INTON;
11500 ap++;
11501 }
11502 return 0;
11503}
11504
11505
Eric Andersenc470f442003-07-28 09:56:35 +000011506/*
11507 * Clear traps on a fork.
11508 */
11509
11510void
11511clear_traps(void)
11512{
11513 char **tp;
11514
11515 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11516 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11517 INTOFF;
11518 ckfree(*tp);
11519 *tp = NULL;
11520 if (tp != &trap[0])
11521 setsignal(tp - trap);
11522 INTON;
11523 }
11524 }
11525}
11526
11527
Eric Andersencb57d552001-06-28 07:25:16 +000011528/*
11529 * Set the signal handler for the specified signal. The routine figures
11530 * out what it should be set to.
11531 */
11532
Eric Andersenc470f442003-07-28 09:56:35 +000011533void
11534setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011535{
11536 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011537 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011538 struct sigaction act;
11539
11540 if ((t = trap[signo]) == NULL)
11541 action = S_DFL;
11542 else if (*t != '\0')
11543 action = S_CATCH;
11544 else
11545 action = S_IGN;
11546 if (rootshell && action == S_DFL) {
11547 switch (signo) {
11548 case SIGINT:
11549 if (iflag || minusc || sflag == 0)
11550 action = S_CATCH;
11551 break;
11552 case SIGQUIT:
11553#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011554 if (debug)
11555 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011556#endif
11557 /* FALLTHROUGH */
11558 case SIGTERM:
11559 if (iflag)
11560 action = S_IGN;
11561 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011562#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011563 case SIGTSTP:
11564 case SIGTTOU:
11565 if (mflag)
11566 action = S_IGN;
11567 break;
11568#endif
11569 }
11570 }
11571
11572 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011573 tsig = *t;
11574 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011575 /*
11576 * current setting unknown
11577 */
11578 if (sigaction(signo, 0, &act) == -1) {
11579 /*
11580 * Pretend it worked; maybe we should give a warning
11581 * here, but other shells don't. We don't alter
11582 * sigmode, so that we retry every time.
11583 */
11584 return;
11585 }
11586 if (act.sa_handler == SIG_IGN) {
11587 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011588 signo == SIGTTIN || signo == SIGTTOU)) {
11589 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011590 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011591 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011592 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011593 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011594 }
11595 }
Eric Andersenc470f442003-07-28 09:56:35 +000011596 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011597 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011598 switch (action) {
11599 case S_CATCH:
11600 act.sa_handler = onsig;
11601 break;
11602 case S_IGN:
11603 act.sa_handler = SIG_IGN;
11604 break;
11605 default:
11606 act.sa_handler = SIG_DFL;
11607 }
Eric Andersencb57d552001-06-28 07:25:16 +000011608 *t = action;
11609 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011610 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011611 sigaction(signo, &act, 0);
11612}
11613
11614/*
11615 * Ignore a signal.
11616 */
11617
Eric Andersenc470f442003-07-28 09:56:35 +000011618void
11619ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011620{
11621 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11622 signal(signo, SIG_IGN);
11623 }
11624 sigmode[signo - 1] = S_HARD_IGN;
11625}
11626
11627
Eric Andersencb57d552001-06-28 07:25:16 +000011628/*
11629 * Signal handler.
11630 */
11631
Eric Andersenc470f442003-07-28 09:56:35 +000011632void
11633onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011634{
Eric Andersencb57d552001-06-28 07:25:16 +000011635 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011636 pendingsigs = signo;
11637
11638 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11639 if (!suppressint)
11640 onint();
11641 intpending = 1;
11642 }
Eric Andersencb57d552001-06-28 07:25:16 +000011643}
11644
11645
Eric Andersencb57d552001-06-28 07:25:16 +000011646/*
11647 * Called to execute a trap. Perhaps we should avoid entering new trap
11648 * handlers while we are executing a trap handler.
11649 */
11650
Eric Andersenc470f442003-07-28 09:56:35 +000011651void
11652dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011653{
Eric Andersenc470f442003-07-28 09:56:35 +000011654 char *p;
11655 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011656 int savestatus;
11657
Eric Andersenc470f442003-07-28 09:56:35 +000011658 savestatus = exitstatus;
11659 q = gotsig;
11660 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11661 *p = 0;
11662 p = trap[p - q + 1];
11663 if (!p)
11664 continue;
11665 evalstring(p, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011666 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011667 }
Eric Andersencb57d552001-06-28 07:25:16 +000011668}
11669
Eric Andersenc470f442003-07-28 09:56:35 +000011670
Eric Andersenc470f442003-07-28 09:56:35 +000011671/*
11672 * Controls whether the shell is interactive or not.
11673 */
11674
Eric Andersenc470f442003-07-28 09:56:35 +000011675void
11676setinteractive(int on)
11677{
11678 static int is_interactive;
11679
11680 if (++on == is_interactive)
11681 return;
11682 is_interactive = on;
11683 setsignal(SIGINT);
11684 setsignal(SIGQUIT);
11685 setsignal(SIGTERM);
11686#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11687 if(is_interactive > 1) {
11688 /* Looks like they want an interactive shell */
11689 static int do_banner;
11690
11691 if(!do_banner) {
11692 out1fmt(
11693 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11694 "Enter 'help' for a list of built-in commands.\n\n");
11695 do_banner++;
11696 }
11697 }
11698#endif
11699}
11700
11701
11702#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11703/*** List the available builtins ***/
11704
11705static int helpcmd(int argc, char **argv)
11706{
11707 int col, i;
11708
11709 out1fmt("\nBuilt-in commands:\n-------------------\n");
11710 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11711 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11712 builtincmd[i].name + 1);
11713 if (col > 60) {
11714 out1fmt("\n");
11715 col = 0;
11716 }
11717 }
11718#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11719 {
11720 extern const struct BB_applet applets[];
11721 extern const size_t NUM_APPLETS;
11722
11723 for (i = 0; i < NUM_APPLETS; i++) {
11724
11725 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11726 if (col > 60) {
11727 out1fmt("\n");
11728 col = 0;
11729 }
11730 }
11731 }
11732#endif
11733 out1fmt("\n\n");
11734 return EXIT_SUCCESS;
11735}
11736#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11737
Eric Andersencb57d552001-06-28 07:25:16 +000011738/*
11739 * Called to exit the shell.
11740 */
11741
Eric Andersenc470f442003-07-28 09:56:35 +000011742void
11743exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011744{
Eric Andersenc470f442003-07-28 09:56:35 +000011745 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011746 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011747 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011748
Eric Andersenc470f442003-07-28 09:56:35 +000011749 status = exitstatus;
11750 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11751 if (setjmp(loc.loc)) {
11752 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011753 }
Eric Andersenc470f442003-07-28 09:56:35 +000011754 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011755 if ((p = trap[0]) != NULL && *p != '\0') {
11756 trap[0] = NULL;
11757 evalstring(p, 0);
11758 }
Eric Andersencb57d552001-06-28 07:25:16 +000011759 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011760#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11761 if (iflag && rootshell) {
11762 const char *hp = lookupvar("HISTFILE");
11763
11764 if(hp != NULL )
11765 save_history ( hp );
11766 }
11767#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011768out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011769 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011770 /* NOTREACHED */
11771}
11772
11773static int decode_signal(const char *string, int minsig)
11774{
11775 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011776 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011777
Eric Andersen34506362001-08-02 05:02:46 +000011778 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011779}
Eric Andersen34506362001-08-02 05:02:46 +000011780
Eric Andersenc470f442003-07-28 09:56:35 +000011781/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11782
11783static struct var *vartab[VTABSIZE];
11784
11785static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011786static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011787
11788/*
11789 * Initialize the varable symbol tables and import the environment
11790 */
11791
Eric Andersenc470f442003-07-28 09:56:35 +000011792
11793#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011794/*
Eric Andersenc470f442003-07-28 09:56:35 +000011795 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011796 */
11797
Eric Andersenc470f442003-07-28 09:56:35 +000011798int
11799setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011800{
Eric Andersenc470f442003-07-28 09:56:35 +000011801 int err;
11802 volatile int saveint;
11803 struct jmploc *volatile savehandler = handler;
11804 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011805
Eric Andersenc470f442003-07-28 09:56:35 +000011806 SAVEINT(saveint);
11807 if (setjmp(jmploc.loc))
11808 err = 1;
11809 else {
11810 handler = &jmploc;
11811 setvar(name, val, flags);
11812 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011813 }
Eric Andersenc470f442003-07-28 09:56:35 +000011814 handler = savehandler;
11815 RESTOREINT(saveint);
11816 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011817}
Eric Andersenc470f442003-07-28 09:56:35 +000011818#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011819
11820/*
11821 * Set the value of a variable. The flags argument is ored with the
11822 * flags of the variable. If val is NULL, the variable is unset.
11823 */
11824
Eric Andersenc470f442003-07-28 09:56:35 +000011825static void
11826setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011827{
Eric Andersenc470f442003-07-28 09:56:35 +000011828 char *p, *q;
11829 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011830 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011831 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011832
Eric Andersenc470f442003-07-28 09:56:35 +000011833 q = endofname(name);
11834 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011835 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011836 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011837 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011838 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011839 if (val == NULL) {
11840 flags |= VUNSET;
11841 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011842 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011843 }
11844 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011845 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11846 *p++ = '\0';
11847 if (vallen) {
11848 p[-1] = '=';
11849 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011850 }
Eric Andersenc470f442003-07-28 09:56:35 +000011851 *p = '\0';
11852 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011853 INTON;
11854}
11855
11856
Eric Andersencb57d552001-06-28 07:25:16 +000011857/*
11858 * Same as setvar except that the variable and value are passed in
11859 * the first argument as name=value. Since the first argument will
11860 * be actually stored in the table, it should not be a string that
11861 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011862 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011863 */
11864
Eric Andersenc470f442003-07-28 09:56:35 +000011865void
11866setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011867{
11868 struct var *vp, **vpp;
11869
11870 vpp = hashvar(s);
11871 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000011872 vp = *findvar(vpp, s);
11873 if (vp) {
Eric Andersencb57d552001-06-28 07:25:16 +000011874 if (vp->flags & VREADONLY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011875 if (flags & VNOSAVE)
11876 free(s);
11877 error("%.*s: is read only", strchrnul(s, '=') - s, s);
Eric Andersencb57d552001-06-28 07:25:16 +000011878 }
Eric Andersenc470f442003-07-28 09:56:35 +000011879
11880 if (flags & VNOSET)
11881 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011882
11883 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000011884 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011885
Eric Andersenc470f442003-07-28 09:56:35 +000011886 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11887 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011888
Eric Andersenc470f442003-07-28 09:56:35 +000011889 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11890 } else {
11891 if (flags & VNOSET)
11892 return;
11893 /* not found */
11894 vp = ckmalloc(sizeof (*vp));
11895 vp->next = *vpp;
11896 vp->func = NULL;
11897 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000011898 }
Eric Andersenc470f442003-07-28 09:56:35 +000011899 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11900 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000011901 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000011902 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011903}
11904
11905
Eric Andersencb57d552001-06-28 07:25:16 +000011906/*
11907 * Process a linked list of variable assignments.
11908 */
11909
Eric Andersenc470f442003-07-28 09:56:35 +000011910static void
11911listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011912{
Eric Andersenc470f442003-07-28 09:56:35 +000011913 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000011914
Eric Andersenc470f442003-07-28 09:56:35 +000011915 if (!lp)
11916 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011917 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011918 do {
11919 setvareq(lp->text, flags);
11920 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000011921 INTON;
11922}
11923
11924
Eric Andersencb57d552001-06-28 07:25:16 +000011925/*
11926 * Find the value of a variable. Returns NULL if not set.
11927 */
11928
Eric Andersenc470f442003-07-28 09:56:35 +000011929static char *
11930lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000011931{
Eric Andersencb57d552001-06-28 07:25:16 +000011932 struct var *v;
11933
11934 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
Eric Andersenc470f442003-07-28 09:56:35 +000011935 return strchrnul(v->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011936 }
11937 return NULL;
11938}
11939
11940
Eric Andersencb57d552001-06-28 07:25:16 +000011941/*
11942 * Search the environment of a builtin command.
11943 */
11944
Eric Andersenc470f442003-07-28 09:56:35 +000011945static char *
11946bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000011947{
Eric Andersenc470f442003-07-28 09:56:35 +000011948 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000011949
Eric Andersenc470f442003-07-28 09:56:35 +000011950 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011951 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000011952 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011953 }
11954 return lookupvar(name);
11955}
11956
11957
Eric Andersencb57d552001-06-28 07:25:16 +000011958/*
Eric Andersenc470f442003-07-28 09:56:35 +000011959 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000011960 */
11961
Eric Andersenc470f442003-07-28 09:56:35 +000011962static char **
11963listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011964{
Eric Andersencb57d552001-06-28 07:25:16 +000011965 struct var **vpp;
11966 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000011967 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000011968 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000011969
Eric Andersenc470f442003-07-28 09:56:35 +000011970 STARTSTACKSTR(ep);
11971 vpp = vartab;
11972 mask = on | off;
11973 do {
11974 for (vp = *vpp ; vp ; vp = vp->next)
11975 if ((vp->flags & mask) == on) {
11976 if (ep == stackstrend())
11977 ep = growstackstr();
11978 *ep++ = (char *) vp->text;
11979 }
11980 } while (++vpp < vartab + VTABSIZE);
11981 if (ep == stackstrend())
11982 ep = growstackstr();
11983 if (end)
11984 *end = ep;
11985 *ep++ = NULL;
11986 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000011987}
11988
11989
11990/*
Eric Andersenc470f442003-07-28 09:56:35 +000011991 * POSIX requires that 'set' (but not export or readonly) output the
11992 * variables in lexicographic order - by the locale's collating order (sigh).
11993 * Maybe we could keep them in an ordered balanced binary tree
11994 * instead of hashed lists.
11995 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000011996 */
11997
Eric Andersenc470f442003-07-28 09:56:35 +000011998static int
11999showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012000{
Eric Andersenc470f442003-07-28 09:56:35 +000012001 const char *sep;
12002 char **ep, **epend;
12003
12004 ep = listvars(on, off, &epend);
12005 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12006
12007 sep = *sep_prefix ? spcstr : sep_prefix;
12008
12009 for (; ep < epend; ep++) {
12010 const char *p;
12011 const char *q;
12012
12013 p = strchrnul(*ep, '=');
12014 q = nullstr;
12015 if (*p)
12016 q = single_quote(++p);
12017
12018 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12019 }
12020
Eric Andersencb57d552001-06-28 07:25:16 +000012021 return 0;
12022}
12023
12024
12025
12026/*
12027 * The export and readonly commands.
12028 */
12029
Eric Andersenc470f442003-07-28 09:56:35 +000012030static int
12031exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012032{
12033 struct var *vp;
12034 char *name;
12035 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012036 char **aptr;
12037 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12038 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012039
Eric Andersenc470f442003-07-28 09:56:35 +000012040 notp = nextopt("p") - 'p';
12041 if (notp && ((name = *(aptr = argptr)))) {
12042 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012043 if ((p = strchr(name, '=')) != NULL) {
12044 p++;
12045 } else {
12046 if ((vp = *findvar(hashvar(name), name))) {
12047 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012048 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012049 }
12050 }
12051 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012052 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012053 } else {
12054 showvars(argv[0], flag, 0);
12055 }
12056 return 0;
12057}
12058
Eric Andersen34506362001-08-02 05:02:46 +000012059
Eric Andersencb57d552001-06-28 07:25:16 +000012060/*
Eric Andersencb57d552001-06-28 07:25:16 +000012061 * Make a variable a local variable. When a variable is made local, it's
12062 * value and flags are saved in a localvar structure. The saved values
12063 * will be restored when the shell function returns. We handle the name
12064 * "-" as a special case.
12065 */
12066
Eric Andersenc470f442003-07-28 09:56:35 +000012067static inline void
12068mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012069{
Eric Andersencb57d552001-06-28 07:25:16 +000012070 struct localvar *lvp;
12071 struct var **vpp;
12072 struct var *vp;
12073
12074 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012075 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012076 if (name[0] == '-' && name[1] == '\0') {
12077 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012078 p = ckmalloc(sizeof(optlist));
12079 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012080 vp = NULL;
12081 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012082 char *eq;
12083
Eric Andersencb57d552001-06-28 07:25:16 +000012084 vpp = hashvar(name);
12085 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012086 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012087 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012088 if (eq)
12089 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012090 else
12091 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012092 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012093 lvp->flags = VUNSET;
12094 } else {
12095 lvp->text = vp->text;
12096 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012097 vp->flags |= VSTRFIXED|VTEXTFIXED;
12098 if (eq)
12099 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012100 }
12101 }
12102 lvp->vp = vp;
12103 lvp->next = localvars;
12104 localvars = lvp;
12105 INTON;
12106}
12107
Eric Andersenc470f442003-07-28 09:56:35 +000012108/*
12109 * The "local" command.
12110 */
12111
12112static int
12113localcmd(int argc, char **argv)
12114{
12115 char *name;
12116
12117 argv = argptr;
12118 while ((name = *argv++) != NULL) {
12119 mklocal(name);
12120 }
12121 return 0;
12122}
12123
12124
12125
Eric Andersencb57d552001-06-28 07:25:16 +000012126/*
12127 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012128 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012129 */
12130
Eric Andersenc470f442003-07-28 09:56:35 +000012131static void
12132poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012133{
Eric Andersencb57d552001-06-28 07:25:16 +000012134 struct localvar *lvp;
12135 struct var *vp;
12136
12137 while ((lvp = localvars) != NULL) {
12138 localvars = lvp->next;
12139 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012140 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12141 if (vp == NULL) { /* $- saved */
12142 memcpy(optlist, lvp->text, sizeof(optlist));
12143 ckfree(lvp->text);
12144 optschanged();
12145 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12146 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012147 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012148 if (vp->func)
12149 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12150 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12151 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012152 vp->flags = lvp->flags;
12153 vp->text = lvp->text;
12154 }
Eric Andersenc470f442003-07-28 09:56:35 +000012155 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012156 }
12157}
12158
12159
Eric Andersencb57d552001-06-28 07:25:16 +000012160/*
12161 * The unset builtin command. We unset the function before we unset the
12162 * variable to allow a function to be unset when there is a readonly variable
12163 * with the same name.
12164 */
12165
Eric Andersenc470f442003-07-28 09:56:35 +000012166int
12167unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012168{
12169 char **ap;
12170 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012171 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012172 int ret = 0;
12173
12174 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012175 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012176 }
Eric Andersencb57d552001-06-28 07:25:16 +000012177
Eric Andersenc470f442003-07-28 09:56:35 +000012178 for (ap = argptr; *ap ; ap++) {
12179 if (flag != 'f') {
12180 i = unsetvar(*ap);
12181 ret |= i;
12182 if (!(i & 2))
12183 continue;
12184 }
12185 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012186 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012187 }
Eric Andersenc470f442003-07-28 09:56:35 +000012188 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012189}
12190
12191
12192/*
12193 * Unset the specified variable.
12194 */
12195
Eric Andersenc470f442003-07-28 09:56:35 +000012196int
12197unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012198{
Eric Andersencb57d552001-06-28 07:25:16 +000012199 struct var **vpp;
12200 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012201 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012202
12203 vpp = findvar(hashvar(s), s);
12204 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012205 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012206 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012207 int flags = vp->flags;
12208
12209 retval = 1;
12210 if (flags & VREADONLY)
12211 goto out;
12212 if (flags & VUNSET)
12213 goto ok;
12214 if ((flags & VSTRFIXED) == 0) {
12215 INTOFF;
12216 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12217 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012218 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012219 ckfree(vp);
12220 INTON;
12221 } else {
12222 setvar(s, 0, 0);
12223 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012224 }
Eric Andersenc470f442003-07-28 09:56:35 +000012225ok:
12226 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012227 }
12228
Eric Andersenc470f442003-07-28 09:56:35 +000012229out:
12230 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012231}
12232
12233
12234
12235/*
12236 * Find the appropriate entry in the hash table from the name.
12237 */
12238
Eric Andersenc470f442003-07-28 09:56:35 +000012239static struct var **
12240hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012241{
Eric Andersencb57d552001-06-28 07:25:16 +000012242 unsigned int hashval;
12243
12244 hashval = ((unsigned char) *p) << 4;
12245 while (*p && *p != '=')
12246 hashval += (unsigned char) *p++;
12247 return &vartab[hashval % VTABSIZE];
12248}
12249
12250
12251
12252/*
Eric Andersenc470f442003-07-28 09:56:35 +000012253 * Compares two strings up to the first = or '\0'. The first
12254 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012255 * either '=' or '\0'.
12256 */
12257
Eric Andersenc470f442003-07-28 09:56:35 +000012258int
12259varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012260{
Eric Andersenc470f442003-07-28 09:56:35 +000012261 int c, d;
12262
12263 while ((c = *p) == (d = *q)) {
12264 if (!c || c == '=')
12265 goto out;
12266 p++;
12267 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012268 }
Eric Andersenc470f442003-07-28 09:56:35 +000012269 if (c == '=')
12270 c = 0;
12271 if (d == '=')
12272 d = 0;
12273out:
12274 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012275}
12276
Eric Andersenc470f442003-07-28 09:56:35 +000012277static int
12278vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012279{
Eric Andersenc470f442003-07-28 09:56:35 +000012280 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012281}
12282
Eric Andersenc470f442003-07-28 09:56:35 +000012283static struct var **
12284findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012285{
12286 for (; *vpp; vpp = &(*vpp)->next) {
12287 if (varequal((*vpp)->text, name)) {
12288 break;
12289 }
12290 }
12291 return vpp;
12292}
Eric Andersenc470f442003-07-28 09:56:35 +000012293/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012294
12295/*
12296 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
Eric Andersenc470f442003-07-28 09:56:35 +000012297 * This code for the times builtin.
Eric Andersencb57d552001-06-28 07:25:16 +000012298 */
Eric Andersenc470f442003-07-28 09:56:35 +000012299
12300#include <sys/times.h>
12301
12302int timescmd(int ac, char **av) {
Eric Andersencb57d552001-06-28 07:25:16 +000012303 struct tms buf;
12304 long int clk_tck = sysconf(_SC_CLK_TCK);
12305
12306 times(&buf);
Eric Andersenc470f442003-07-28 09:56:35 +000012307 out1fmt("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12308 (int) (buf.tms_utime / clk_tck / 60),
12309 ((double) buf.tms_utime) / clk_tck,
12310 (int) (buf.tms_stime / clk_tck / 60),
12311 ((double) buf.tms_stime) / clk_tck,
12312 (int) (buf.tms_cutime / clk_tck / 60),
12313 ((double) buf.tms_cutime) / clk_tck,
12314 (int) (buf.tms_cstime / clk_tck / 60),
12315 ((double) buf.tms_cstime) / clk_tck);
Eric Andersencb57d552001-06-28 07:25:16 +000012316 return 0;
12317}
12318
Eric Andersend35c5df2002-01-09 15:37:36 +000012319#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012320static int
12321dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012322{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012323 long result = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012324 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012325
Eric Andersenc470f442003-07-28 09:56:35 +000012326 INTOFF;
12327 result = arith(s, &errcode);
12328 if (errcode < 0) {
12329 if (errcode == -2)
12330 error("divide by zero");
12331 else
12332 synerror(s);
12333 }
12334 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012335
Eric Andersenc470f442003-07-28 09:56:35 +000012336 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012337}
Eric Andersenc470f442003-07-28 09:56:35 +000012338
12339
12340/*
12341 * The exp(1) builtin.
12342 */
12343static int
12344expcmd(int argc, char **argv)
12345{
12346 const char *p;
12347 char *concat;
12348 char **ap;
12349 long i;
12350
12351 if (argc > 1) {
12352 p = argv[1];
12353 if (argc > 2) {
12354 /*
12355 * concatenate arguments
12356 */
12357 STARTSTACKSTR(concat);
12358 ap = argv + 2;
12359 for (;;) {
12360 while (*p)
12361 STPUTC(*p++, concat);
12362 if ((p = *ap++) == NULL)
12363 break;
12364 STPUTC(' ', concat);
12365 }
12366 STPUTC('\0', concat);
12367 p = grabstackstr(concat);
12368 }
12369 } else
12370 p = nullstr;
12371
12372 i = dash_arith(p);
12373
12374 out1fmt("%ld\n", i);
12375 return (! i);
12376}
12377#endif /* CONFIG_ASH_MATH_SUPPORT */
12378
12379/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12380
12381/*
12382 * Miscelaneous builtins.
12383 */
12384
12385#undef rflag
12386
12387#ifdef __GLIBC__
12388#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12389typedef enum __rlimit_resource rlim_t;
12390#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012391#endif
12392
12393
Eric Andersenc470f442003-07-28 09:56:35 +000012394/*
12395 * The read builtin. The -e option causes backslashes to escape the
12396 * following character.
12397 *
12398 * This uses unbuffered input, which may be avoidable in some cases.
12399 */
12400
12401static int
12402readcmd(int argc, char **argv)
12403{
12404 char **ap;
12405 int backslash;
12406 char c;
12407 int rflag;
12408 char *prompt;
12409 const char *ifs;
12410 char *p;
12411 int startword;
12412 int status;
12413 int i;
12414
12415 rflag = 0;
12416 prompt = NULL;
12417 while ((i = nextopt("p:r")) != '\0') {
12418 if (i == 'p')
12419 prompt = optionarg;
12420 else
12421 rflag = 1;
12422 }
12423 if (prompt && isatty(0)) {
12424 out2str(prompt);
12425 flushall();
12426 }
12427 if (*(ap = argptr) == NULL)
12428 error("arg count");
12429 if ((ifs = bltinlookup("IFS")) == NULL)
12430 ifs = defifs;
12431 status = 0;
12432 startword = 1;
12433 backslash = 0;
12434 STARTSTACKSTR(p);
12435 for (;;) {
12436 if (read(0, &c, 1) != 1) {
12437 status = 1;
12438 break;
12439 }
12440 if (c == '\0')
12441 continue;
12442 if (backslash) {
12443 backslash = 0;
12444 if (c != '\n')
12445 goto put;
12446 continue;
12447 }
12448 if (!rflag && c == '\\') {
12449 backslash++;
12450 continue;
12451 }
12452 if (c == '\n')
12453 break;
12454 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12455 continue;
12456 }
12457 startword = 0;
12458 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12459 STACKSTRNUL(p);
12460 setvar(*ap, stackblock(), 0);
12461 ap++;
12462 startword = 1;
12463 STARTSTACKSTR(p);
12464 } else {
12465put:
12466 STPUTC(c, p);
12467 }
12468 }
12469 STACKSTRNUL(p);
12470 /* Remove trailing blanks */
12471 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12472 *p = '\0';
12473 setvar(*ap, stackblock(), 0);
12474 while (*++ap != NULL)
12475 setvar(*ap, nullstr, 0);
12476 return status;
12477}
12478
12479
12480static int umaskcmd(int argc, char **argv)
12481{
12482 static const char permuser[3] = "ugo";
12483 static const char permmode[3] = "rwx";
12484 static const short int permmask[] = {
12485 S_IRUSR, S_IWUSR, S_IXUSR,
12486 S_IRGRP, S_IWGRP, S_IXGRP,
12487 S_IROTH, S_IWOTH, S_IXOTH
12488 };
12489
12490 char *ap;
12491 mode_t mask;
12492 int i;
12493 int symbolic_mode = 0;
12494
12495 while (nextopt("S") != '\0') {
12496 symbolic_mode = 1;
12497 }
12498
12499 INTOFF;
12500 mask = umask(0);
12501 umask(mask);
12502 INTON;
12503
12504 if ((ap = *argptr) == NULL) {
12505 if (symbolic_mode) {
12506 char buf[18];
12507 char *p = buf;
12508
12509 for (i = 0; i < 3; i++) {
12510 int j;
12511
12512 *p++ = permuser[i];
12513 *p++ = '=';
12514 for (j = 0; j < 3; j++) {
12515 if ((mask & permmask[3 * i + j]) == 0) {
12516 *p++ = permmode[j];
12517 }
12518 }
12519 *p++ = ',';
12520 }
12521 *--p = 0;
12522 puts(buf);
12523 } else {
12524 out1fmt("%.4o\n", mask);
12525 }
12526 } else {
12527 if (is_digit((unsigned char) *ap)) {
12528 mask = 0;
12529 do {
12530 if (*ap >= '8' || *ap < '0')
12531 error(illnum, argv[1]);
12532 mask = (mask << 3) + (*ap - '0');
12533 } while (*++ap != '\0');
12534 umask(mask);
12535 } else {
12536 mask = ~mask & 0777;
12537 if (!bb_parse_mode(ap, &mask)) {
12538 error("Illegal mode: %s", ap);
12539 }
12540 umask(~mask & 0777);
12541 }
12542 }
12543 return 0;
12544}
12545
12546/*
12547 * ulimit builtin
12548 *
12549 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12550 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12551 * ash by J.T. Conklin.
12552 *
12553 * Public domain.
12554 */
12555
12556struct limits {
12557 const char *name;
12558 int cmd;
12559 int factor; /* multiply by to get rlim_{cur,max} values */
12560 char option;
12561};
12562
12563static const struct limits limits[] = {
12564#ifdef RLIMIT_CPU
12565 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12566#endif
12567#ifdef RLIMIT_FSIZE
12568 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12569#endif
12570#ifdef RLIMIT_DATA
12571 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12572#endif
12573#ifdef RLIMIT_STACK
12574 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12575#endif
12576#ifdef RLIMIT_CORE
12577 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12578#endif
12579#ifdef RLIMIT_RSS
12580 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12581#endif
12582#ifdef RLIMIT_MEMLOCK
12583 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12584#endif
12585#ifdef RLIMIT_NPROC
12586 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12587#endif
12588#ifdef RLIMIT_NOFILE
12589 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12590#endif
12591#ifdef RLIMIT_VMEM
12592 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12593#endif
12594#ifdef RLIMIT_SWAP
12595 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12596#endif
12597 { (char *) 0, 0, 0, '\0' }
12598};
12599
12600int
12601ulimitcmd(int argc, char **argv)
12602{
12603 int c;
12604 rlim_t val = 0;
12605 enum { SOFT = 0x1, HARD = 0x2 }
12606 how = SOFT | HARD;
12607 const struct limits *l;
12608 int set, all = 0;
12609 int optc, what;
12610 struct rlimit limit;
12611
12612 what = 'f';
12613 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12614 switch (optc) {
12615 case 'H':
12616 how = HARD;
12617 break;
12618 case 'S':
12619 how = SOFT;
12620 break;
12621 case 'a':
12622 all = 1;
12623 break;
12624 default:
12625 what = optc;
12626 }
12627
12628 for (l = limits; l->name && l->option != what; l++)
12629 ;
12630 if (!l->name)
12631 error("internal error (%c)", what);
12632
12633 set = *argptr ? 1 : 0;
12634 if (set) {
12635 char *p = *argptr;
12636
12637 if (all || argptr[1])
12638 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012639 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012640 val = RLIM_INFINITY;
12641 else {
12642 val = (rlim_t) 0;
12643
12644 while ((c = *p++) >= '0' && c <= '9')
12645 {
12646 val = (val * 10) + (long)(c - '0');
12647 if (val < (rlim_t) 0)
12648 break;
12649 }
12650 if (c)
12651 error("bad number");
12652 val *= l->factor;
12653 }
12654 }
12655 if (all) {
12656 for (l = limits; l->name; l++) {
12657 getrlimit(l->cmd, &limit);
12658 if (how & SOFT)
12659 val = limit.rlim_cur;
12660 else if (how & HARD)
12661 val = limit.rlim_max;
12662
12663 out1fmt("%-20s ", l->name);
12664 if (val == RLIM_INFINITY)
12665 out1fmt("unlimited\n");
12666 else
12667 {
12668 val /= l->factor;
12669 out1fmt("%lld\n", (long long) val);
12670 }
12671 }
12672 return 0;
12673 }
12674
12675 getrlimit(l->cmd, &limit);
12676 if (set) {
12677 if (how & HARD)
12678 limit.rlim_max = val;
12679 if (how & SOFT)
12680 limit.rlim_cur = val;
12681 if (setrlimit(l->cmd, &limit) < 0)
12682 error("error setting limit (%m)");
12683 } else {
12684 if (how & SOFT)
12685 val = limit.rlim_cur;
12686 else if (how & HARD)
12687 val = limit.rlim_max;
12688
12689 if (val == RLIM_INFINITY)
12690 out1fmt("unlimited\n");
12691 else
12692 {
12693 val /= l->factor;
12694 out1fmt("%lld\n", (long long) val);
12695 }
12696 }
12697 return 0;
12698}
12699
12700#ifdef DEBUG
12701const char *bb_applet_name = "debug stuff usage";
12702int main(int argc, char **argv)
12703{
12704 return ash_main(argc, argv);
12705}
12706#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012707
Eric Andersendf82f612001-06-28 07:46:40 +000012708/*-
12709 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000012710 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000012711 *
12712 * This code is derived from software contributed to Berkeley by
12713 * Kenneth Almquist.
12714 *
12715 * Redistribution and use in source and binary forms, with or without
12716 * modification, are permitted provided that the following conditions
12717 * are met:
12718 * 1. Redistributions of source code must retain the above copyright
12719 * notice, this list of conditions and the following disclaimer.
12720 * 2. Redistributions in binary form must reproduce the above copyright
12721 * notice, this list of conditions and the following disclaimer in the
12722 * documentation and/or other materials provided with the distribution.
12723 *
Eric Andersen2870d962001-07-02 17:27:21 +000012724 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12725 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000012726 *
12727 * 4. Neither the name of the University nor the names of its contributors
12728 * may be used to endorse or promote products derived from this software
12729 * without specific prior written permission.
12730 *
12731 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12732 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12733 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12734 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12735 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12736 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12737 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12738 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12739 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12740 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12741 * SUCH DAMAGE.
12742 */