source: MondoRescue/branches/stable/mindi-busybox/shell/msh.c

Last change on this file was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 99.4 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Minix shell port for busybox
4 *
5 * This version of the Minix shell was adapted for use in busybox
6 * by Erik Andersen <andersen@codepoet.org>
7 *
8 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
11 * Erik Andersen <andersen@codepoet.org>
12 *
13 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14 */
15
16#include <sys/times.h>
17#include <setjmp.h>
18
19#ifdef STANDALONE
20# ifndef _GNU_SOURCE
21# define _GNU_SOURCE
22# endif
23# include <sys/types.h>
24# include <sys/stat.h>
25# include <sys/wait.h>
26# include <signal.h>
27# include <stdio.h>
28# include <stdlib.h>
29# include <unistd.h>
30# include <string.h>
31# include <errno.h>
32# include <dirent.h>
33# include <fcntl.h>
34# include <ctype.h>
35# include <assert.h>
36# define bb_dev_null "/dev/null"
37# define DEFAULT_SHELL "/proc/self/exe"
38# define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
39# define bb_banner "busybox standalone"
40# define ENABLE_FEATURE_SH_STANDALONE 0
41# define bb_msg_memory_exhausted "memory exhausted"
42# define xmalloc(size) malloc(size)
43# define msh_main(argc,argv) main(argc,argv)
44# define safe_read(fd,buf,count) read(fd,buf,count)
45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
48static char *find_applet_by_name(const char *applet)
49{
50 return NULL;
51}
52static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
53{
54 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
61 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
65 }
66 }
67 }
68 return buf;
69}
70static char *itoa_to_buf(int n, char *buf, unsigned buflen)
71{
72 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
76 }
77 return utoa_to_buf((unsigned)n, buf, buflen);
78}
79static char local_buf[12];
80static char *itoa(int n)
81{
82 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
83 return local_buf;
84}
85#else
86# include "busybox.h"
87extern char **environ;
88#endif
89
90/*#define MSHDEBUG 1*/
91
92#ifdef MSHDEBUG
93int mshdbg = MSHDEBUG;
94
95#define DBGPRINTF(x) if (mshdbg>0) printf x
96#define DBGPRINTF0(x) if (mshdbg>0) printf x
97#define DBGPRINTF1(x) if (mshdbg>1) printf x
98#define DBGPRINTF2(x) if (mshdbg>2) printf x
99#define DBGPRINTF3(x) if (mshdbg>3) printf x
100#define DBGPRINTF4(x) if (mshdbg>4) printf x
101#define DBGPRINTF5(x) if (mshdbg>5) printf x
102#define DBGPRINTF6(x) if (mshdbg>6) printf x
103#define DBGPRINTF7(x) if (mshdbg>7) printf x
104#define DBGPRINTF8(x) if (mshdbg>8) printf x
105#define DBGPRINTF9(x) if (mshdbg>9) printf x
106
107int mshdbg_rc = 0;
108
109#define RCPRINTF(x) if (mshdbg_rc) printf x
110
111#else
112
113#define DBGPRINTF(x)
114#define DBGPRINTF0(x) ((void)0)
115#define DBGPRINTF1(x) ((void)0)
116#define DBGPRINTF2(x) ((void)0)
117#define DBGPRINTF3(x) ((void)0)
118#define DBGPRINTF4(x) ((void)0)
119#define DBGPRINTF5(x) ((void)0)
120#define DBGPRINTF6(x) ((void)0)
121#define DBGPRINTF7(x) ((void)0)
122#define DBGPRINTF8(x) ((void)0)
123#define DBGPRINTF9(x) ((void)0)
124
125#define RCPRINTF(x) ((void)0)
126
127#endif /* MSHDEBUG */
128
129
130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
133#else
134# define DEFAULT_ROOT_PROMPT "# "
135# define DEFAULT_USER_PROMPT "$ "
136#endif
137
138
139/* -------- sh.h -------- */
140/*
141 * shell
142 */
143
144#define LINELIM 2100
145#define NPUSH 8 /* limit to input nesting */
146
147#undef NOFILE
148#define NOFILE 20 /* Number of open files */
149#define NUFILE 10 /* Number of user-accessible files */
150#define FDBASE 10 /* First file usable by Shell */
151
152/*
153 * values returned by wait
154 */
155#define WAITSIG(s) ((s) & 0177)
156#define WAITVAL(s) (((s) >> 8) & 0377)
157#define WAITCORE(s) (((s) & 0200) != 0)
158
159/*
160 * library and system definitions
161 */
162typedef void xint; /* base type of jmp_buf, for not broken compilers */
163
164/*
165 * shell components
166 */
167#define NOBLOCK ((struct op *)NULL)
168#define NOWORD ((char *)NULL)
169#define NOWORDS ((char **)NULL)
170#define NOPIPE ((int *)NULL)
171
172/*
173 * redirection
174 */
175struct ioword {
176 short io_unit; /* unit affected */
177 short io_flag; /* action (below) */
178 char *io_name; /* file name */
179};
180
181#define IOREAD 1 /* < */
182#define IOHERE 2 /* << (here file) */
183#define IOWRITE 4 /* > */
184#define IOCAT 8 /* >> */
185#define IOXHERE 16 /* ${}, ` in << */
186#define IODUP 32 /* >&digit */
187#define IOCLOSE 64 /* >&- */
188
189#define IODEFAULT (-1) /* token for default IO unit */
190
191
192/*
193 * Description of a command or an operation on commands.
194 * Might eventually use a union.
195 */
196struct op {
197 int type; /* operation type, see below */
198 char **words; /* arguments to a command */
199 struct ioword **ioact; /* IO actions (eg, < > >>) */
200 struct op *left;
201 struct op *right;
202 char *str; /* identifier for case and for */
203};
204
205#define TCOM 1 /* command */
206#define TPAREN 2 /* (c-list) */
207#define TPIPE 3 /* a | b */
208#define TLIST 4 /* a [&;] b */
209#define TOR 5 /* || */
210#define TAND 6 /* && */
211#define TFOR 7
212#define TDO 8
213#define TCASE 9
214#define TIF 10
215#define TWHILE 11
216#define TUNTIL 12
217#define TELIF 13
218#define TPAT 14 /* pattern in case */
219#define TBRACE 15 /* {c-list} */
220#define TASYNC 16 /* c & */
221/* Added to support "." file expansion */
222#define TDOT 17
223
224/* Strings for names to make debug easier */
225#ifdef MSHDEBUG
226static const char *const T_CMD_NAMES[] = {
227 "PLACEHOLDER",
228 "TCOM",
229 "TPAREN",
230 "TPIPE",
231 "TLIST",
232 "TOR",
233 "TAND",
234 "TFOR",
235 "TDO",
236 "TCASE",
237 "TIF",
238 "TWHILE",
239 "TUNTIL",
240 "TELIF",
241 "TPAT",
242 "TBRACE",
243 "TASYNC",
244 "TDOT",
245};
246#endif
247
248/*
249 * actions determining the environment of a process
250 */
251#define FEXEC 1 /* execute without forking */
252
253#define AREASIZE (90000)
254
255/*
256 * flags to control evaluation of words
257 */
258#define DOSUB 1 /* interpret $, `, and quotes */
259#define DOBLANK 2 /* perform blank interpretation */
260#define DOGLOB 4 /* interpret [?* */
261#define DOKEY 8 /* move words with `=' to 2nd arg. list */
262#define DOTRIM 16 /* trim resulting string */
263
264#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
265
266
267struct brkcon {
268 jmp_buf brkpt;
269 struct brkcon *nextlev;
270};
271
272
273/*
274 * flags:
275 * -e: quit on error
276 * -k: look for name=value everywhere on command line
277 * -n: no execution
278 * -t: exit after reading and executing one command
279 * -v: echo as read
280 * -x: trace
281 * -u: unset variables net diagnostic
282 */
283static char flags['z' - 'a' + 1] ALIGN1;
284/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
285#define FLAG (flags - 'a')
286
287/* moved to G: static char *trap[_NSIG + 1]; */
288/* moved to G: static char ourtrap[_NSIG + 1]; */
289static int trapset; /* trap pending */
290
291static int yynerrs; /* yacc */
292
293/* moved to G: static char line[LINELIM]; */
294
295#if ENABLE_FEATURE_EDITING
296static char *current_prompt;
297static line_input_t *line_input_state;
298#endif
299
300
301/*
302 * other functions
303 */
304static const char *rexecve(char *c, char **v, char **envp);
305static char *evalstr(char *cp, int f);
306static char *putn(int n);
307static char *unquote(char *as);
308static int rlookup(char *n);
309static struct wdblock *glob(char *cp, struct wdblock *wb);
310static int my_getc(int ec);
311static int subgetc(char ec, int quoted);
312static char **makenv(int all, struct wdblock *wb);
313static char **eval(char **ap, int f);
314static int setstatus(int s);
315static int waitfor(int lastpid, int canintr);
316
317static void onintr(int s); /* SIGINT handler */
318
319static int newenv(int f);
320static void quitenv(void);
321static void next(int f);
322static void setdash(void);
323static void onecommand(void);
324static void runtrap(int i);
325
326
327/* -------- area stuff -------- */
328
329#define REGSIZE sizeof(struct region)
330#define GROWBY (256)
331/* #define SHRINKBY (64) */
332#undef SHRINKBY
333#define FREE (32767)
334#define BUSY (0)
335#define ALIGN (sizeof(int)-1)
336
337
338struct region {
339 struct region *next;
340 int area;
341};
342
343
344/* -------- grammar stuff -------- */
345typedef union {
346 char *cp;
347 char **wp;
348 int i;
349 struct op *o;
350} YYSTYPE;
351
352#define WORD 256
353#define LOGAND 257
354#define LOGOR 258
355#define BREAK 259
356#define IF 260
357#define THEN 261
358#define ELSE 262
359#define ELIF 263
360#define FI 264
361#define CASE 265
362#define ESAC 266
363#define FOR 267
364#define WHILE 268
365#define UNTIL 269
366#define DO 270
367#define DONE 271
368#define IN 272
369/* Added for "." file expansion */
370#define DOT 273
371
372#define YYERRCODE 300
373
374/* flags to yylex */
375#define CONTIN 01 /* skip new lines to complete command */
376
377static struct op *pipeline(int cf);
378static struct op *andor(void);
379static struct op *c_list(void);
380static int synio(int cf);
381static void musthave(int c, int cf);
382static struct op *simple(void);
383static struct op *nested(int type, int mark);
384static struct op *command(int cf);
385static struct op *dogroup(int onlydone);
386static struct op *thenpart(void);
387static struct op *elsepart(void);
388static struct op *caselist(void);
389static struct op *casepart(void);
390static char **pattern(void);
391static char **wordlist(void);
392static struct op *list(struct op *t1, struct op *t2);
393static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
394static struct op *newtp(void);
395static struct op *namelist(struct op *t);
396static char **copyw(void);
397static void word(char *cp);
398static struct ioword **copyio(void);
399static struct ioword *io(int u, int f, char *cp);
400static int yylex(int cf);
401static int collect(int c, int c1);
402static int dual(int c);
403static void diag(int ec);
404static char *tree(unsigned size);
405
406/* -------- var.h -------- */
407
408struct var {
409 char *value;
410 char *name;
411 struct var *next;
412 char status;
413};
414
415#define COPYV 1 /* flag to setval, suggesting copy */
416#define RONLY 01 /* variable is read-only */
417#define EXPORT 02 /* variable is to be exported */
418#define GETCELL 04 /* name & value space was got with getcell */
419
420static int yyparse(void);
421
422static int execute(struct op *t, int *pin, int *pout, int act);
423
424
425#define AFID_NOBUF (~0)
426#define AFID_ID 0
427
428
429/* -------- io.h -------- */
430/* io buffer */
431struct iobuf {
432 unsigned id; /* buffer id */
433 char buf[512]; /* buffer */
434 char *bufp; /* pointer into buffer */
435 char *ebufp; /* pointer to end of buffer */
436};
437
438/* possible arguments to an IO function */
439struct ioarg {
440 const char *aword;
441 char **awordlist;
442 int afile; /* file descriptor */
443 unsigned afid; /* buffer id */
444 long afpos; /* file position */
445 struct iobuf *afbuf; /* buffer for this file */
446};
447
448/* an input generator's state */
449struct io {
450 int (*iofn) (struct ioarg *, struct io *);
451 struct ioarg *argp;
452 int peekc;
453 char prev; /* previous character read by readc() */
454 char nlcount; /* for `'s */
455 char xchar; /* for `'s */
456 char task; /* reason for pushed IO */
457};
458
459#define XOTHER 0 /* none of the below */
460#define XDOLL 1 /* expanding ${} */
461#define XGRAVE 2 /* expanding `'s */
462#define XIO 3 /* file IO */
463
464/* in substitution */
465#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
466
467static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
468/* moved to G: static struct ioarg ioargstack[NPUSH]; */
469static struct io iostack[NPUSH];
470/* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */
471/* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */
472static unsigned bufid = AFID_ID; /* buffer id counter */
473
474#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
475
476
477/*
478 * input generators for IO structure
479 */
480static int nlchar(struct ioarg *ap);
481static int strchar(struct ioarg *ap);
482static int qstrchar(struct ioarg *ap);
483static int filechar(struct ioarg *ap);
484static int herechar(struct ioarg *ap);
485static int linechar(struct ioarg *ap);
486static int gravechar(struct ioarg *ap, struct io *iop);
487static int qgravechar(struct ioarg *ap, struct io *iop);
488static int dolchar(struct ioarg *ap);
489static int wdchar(struct ioarg *ap);
490static void scraphere(void);
491static void freehere(int area);
492static void gethere(void);
493static void markhere(char *s, struct ioword *iop);
494static int herein(char *hname, int xdoll);
495static int run(struct ioarg *argp, int (*f) (struct ioarg *));
496
497
498static int eofc(void);
499static int readc(void);
500static void unget(int c);
501static void ioecho(char c);
502
503
504/*
505 * IO control
506 */
507static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
508#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
509static int remap(int fd);
510static int openpipe(int *pv);
511static void closepipe(int *pv);
512static struct io *setbase(struct io *ip);
513
514/* -------- word.h -------- */
515
516#define NSTART 16 /* default number of words to allow for initially */
517
518struct wdblock {
519 short w_bsize;
520 short w_nword;
521 /* bounds are arbitrary */
522 char *w_words[1];
523};
524
525static struct wdblock *addword(char *wd, struct wdblock *wb);
526static struct wdblock *newword(int nw);
527static char **getwords(struct wdblock *wb);
528
529/* -------- misc stuff -------- */
530
531static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
532static int iosetup(struct ioword *iop, int pipein, int pipeout);
533static void brkset(struct brkcon *bc);
534static int dolabel(struct op *t);
535static int dohelp(struct op *t);
536static int dochdir(struct op *t);
537static int doshift(struct op *t);
538static int dologin(struct op *t);
539static int doumask(struct op *t);
540static int doexec(struct op *t);
541static int dodot(struct op *t);
542static int dowait(struct op *t);
543static int doread(struct op *t);
544static int doeval(struct op *t);
545static int dotrap(struct op *t);
546static int getsig(char *s);
547static void setsig(int n, sighandler_t f);
548static int getn(char *as);
549static int dobreak(struct op *t);
550static int docontinue(struct op *t);
551static int brkcontin(char *cp, int val);
552static int doexit(struct op *t);
553static int doexport(struct op *t);
554static int doreadonly(struct op *t);
555static void rdexp(char **wp, void (*f) (struct var *), int key);
556static void badid(char *s);
557static int doset(struct op *t);
558static void varput(char *s, int out);
559static int dotimes(struct op *t);
560static int expand(const char *cp, struct wdblock **wbp, int f);
561static char *blank(int f);
562static int dollar(int quoted);
563static int grave(int quoted);
564static void globname(char *we, char *pp);
565static char *generate(char *start1, char *end1, char *middle, char *end);
566static int anyspcl(struct wdblock *wb);
567static int xstrcmp(char *p1, char *p2);
568static void glob0(char *a0, unsigned a1, int a2,
569 int (*a3) (char *, char *));
570static void readhere(char **name, char *s, int ec);
571static int xxchar(struct ioarg *ap);
572
573struct here {
574 char *h_tag;
575 int h_dosub;
576 struct ioword *h_iop;
577 struct here *h_next;
578};
579
580static const char *const signame[] = {
581 "Signal 0",
582 "Hangup",
583 NULL, /* interrupt */
584 "Quit",
585 "Illegal instruction",
586 "Trace/BPT trap",
587 "Abort",
588 "Bus error",
589 "Floating Point Exception",
590 "Killed",
591 "SIGUSR1",
592 "SIGSEGV",
593 "SIGUSR2",
594 NULL, /* broken pipe */
595 "Alarm clock",
596 "Terminated"
597};
598
599
600struct res {
601 const char *r_name;
602 int r_val;
603};
604static const struct res restab[] = {
605 { "for" , FOR },
606 { "case" , CASE },
607 { "esac" , ESAC },
608 { "while", WHILE },
609 { "do" , DO },
610 { "done" , DONE },
611 { "if" , IF },
612 { "in" , IN },
613 { "then" , THEN },
614 { "else" , ELSE },
615 { "elif" , ELIF },
616 { "until", UNTIL },
617 { "fi" , FI },
618 { ";;" , BREAK },
619 { "||" , LOGOR },
620 { "&&" , LOGAND },
621 { "{" , '{' },
622 { "}" , '}' },
623 { "." , DOT },
624 { NULL , 0 },
625};
626
627struct builtincmd {
628 const char *name;
629 int (*builtinfunc)(struct op *t);
630};
631static const struct builtincmd builtincmds[] = {
632 { "." , dodot },
633 { ":" , dolabel },
634 { "break" , dobreak },
635 { "cd" , dochdir },
636 { "continue", docontinue },
637 { "eval" , doeval },
638 { "exec" , doexec },
639 { "exit" , doexit },
640 { "export" , doexport },
641 { "help" , dohelp },
642 { "login" , dologin },
643 { "newgrp" , dologin },
644 { "read" , doread },
645 { "readonly", doreadonly },
646 { "set" , doset },
647 { "shift" , doshift },
648 { "times" , dotimes },
649 { "trap" , dotrap },
650 { "umask" , doumask },
651 { "wait" , dowait },
652 { NULL , NULL },
653};
654
655static struct op *scantree(struct op *);
656static struct op *dowholefile(int, int);
657
658
659/* Globals */
660static char **dolv;
661static int dolc;
662static int exstat;
663static char gflg;
664static int interactive; /* Is this an interactive shell */
665static int execflg;
666static int multiline; /* \n changed to ; */
667static struct op *outtree; /* result from parser */
668static xint *failpt;
669static xint *errpt;
670static struct brkcon *brklist;
671static int isbreak;
672static struct wdblock *wdlist;
673static struct wdblock *iolist;
674
675#ifdef MSHDEBUG
676static struct var *mshdbg_var;
677#endif
678static struct var *vlist; /* dictionary */
679static struct var *homedir; /* home directory */
680static struct var *prompt; /* main prompt */
681static struct var *cprompt; /* continuation prompt */
682static struct var *path; /* search path for commands */
683static struct var *shell; /* shell to interpret command files */
684static struct var *ifs; /* field separators */
685
686static int areanum; /* current allocation area */
687static int intr; /* interrupt pending */
688static int inparse;
689static char *null = (char*)""; /* null value for variable */
690static int heedint = 1; /* heed interrupt signals */
691static void (*qflag)(int) = SIG_IGN;
692static int startl;
693static int peeksym;
694static int nlseen;
695static int iounit = IODEFAULT;
696static YYSTYPE yylval;
697static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
698
699static struct here *inhere; /* list of hear docs while parsing */
700static struct here *acthere; /* list of active here documents */
701static struct region *areabot; /* bottom of area */
702static struct region *areatop; /* top of area */
703static struct region *areanxt; /* starting point of scan */
704static void *brktop;
705static void *brkaddr;
706
707/*
708 * parsing & execution environment
709 */
710struct env {
711 char *linep;
712 struct io *iobase;
713 struct io *iop;
714 xint *errpt; /* void * */
715 int iofd;
716 struct env *oenv;
717};
718
719static struct env e = {
720 NULL /* set to line in main() */, /* linep: char ptr */
721 iostack, /* iobase: struct io ptr */
722 iostack - 1, /* iop: struct io ptr */
723 (xint *) NULL, /* errpt: void ptr for errors? */
724 FDBASE, /* iofd: file desc */
725 (struct env *) NULL /* oenv: struct env ptr */
726};
727
728
729struct globals {
730 char ourtrap[_NSIG + 1];
731 char *trap[_NSIG + 1];
732 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
733 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
734 struct ioarg ioargstack[NPUSH];
735 char filechar_cmdbuf[BUFSIZ];
736 char line[LINELIM];
737 char child_cmd[LINELIM];
738};
739
740#define G (*ptr_to_globals)
741#define ourtrap (G.ourtrap )
742#define trap (G.trap )
743#define sharedbuf (G.sharedbuf )
744#define mainbuf (G.mainbuf )
745#define ioargstack (G.ioargstack )
746#define filechar_cmdbuf (G.filechar_cmdbuf)
747#define line (G.line )
748#define child_cmd (G.child_cmd )
749
750
751#ifdef MSHDEBUG
752void print_t(struct op *t)
753{
754 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
755 T_CMD_NAMES[t->type], t->words, t->ioact));
756
757 if (t->words) {
758 DBGPRINTF(("T: W1: %s", t->words[0]));
759 }
760}
761
762void print_tree(struct op *head)
763{
764 if (head == NULL) {
765 DBGPRINTF(("PRINT_TREE: no tree\n"));
766 return;
767 }
768
769 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
770 head->right));
771
772 if (head->left)
773 print_tree(head->left);
774
775 if (head->right)
776 print_tree(head->right);
777}
778#endif /* MSHDEBUG */
779
780
781/*
782 * IO functions
783 */
784static void prs(const char *s)
785{
786 if (*s)
787 write(2, s, strlen(s));
788}
789
790static void prn(unsigned u)
791{
792 prs(itoa(u));
793}
794
795static void echo(char **wp)
796{
797 int i;
798
799 prs("+");
800 for (i = 0; wp[i]; i++) {
801 if (i)
802 prs(" ");
803 prs(wp[i]);
804 }
805 prs("\n");
806}
807
808static void closef(int i)
809{
810 if (i > 2)
811 close(i);
812}
813
814static void closeall(void)
815{
816 int u;
817
818 for (u = NUFILE; u < NOFILE;)
819 close(u++);
820}
821
822
823/* fail but return to process next command */
824static void fail(void) ATTRIBUTE_NORETURN;
825static void fail(void)
826{
827 longjmp(failpt, 1);
828 /* NOTREACHED */
829}
830
831/* abort shell (or fail in subshell) */
832static void leave(void) ATTRIBUTE_NORETURN;
833static void leave(void)
834{
835 DBGPRINTF(("LEAVE: leave called!\n"));
836
837 if (execflg)
838 fail();
839 scraphere();
840 freehere(1);
841 runtrap(0);
842 _exit(exstat);
843 /* NOTREACHED */
844}
845
846static void warn(const char *s)
847{
848 if (*s) {
849 prs(s);
850 exstat = -1;
851 }
852 prs("\n");
853 if (FLAG['e'])
854 leave();
855}
856
857static void err(const char *s)
858{
859 warn(s);
860 if (FLAG['n'])
861 return;
862 if (!interactive)
863 leave();
864 if (e.errpt)
865 longjmp(e.errpt, 1);
866 closeall();
867 e.iop = e.iobase = iostack;
868}
869
870
871/* -------- area.c -------- */
872
873/*
874 * All memory between (char *)areabot and (char *)(areatop+1) is
875 * exclusively administered by the area management routines.
876 * It is assumed that sbrk() and brk() manipulate the high end.
877 */
878
879#define sbrk(X) ({ \
880 void * __q = (void *)-1; \
881 if (brkaddr + (int)(X) < brktop) { \
882 __q = brkaddr; \
883 brkaddr += (int)(X); \
884 } \
885 __q; \
886})
887
888static void initarea(void)
889{
890 brkaddr = xmalloc(AREASIZE);
891 brktop = brkaddr + AREASIZE;
892
893 while ((long) sbrk(0) & ALIGN)
894 sbrk(1);
895 areabot = (struct region *) sbrk(REGSIZE);
896
897 areabot->next = areabot;
898 areabot->area = BUSY;
899 areatop = areabot;
900 areanxt = areabot;
901}
902
903static char *getcell(unsigned nbytes)
904{
905 int nregio;
906 struct region *p, *q;
907 int i;
908
909 if (nbytes == 0) {
910 puts("getcell(0)");
911 abort();
912 }
913 /* silly and defeats the algorithm */
914 /*
915 * round upwards and add administration area
916 */
917 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
918 p = areanxt;
919 for (;;) {
920 if (p->area > areanum) {
921 /*
922 * merge free cells
923 */
924 while ((q = p->next)->area > areanum && q != areanxt)
925 p->next = q->next;
926 /*
927 * exit loop if cell big enough
928 */
929 if (q >= p + nregio)
930 goto found;
931 }
932 p = p->next;
933 if (p == areanxt)
934 break;
935 }
936 i = nregio >= GROWBY ? nregio : GROWBY;
937 p = (struct region *) sbrk(i * REGSIZE);
938 if (p == (struct region *) -1)
939 return NULL;
940 p--;
941 if (p != areatop) {
942 puts("not contig");
943 abort(); /* allocated areas are contiguous */
944 }
945 q = p + i;
946 p->next = q;
947 p->area = FREE;
948 q->next = areabot;
949 q->area = BUSY;
950 areatop = q;
951 found:
952 /*
953 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
954 */
955 areanxt = p + nregio;
956 if (areanxt < q) {
957 /*
958 * split into requested area and rest
959 */
960 if (areanxt + 1 > q) {
961 puts("OOM");
962 abort(); /* insufficient space left for admin */
963 }
964 areanxt->next = q;
965 areanxt->area = FREE;
966 p->next = areanxt;
967 }
968 p->area = areanum;
969 return (char *) (p + 1);
970}
971
972static void freecell(char *cp)
973{
974 struct region *p;
975
976 p = (struct region *) cp;
977 if (p != NULL) {
978 p--;
979 if (p < areanxt)
980 areanxt = p;
981 p->area = FREE;
982 }
983}
984#define DELETE(obj) freecell((char *)obj)
985
986static void freearea(int a)
987{
988 struct region *p, *top;
989
990 top = areatop;
991 for (p = areabot; p != top; p = p->next)
992 if (p->area >= a)
993 p->area = FREE;
994}
995
996static void setarea(char *cp, int a)
997{
998 struct region *p;
999
1000 p = (struct region *) cp;
1001 if (p != NULL)
1002 (p - 1)->area = a;
1003}
1004
1005static int getarea(char *cp)
1006{
1007 return ((struct region *) cp - 1)->area;
1008}
1009
1010static void garbage(void)
1011{
1012 struct region *p, *q, *top;
1013
1014 top = areatop;
1015 for (p = areabot; p != top; p = p->next) {
1016 if (p->area > areanum) {
1017 while ((q = p->next)->area > areanum)
1018 p->next = q->next;
1019 areanxt = p;
1020 }
1021 }
1022#ifdef SHRINKBY
1023 if (areatop >= q + SHRINKBY && q->area > areanum) {
1024 brk((char *) (q + 1));
1025 q->next = areabot;
1026 q->area = BUSY;
1027 areatop = q;
1028 }
1029#endif
1030}
1031
1032static char *space(int n)
1033{
1034 char *cp;
1035
1036 cp = getcell(n);
1037 if (cp == NULL)
1038 err("out of string space");
1039 return cp;
1040}
1041
1042static char *strsave(const char *s, int a)
1043{
1044 char *cp;
1045
1046 cp = space(strlen(s) + 1);
1047 if (cp == NULL) {
1048// FIXME: I highly doubt this is good.
1049 return (char*)"";
1050 }
1051 setarea(cp, a);
1052 strcpy(cp, s);
1053 return cp;
1054}
1055
1056
1057/* -------- var.c -------- */
1058
1059static int eqname(const char *n1, const char *n2)
1060{
1061 for (; *n1 != '=' && *n1 != '\0'; n1++)
1062 if (*n2++ != *n1)
1063 return 0;
1064 return *n2 == '\0' || *n2 == '=';
1065}
1066
1067static const char *findeq(const char *cp)
1068{
1069 while (*cp != '\0' && *cp != '=')
1070 cp++;
1071 return cp;
1072}
1073
1074/*
1075 * Find the given name in the dictionary
1076 * and return its value. If the name was
1077 * not previously there, enter it now and
1078 * return a null value.
1079 */
1080static struct var *lookup(const char *n)
1081{
1082// FIXME: dirty hack
1083 static struct var dummy;
1084
1085 struct var *vp;
1086 const char *cp;
1087 char *xp;
1088 int c;
1089
1090 if (isdigit(*n)) {
1091 dummy.name = (char*)n;
1092 for (c = 0; isdigit(*n) && c < 1000; n++)
1093 c = c * 10 + *n - '0';
1094 dummy.status = RONLY;
1095 dummy.value = (c <= dolc ? dolv[c] : null);
1096 return &dummy;
1097 }
1098
1099 for (vp = vlist; vp; vp = vp->next)
1100 if (eqname(vp->name, n))
1101 return vp;
1102
1103 cp = findeq(n);
1104 vp = (struct var *) space(sizeof(*vp));
1105 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
1106 dummy.name = dummy.value = (char*)"";
1107 return &dummy;
1108 }
1109
1110 xp = vp->name;
1111 while ((*xp = *n++) != '\0' && *xp != '=')
1112 xp++;
1113 *xp++ = '=';
1114 *xp = '\0';
1115 setarea((char *) vp, 0);
1116 setarea((char *) vp->name, 0);
1117 vp->value = null;
1118 vp->next = vlist;
1119 vp->status = GETCELL;
1120 vlist = vp;
1121 return vp;
1122}
1123
1124/*
1125 * if name is not NULL, it must be
1126 * a prefix of the space `val',
1127 * and end with `='.
1128 * this is all so that exporting
1129 * values is reasonably painless.
1130 */
1131static void nameval(struct var *vp, const char *val, const char *name)
1132{
1133 const char *cp;
1134 char *xp;
1135 int fl;
1136
1137 if (vp->status & RONLY) {
1138 xp = vp->name;
1139 while (*xp && *xp != '=')
1140 putc(*xp++, stderr);
1141 err(" is read-only");
1142 return;
1143 }
1144 fl = 0;
1145 if (name == NULL) {
1146 xp = space(strlen(vp->name) + strlen(val) + 2);
1147 if (xp == NULL)
1148 return;
1149 /* make string: name=value */
1150 setarea(xp, 0);
1151 name = xp;
1152 cp = vp->name;
1153 while ((*xp = *cp++) != '\0' && *xp != '=')
1154 xp++;
1155 *xp++ = '=';
1156 strcpy(xp, val);
1157 val = xp;
1158 fl = GETCELL;
1159 }
1160 if (vp->status & GETCELL)
1161 freecell(vp->name); /* form new string `name=value' */
1162 vp->name = (char*)name;
1163 vp->value = (char*)val;
1164 vp->status |= fl;
1165}
1166
1167/*
1168 * give variable at `vp' the value `val'.
1169 */
1170static void setval(struct var *vp, const char *val)
1171{
1172 nameval(vp, val, NULL);
1173}
1174
1175static void export(struct var *vp)
1176{
1177 vp->status |= EXPORT;
1178}
1179
1180static void ronly(struct var *vp)
1181{
1182 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1183 vp->status |= RONLY;
1184}
1185
1186static int isassign(const char *s)
1187{
1188 unsigned char c;
1189 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1190
1191 c = *s;
1192 /* no isalpha() - we shouldn't use locale */
1193 /* c | 0x20 - lowercase (Latin) letters */
1194 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1195 /* not letter */
1196 return 0;
1197
1198 while (1) {
1199 c = *++s;
1200 if (c == '=')
1201 return 1;
1202 if (c == '\0')
1203 return 0;
1204 if (c != '_'
1205 && (unsigned)(c - '0') > 9 /* not number */
1206 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
1207 ) {
1208 return 0;
1209 }
1210 }
1211}
1212
1213static int assign(const char *s, int cf)
1214{
1215 const char *cp;
1216 struct var *vp;
1217
1218 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1219
1220 if (!isalpha(*s) && *s != '_')
1221 return 0;
1222 for (cp = s; *cp != '='; cp++)
1223 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1224 return 0;
1225 vp = lookup(s);
1226 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1227 if (cf != COPYV)
1228 vp->status &= ~GETCELL;
1229 return 1;
1230}
1231
1232static int checkname(char *cp)
1233{
1234 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1235
1236 if (!isalpha(*cp++) && *(cp - 1) != '_')
1237 return 0;
1238 while (*cp)
1239 if (!isalnum(*cp++) && *(cp - 1) != '_')
1240 return 0;
1241 return 1;
1242}
1243
1244static void putvlist(int f, int out)
1245{
1246 struct var *vp;
1247
1248 for (vp = vlist; vp; vp = vp->next) {
1249 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1250 if (vp->status & EXPORT)
1251 write(out, "export ", 7);
1252 if (vp->status & RONLY)
1253 write(out, "readonly ", 9);
1254 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1255 write(out, "\n", 1);
1256 }
1257 }
1258}
1259
1260
1261/*
1262 * trap handling
1263 */
1264static void sig(int i)
1265{
1266 trapset = i;
1267 signal(i, sig);
1268}
1269
1270static void runtrap(int i)
1271{
1272 char *trapstr;
1273
1274 trapstr = trap[i];
1275 if (trapstr == NULL)
1276 return;
1277
1278 if (i == 0)
1279 trap[i] = NULL;
1280
1281 RUN(aword, trapstr, nlchar);
1282}
1283
1284
1285static void setdash(void)
1286{
1287 char *cp;
1288 int c;
1289 char m['z' - 'a' + 1];
1290
1291 cp = m;
1292 for (c = 'a'; c <= 'z'; c++)
1293 if (FLAG[c])
1294 *cp++ = c;
1295 *cp = '\0';
1296 setval(lookup("-"), m);
1297}
1298
1299static int newfile(char *s)
1300{
1301 int f;
1302
1303 DBGPRINTF7(("NEWFILE: opening %s\n", s));
1304
1305 f = 0;
1306 if (NOT_LONE_DASH(s)) {
1307 DBGPRINTF(("NEWFILE: s is %s\n", s));
1308 f = open(s, O_RDONLY);
1309 if (f < 0) {
1310 prs(s);
1311 err(": cannot open");
1312 return 1;
1313 }
1314 }
1315
1316 next(remap(f));
1317 return 0;
1318}
1319
1320
1321struct op *scantree(struct op *head)
1322{
1323 struct op *dotnode;
1324
1325 if (head == NULL)
1326 return NULL;
1327
1328 if (head->left != NULL) {
1329 dotnode = scantree(head->left);
1330 if (dotnode)
1331 return dotnode;
1332 }
1333
1334 if (head->right != NULL) {
1335 dotnode = scantree(head->right);
1336 if (dotnode)
1337 return dotnode;
1338 }
1339
1340 if (head->words == NULL)
1341 return NULL;
1342
1343 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1344
1345 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
1346 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1347 return head;
1348 }
1349
1350 return NULL;
1351}
1352
1353
1354static void onecommand(void)
1355{
1356 int i;
1357 jmp_buf m1;
1358
1359 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
1360
1361 while (e.oenv)
1362 quitenv();
1363
1364 areanum = 1;
1365 freehere(areanum);
1366 freearea(areanum);
1367 garbage();
1368 wdlist = 0;
1369 iolist = 0;
1370 e.errpt = 0;
1371 e.linep = line;
1372 yynerrs = 0;
1373 multiline = 0;
1374 inparse = 1;
1375 intr = 0;
1376 execflg = 0;
1377
1378 failpt = m1;
1379 setjmp(failpt); /* Bruce Evans' fix */
1380 failpt = m1;
1381 if (setjmp(failpt) || yyparse() || intr) {
1382 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1383
1384 while (e.oenv)
1385 quitenv();
1386 scraphere();
1387 if (!interactive && intr)
1388 leave();
1389 inparse = 0;
1390 intr = 0;
1391 return;
1392 }
1393
1394 inparse = 0;
1395 brklist = 0;
1396 intr = 0;
1397 execflg = 0;
1398
1399 if (!FLAG['n']) {
1400 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1401 outtree));
1402 execute(outtree, NOPIPE, NOPIPE, 0);
1403 }
1404
1405 if (!interactive && intr) {
1406 execflg = 0;
1407 leave();
1408 }
1409
1410 i = trapset;
1411 if (i != 0) {
1412 trapset = 0;
1413 runtrap(i);
1414 }
1415}
1416
1417static int newenv(int f)
1418{
1419 struct env *ep;
1420
1421 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1422
1423 if (f) {
1424 quitenv();
1425 return 1;
1426 }
1427
1428 ep = (struct env *) space(sizeof(*ep));
1429 if (ep == NULL) {
1430 while (e.oenv)
1431 quitenv();
1432 fail();
1433 }
1434 *ep = e;
1435 e.oenv = ep;
1436 e.errpt = errpt;
1437
1438 return 0;
1439}
1440
1441static void quitenv(void)
1442{
1443 struct env *ep;
1444 int fd;
1445
1446 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
1447
1448 ep = e.oenv;
1449 if (ep != NULL) {
1450 fd = e.iofd;
1451 e = *ep;
1452 /* should close `'d files */
1453 DELETE(ep);
1454 while (--fd >= e.iofd)
1455 close(fd);
1456 }
1457}
1458
1459/*
1460 * Is character c in s?
1461 */
1462static int any(int c, const char *s)
1463{
1464 while (*s)
1465 if (*s++ == c)
1466 return 1;
1467 return 0;
1468}
1469
1470/*
1471 * Is any character from s1 in s2?
1472 */
1473static int anys(const char *s1, const char *s2)
1474{
1475 while (*s1)
1476 if (any(*s1++, s2))
1477 return 1;
1478 return 0;
1479}
1480
1481static char *putn(int n)
1482{
1483 return itoa(n);
1484}
1485
1486static void next(int f)
1487{
1488 PUSHIO(afile, f, filechar);
1489}
1490
1491static void onintr(int s) /* ANSI C requires a parameter */
1492{
1493 signal(SIGINT, onintr);
1494 intr = 1;
1495 if (interactive) {
1496 if (inparse) {
1497 prs("\n");
1498 fail();
1499 }
1500 } else if (heedint) {
1501 execflg = 0;
1502 leave();
1503 }
1504}
1505
1506
1507/* -------- gmatch.c -------- */
1508/*
1509 * int gmatch(string, pattern)
1510 * char *string, *pattern;
1511 *
1512 * Match a pattern as in sh(1).
1513 */
1514
1515#define CMASK 0377
1516#define QUOTE 0200
1517#define QMASK (CMASK & ~QUOTE)
1518#define NOT '!' /* might use ^ */
1519
1520static const char *cclass(const char *p, int sub)
1521{
1522 int c, d, not, found;
1523
1524 not = (*p == NOT);
1525 if (not != 0)
1526 p++;
1527 found = not;
1528 do {
1529 if (*p == '\0')
1530 return NULL;
1531 c = *p & CMASK;
1532 if (p[1] == '-' && p[2] != ']') {
1533 d = p[2] & CMASK;
1534 p++;
1535 } else
1536 d = c;
1537 if (c == sub || (c <= sub && sub <= d))
1538 found = !not;
1539 } while (*++p != ']');
1540 return found ? p + 1 : NULL;
1541}
1542
1543static int gmatch(const char *s, const char *p)
1544{
1545 int sc, pc;
1546
1547 if (s == NULL || p == NULL)
1548 return 0;
1549
1550 while ((pc = *p++ & CMASK) != '\0') {
1551 sc = *s++ & QMASK;
1552 switch (pc) {
1553 case '[':
1554 p = cclass(p, sc);
1555 if (p == NULL)
1556 return 0;
1557 break;
1558
1559 case '?':
1560 if (sc == 0)
1561 return 0;
1562 break;
1563
1564 case '*':
1565 s--;
1566 do {
1567 if (*p == '\0' || gmatch(s, p))
1568 return 1;
1569 } while (*s++ != '\0');
1570 return 0;
1571
1572 default:
1573 if (sc != (pc & ~QUOTE))
1574 return 0;
1575 }
1576 }
1577 return *s == '\0';
1578}
1579
1580
1581/* -------- csyn.c -------- */
1582/*
1583 * shell: syntax (C version)
1584 */
1585
1586static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1587static void yyerror(const char *s)
1588{
1589 yynerrs++;
1590 if (interactive && e.iop <= iostack) {
1591 multiline = 0;
1592 while (eofc() == 0 && yylex(0) != '\n');
1593 }
1594 err(s);
1595 fail();
1596}
1597
1598static void zzerr(void) ATTRIBUTE_NORETURN;
1599static void zzerr(void)
1600{
1601 yyerror("syntax error");
1602}
1603
1604int yyparse(void)
1605{
1606 DBGPRINTF7(("YYPARSE: enter...\n"));
1607
1608 startl = 1;
1609 peeksym = 0;
1610 yynerrs = 0;
1611 outtree = c_list();
1612 musthave('\n', 0);
1613 return (yynerrs != 0);
1614}
1615
1616static struct op *pipeline(int cf)
1617{
1618 struct op *t, *p;
1619 int c;
1620
1621 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1622
1623 t = command(cf);
1624
1625 DBGPRINTF9(("PIPELINE: t=%p\n", t));
1626
1627 if (t != NULL) {
1628 while ((c = yylex(0)) == '|') {
1629 p = command(CONTIN);
1630 if (p == NULL) {
1631 DBGPRINTF8(("PIPELINE: error!\n"));
1632 zzerr();
1633 }
1634
1635 if (t->type != TPAREN && t->type != TCOM) {
1636 /* shell statement */
1637 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1638 }
1639
1640 t = block(TPIPE, t, p, NOWORDS);
1641 }
1642 peeksym = c;
1643 }
1644
1645 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
1646 return t;
1647}
1648
1649static struct op *andor(void)
1650{
1651 struct op *t, *p;
1652 int c;
1653
1654 DBGPRINTF7(("ANDOR: enter...\n"));
1655
1656 t = pipeline(0);
1657
1658 DBGPRINTF9(("ANDOR: t=%p\n", t));
1659
1660 if (t != NULL) {
1661 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1662 p = pipeline(CONTIN);
1663 if (p == NULL) {
1664 DBGPRINTF8(("ANDOR: error!\n"));
1665 zzerr();
1666 }
1667
1668 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1669 } /* WHILE */
1670
1671 peeksym = c;
1672 }
1673
1674 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
1675 return t;
1676}
1677
1678static struct op *c_list(void)
1679{
1680 struct op *t, *p;
1681 int c;
1682
1683 DBGPRINTF7(("C_LIST: enter...\n"));
1684
1685 t = andor();
1686
1687 if (t != NULL) {
1688 peeksym = yylex(0);
1689 if (peeksym == '&')
1690 t = block(TASYNC, t, NOBLOCK, NOWORDS);
1691
1692 while ((c = yylex(0)) == ';' || c == '&'
1693 || (multiline && c == '\n')) {
1694
1695 p = andor();
1696 if (p== NULL)
1697 return t;
1698
1699 peeksym = yylex(0);
1700 if (peeksym == '&')
1701 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1702
1703 t = list(t, p);
1704 } /* WHILE */
1705
1706 peeksym = c;
1707 }
1708 /* IF */
1709 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1710 return t;
1711}
1712
1713static int synio(int cf)
1714{
1715 struct ioword *iop;
1716 int i;
1717 int c;
1718
1719 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1720
1721 c = yylex(cf);
1722 if (c != '<' && c != '>') {
1723 peeksym = c;
1724 return 0;
1725 }
1726
1727 i = yylval.i;
1728 musthave(WORD, 0);
1729 iop = io(iounit, i, yylval.cp);
1730 iounit = IODEFAULT;
1731
1732 if (i & IOHERE)
1733 markhere(yylval.cp, iop);
1734
1735 DBGPRINTF7(("SYNIO: returning 1\n"));
1736 return 1;
1737}
1738
1739static void musthave(int c, int cf)
1740{
1741 peeksym = yylex(cf);
1742 if (peeksym != c) {
1743 DBGPRINTF7(("MUSTHAVE: error!\n"));
1744 zzerr();
1745 }
1746
1747 peeksym = 0;
1748}
1749
1750static struct op *simple(void)
1751{
1752 struct op *t;
1753
1754 t = NULL;
1755 for (;;) {
1756 switch (peeksym = yylex(0)) {
1757 case '<':
1758 case '>':
1759 (void) synio(0);
1760 break;
1761
1762 case WORD:
1763 if (t == NULL) {
1764 t = newtp();
1765 t->type = TCOM;
1766 }
1767 peeksym = 0;
1768 word(yylval.cp);
1769 break;
1770
1771 default:
1772 return t;
1773 }
1774 }
1775}
1776
1777static struct op *nested(int type, int mark)
1778{
1779 struct op *t;
1780
1781 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1782
1783 multiline++;
1784 t = c_list();
1785 musthave(mark, 0);
1786 multiline--;
1787 return block(type, t, NOBLOCK, NOWORDS);
1788}
1789
1790static struct op *command(int cf)
1791{
1792 struct op *t;
1793 struct wdblock *iosave;
1794 int c;
1795
1796 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1797
1798 iosave = iolist;
1799 iolist = NULL;
1800
1801 if (multiline)
1802 cf |= CONTIN;
1803
1804 while (synio(cf))
1805 cf = 0;
1806
1807 c = yylex(cf);
1808
1809 switch (c) {
1810 default:
1811 peeksym = c;
1812 t = simple();
1813 if (t == NULL) {
1814 if (iolist == NULL)
1815 return NULL;
1816 t = newtp();
1817 t->type = TCOM;
1818 }
1819 break;
1820
1821 case '(':
1822 t = nested(TPAREN, ')');
1823 break;
1824
1825 case '{':
1826 t = nested(TBRACE, '}');
1827 break;
1828
1829 case FOR:
1830 t = newtp();
1831 t->type = TFOR;
1832 musthave(WORD, 0);
1833 startl = 1;
1834 t->str = yylval.cp;
1835 multiline++;
1836 t->words = wordlist();
1837 c = yylex(0);
1838 if (c != '\n' && c != ';')
1839 peeksym = c;
1840 t->left = dogroup(0);
1841 multiline--;
1842 break;
1843
1844 case WHILE:
1845 case UNTIL:
1846 multiline++;
1847 t = newtp();
1848 t->type = c == WHILE ? TWHILE : TUNTIL;
1849 t->left = c_list();
1850 t->right = dogroup(1);
1851 t->words = NULL;
1852 multiline--;
1853 break;
1854
1855 case CASE:
1856 t = newtp();
1857 t->type = TCASE;
1858 musthave(WORD, 0);
1859 t->str = yylval.cp;
1860 startl++;
1861 multiline++;
1862 musthave(IN, CONTIN);
1863 startl++;
1864
1865 t->left = caselist();
1866
1867 musthave(ESAC, 0);
1868 multiline--;
1869 break;
1870
1871 case IF:
1872 multiline++;
1873 t = newtp();
1874 t->type = TIF;
1875 t->left = c_list();
1876 t->right = thenpart();
1877 musthave(FI, 0);
1878 multiline--;
1879 break;
1880
1881 case DOT:
1882 t = newtp();
1883 t->type = TDOT;
1884
1885 musthave(WORD, 0); /* gets name of file */
1886 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1887
1888 word(yylval.cp); /* add word to wdlist */
1889 word(NOWORD); /* terminate wdlist */
1890 t->words = copyw(); /* dup wdlist */
1891 break;
1892
1893 }
1894
1895 while (synio(0));
1896
1897 t = namelist(t);
1898 iolist = iosave;
1899
1900 DBGPRINTF(("COMMAND: returning %p\n", t));
1901
1902 return t;
1903}
1904
1905static struct op *dowholefile(int type, int mark)
1906{
1907 struct op *t;
1908
1909 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1910
1911 multiline++;
1912 t = c_list();
1913 multiline--;
1914 t = block(type, t, NOBLOCK, NOWORDS);
1915 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
1916 return t;
1917}
1918
1919static struct op *dogroup(int onlydone)
1920{
1921 int c;
1922 struct op *mylist;
1923
1924 c = yylex(CONTIN);
1925 if (c == DONE && onlydone)
1926 return NULL;
1927 if (c != DO)
1928 zzerr();
1929 mylist = c_list();
1930 musthave(DONE, 0);
1931 return mylist;
1932}
1933
1934static struct op *thenpart(void)
1935{
1936 int c;
1937 struct op *t;
1938
1939 c = yylex(0);
1940 if (c != THEN) {
1941 peeksym = c;
1942 return NULL;
1943 }
1944 t = newtp();
1945 t->type = 0;
1946 t->left = c_list();
1947 if (t->left == NULL)
1948 zzerr();
1949 t->right = elsepart();
1950 return t;
1951}
1952
1953static struct op *elsepart(void)
1954{
1955 int c;
1956 struct op *t;
1957
1958 switch (c = yylex(0)) {
1959 case ELSE:
1960 t = c_list();
1961 if (t == NULL)
1962 zzerr();
1963 return t;
1964
1965 case ELIF:
1966 t = newtp();
1967 t->type = TELIF;
1968 t->left = c_list();
1969 t->right = thenpart();
1970 return t;
1971
1972 default:
1973 peeksym = c;
1974 return NULL;
1975 }
1976}
1977
1978static struct op *caselist(void)
1979{
1980 struct op *t;
1981
1982 t = NULL;
1983 while ((peeksym = yylex(CONTIN)) != ESAC) {
1984 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
1985 t = list(t, casepart());
1986 }
1987
1988 DBGPRINTF(("CASELIST, returning t=%p\n", t));
1989 return t;
1990}
1991
1992static struct op *casepart(void)
1993{
1994 struct op *t;
1995
1996 DBGPRINTF7(("CASEPART: enter...\n"));
1997
1998 t = newtp();
1999 t->type = TPAT;
2000 t->words = pattern();
2001 musthave(')', 0);
2002 t->left = c_list();
2003 peeksym = yylex(CONTIN);
2004 if (peeksym != ESAC)
2005 musthave(BREAK, CONTIN);
2006
2007 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
2008
2009 return t;
2010}
2011
2012static char **pattern(void)
2013{
2014 int c, cf;
2015
2016 cf = CONTIN;
2017 do {
2018 musthave(WORD, cf);
2019 word(yylval.cp);
2020 cf = 0;
2021 c = yylex(0);
2022 } while (c == '|');
2023 peeksym = c;
2024 word(NOWORD);
2025
2026 return copyw();
2027}
2028
2029static char **wordlist(void)
2030{
2031 int c;
2032
2033 c = yylex(0);
2034 if (c != IN) {
2035 peeksym = c;
2036 return NULL;
2037 }
2038 startl = 0;
2039 while ((c = yylex(0)) == WORD)
2040 word(yylval.cp);
2041 word(NOWORD);
2042 peeksym = c;
2043 return copyw();
2044}
2045
2046/*
2047 * supporting functions
2048 */
2049static struct op *list(struct op *t1, struct op *t2)
2050{
2051 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
2052
2053 if (t1 == NULL)
2054 return t2;
2055 if (t2 == NULL)
2056 return t1;
2057
2058 return block(TLIST, t1, t2, NOWORDS);
2059}
2060
2061static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
2062{
2063 struct op *t;
2064
2065 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2066
2067 t = newtp();
2068 t->type = type;
2069 t->left = t1;
2070 t->right = t2;
2071 t->words = wp;
2072
2073 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
2074 t2));
2075
2076 return t;
2077}
2078
2079/* See if given string is a shell multiline (FOR, IF, etc) */
2080static int rlookup(char *n)
2081{
2082 const struct res *rp;
2083
2084 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2085
2086 for (rp = restab; rp->r_name; rp++)
2087 if (strcmp(rp->r_name, n) == 0) {
2088 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2089 return rp->r_val; /* Return numeric code for shell multiline */
2090 }
2091
2092 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2093 return 0; /* Not a shell multiline */
2094}
2095
2096static struct op *newtp(void)
2097{
2098 struct op *t;
2099
2100 t = (struct op *) tree(sizeof(*t));
2101 t->type = 0;
2102 t->words = NULL;
2103 t->ioact = NULL;
2104 t->left = NULL;
2105 t->right = NULL;
2106 t->str = NULL;
2107
2108 DBGPRINTF3(("NEWTP: allocated %p\n", t));
2109
2110 return t;
2111}
2112
2113static struct op *namelist(struct op *t)
2114{
2115 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
2116 T_CMD_NAMES[t->type], iolist));
2117
2118 if (iolist) {
2119 iolist = addword((char *) NULL, iolist);
2120 t->ioact = copyio();
2121 } else
2122 t->ioact = NULL;
2123
2124 if (t->type != TCOM) {
2125 if (t->type != TPAREN && t->ioact != NULL) {
2126 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2127 t->ioact = t->left->ioact;
2128 t->left->ioact = NULL;
2129 }
2130 return t;
2131 }
2132
2133 word(NOWORD);
2134 t->words = copyw();
2135
2136 return t;
2137}
2138
2139static char **copyw(void)
2140{
2141 char **wd;
2142
2143 wd = getwords(wdlist);
2144 wdlist = 0;
2145 return wd;
2146}
2147
2148static void word(char *cp)
2149{
2150 wdlist = addword(cp, wdlist);
2151}
2152
2153static struct ioword **copyio(void)
2154{
2155 struct ioword **iop;
2156
2157 iop = (struct ioword **) getwords(iolist);
2158 iolist = 0;
2159 return iop;
2160}
2161
2162static struct ioword *io(int u, int f, char *cp)
2163{
2164 struct ioword *iop;
2165
2166 iop = (struct ioword *) tree(sizeof(*iop));
2167 iop->io_unit = u;
2168 iop->io_flag = f;
2169 iop->io_name = cp;
2170 iolist = addword((char *) iop, iolist);
2171 return iop;
2172}
2173
2174static int yylex(int cf)
2175{
2176 int c, c1;
2177 int atstart;
2178
2179 c = peeksym;
2180 if (c > 0) {
2181 peeksym = 0;
2182 if (c == '\n')
2183 startl = 1;
2184 return c;
2185 }
2186
2187 nlseen = 0;
2188 atstart = startl;
2189 startl = 0;
2190 yylval.i = 0;
2191 e.linep = line;
2192
2193/* MALAMO */
2194 line[LINELIM - 1] = '\0';
2195
2196 loop:
2197 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2198 ;
2199
2200 switch (c) {
2201 default:
2202 if (any(c, "0123456789")) {
2203 c1 = my_getc(0);
2204 unget(c1);
2205 if (c1 == '<' || c1 == '>') {
2206 iounit = c - '0';
2207 goto loop;
2208 }
2209 *e.linep++ = c;
2210 c = c1;
2211 }
2212 break;
2213
2214 case '#': /* Comment, skip to next newline or End-of-string */
2215 while ((c = my_getc(0)) != '\0' && c != '\n');
2216 unget(c);
2217 goto loop;
2218
2219 case 0:
2220 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2221 return c;
2222
2223 case '$':
2224 DBGPRINTF9(("YYLEX: found $\n"));
2225 *e.linep++ = c;
2226 c = my_getc(0);
2227 if (c == '{') {
2228 c = collect(c, '}');
2229 if (c != '\0')
2230 return c;
2231 goto pack;
2232 }
2233 break;
2234
2235 case '`':
2236 case '\'':
2237 case '"':
2238 c = collect(c, c);
2239 if (c != '\0')
2240 return c;
2241 goto pack;
2242
2243 case '|':
2244 case '&':
2245 case ';':
2246 startl = 1;
2247 /* If more chars process them, else return NULL char */
2248 c1 = dual(c);
2249 if (c1 != '\0')
2250 return c1;
2251 return c;
2252
2253 case '^':
2254 startl = 1;
2255 return '|';
2256 case '>':
2257 case '<':
2258 diag(c);
2259 return c;
2260
2261 case '\n':
2262 nlseen++;
2263 gethere();
2264 startl = 1;
2265 if (multiline || cf & CONTIN) {
2266 if (interactive && e.iop <= iostack) {
2267#if ENABLE_FEATURE_EDITING
2268 current_prompt = cprompt->value;
2269#else
2270 prs(cprompt->value);
2271#endif
2272 }
2273 if (cf & CONTIN)
2274 goto loop;
2275 }
2276 return c;
2277
2278 case '(':
2279 case ')':
2280 startl = 1;
2281 return c;
2282 }
2283
2284 unget(c);
2285
2286 pack:
2287 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
2288 if (e.linep >= elinep)
2289 err("word too long");
2290 else
2291 *e.linep++ = c;
2292 };
2293
2294 unget(c);
2295
2296 if (any(c, "\"'`$"))
2297 goto loop;
2298
2299 *e.linep++ = '\0';
2300
2301 if (atstart) {
2302 c = rlookup(line);
2303 if (c != 0) {
2304 startl = 1;
2305 return c;
2306 }
2307 }
2308
2309 yylval.cp = strsave(line, areanum);
2310 return WORD;
2311}
2312
2313
2314static int collect(int c, int c1)
2315{
2316 char s[2];
2317
2318 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2319
2320 *e.linep++ = c;
2321 while ((c = my_getc(c1)) != c1) {
2322 if (c == 0) {
2323 unget(c);
2324 s[0] = c1;
2325 s[1] = 0;
2326 prs("no closing ");
2327 yyerror(s);
2328 return YYERRCODE;
2329 }
2330 if (interactive && c == '\n' && e.iop <= iostack) {
2331#if ENABLE_FEATURE_EDITING
2332 current_prompt = cprompt->value;
2333#else
2334 prs(cprompt->value);
2335#endif
2336 }
2337 *e.linep++ = c;
2338 }
2339
2340 *e.linep++ = c;
2341
2342 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2343
2344 return 0;
2345}
2346
2347/* "multiline commands" helper func */
2348/* see if next 2 chars form a shell multiline */
2349static int dual(int c)
2350{
2351 char s[3];
2352 char *cp = s;
2353
2354 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2355
2356 *cp++ = c; /* c is the given "peek" char */
2357 *cp++ = my_getc(0); /* get next char of input */
2358 *cp = '\0'; /* add EOS marker */
2359
2360 c = rlookup(s); /* see if 2 chars form a shell multiline */
2361 if (c == 0)
2362 unget(*--cp); /* String is not a shell multiline, put peek char back */
2363
2364 return c; /* String is multiline, return numeric multiline (restab) code */
2365}
2366
2367static void diag(int ec)
2368{
2369 int c;
2370
2371 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2372
2373 c = my_getc(0);
2374 if (c == '>' || c == '<') {
2375 if (c != ec)
2376 zzerr();
2377 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
2378 c = my_getc(0);
2379 } else
2380 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
2381 if (c != '&' || yylval.i == IOHERE)
2382 unget(c);
2383 else
2384 yylval.i |= IODUP;
2385}
2386
2387static char *tree(unsigned size)
2388{
2389 char *t;
2390
2391 t = getcell(size);
2392 if (t == NULL) {
2393 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2394 prs("command line too complicated\n");
2395 fail();
2396 /* NOTREACHED */
2397 }
2398 return t;
2399}
2400
2401
2402/* VARARGS1 */
2403/* ARGSUSED */
2404
2405/* -------- exec.c -------- */
2406
2407static struct op **find1case(struct op *t, const char *w)
2408{
2409 struct op *t1;
2410 struct op **tp;
2411 char **wp;
2412 char *cp;
2413
2414 if (t == NULL) {
2415 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2416 return NULL;
2417 }
2418
2419 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2420 T_CMD_NAMES[t->type]));
2421
2422 if (t->type == TLIST) {
2423 tp = find1case(t->left, w);
2424 if (tp != NULL) {
2425 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2426 return tp;
2427 }
2428 t1 = t->right; /* TPAT */
2429 } else
2430 t1 = t;
2431
2432 for (wp = t1->words; *wp;) {
2433 cp = evalstr(*wp++, DOSUB);
2434 if (cp && gmatch(w, cp)) {
2435 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2436 &t1->left));
2437 return &t1->left;
2438 }
2439 }
2440
2441 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2442 return NULL;
2443}
2444
2445static struct op *findcase(struct op *t, const char *w)
2446{
2447 struct op **tp;
2448
2449 tp = find1case(t, w);
2450 return tp != NULL ? *tp : NULL;
2451}
2452
2453/*
2454 * execute tree
2455 */
2456
2457static int execute(struct op *t, int *pin, int *pout, int act)
2458{
2459 struct op *t1;
2460 volatile int i, rv, a;
2461 const char *cp;
2462 char **wp, **wp2;
2463 struct var *vp;
2464 struct op *outtree_save;
2465 struct brkcon bc;
2466
2467#if __GNUC__
2468 /* Avoid longjmp clobbering */
2469 (void) &wp;
2470#endif
2471
2472 if (t == NULL) {
2473 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2474 return 0;
2475 }
2476
2477 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
2478 t->type, T_CMD_NAMES[t->type],
2479 ((t->words == NULL) ? "NULL" : t->words[0])));
2480
2481 rv = 0;
2482 a = areanum++;
2483 wp = (wp2 = t->words) != NULL
2484 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2485 : NULL;
2486
2487 switch (t->type) {
2488 case TDOT:
2489 DBGPRINTF3(("EXECUTE: TDOT\n"));
2490
2491 outtree_save = outtree;
2492
2493 newfile(evalstr(t->words[0], DOALL));
2494
2495 t->left = dowholefile(TLIST, 0);
2496 t->right = NULL;
2497
2498 outtree = outtree_save;
2499
2500 if (t->left)
2501 rv = execute(t->left, pin, pout, 0);
2502 if (t->right)
2503 rv = execute(t->right, pin, pout, 0);
2504 break;
2505
2506 case TPAREN:
2507 rv = execute(t->left, pin, pout, 0);
2508 break;
2509
2510 case TCOM:
2511 rv = forkexec(t, pin, pout, act, wp);
2512 break;
2513
2514 case TPIPE:
2515 {
2516 int pv[2];
2517
2518 rv = openpipe(pv);
2519 if (rv < 0)
2520 break;
2521 pv[0] = remap(pv[0]);
2522 pv[1] = remap(pv[1]);
2523 (void) execute(t->left, pin, pv, 0);
2524 rv = execute(t->right, pv, pout, 0);
2525 }
2526 break;
2527
2528 case TLIST:
2529 (void) execute(t->left, pin, pout, 0);
2530 rv = execute(t->right, pin, pout, 0);
2531 break;
2532
2533 case TASYNC:
2534 {
2535 int hinteractive = interactive;
2536
2537 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2538
2539 i = vfork();
2540 if (i == 0) { /* child */
2541 signal(SIGINT, SIG_IGN);
2542 signal(SIGQUIT, SIG_IGN);
2543 if (interactive)
2544 signal(SIGTERM, SIG_DFL);
2545 interactive = 0;
2546 if (pin == NULL) {
2547 close(0);
2548 xopen(bb_dev_null, O_RDONLY);
2549 }
2550 _exit(execute(t->left, pin, pout, FEXEC));
2551 }
2552 interactive = hinteractive;
2553 if (i != -1) {
2554 setval(lookup("!"), putn(i));
2555 if (pin != NULL)
2556 closepipe(pin);
2557 if (interactive) {
2558 prs(putn(i));
2559 prs("\n");
2560 }
2561 } else
2562 rv = -1;
2563 setstatus(rv);
2564 }
2565 break;
2566
2567 case TOR:
2568 case TAND:
2569 rv = execute(t->left, pin, pout, 0);
2570 t1 = t->right;
2571 if (t1 != NULL && (rv == 0) == (t->type == TAND))
2572 rv = execute(t1, pin, pout, 0);
2573 break;
2574
2575 case TFOR:
2576 if (wp == NULL) {
2577 wp = dolv + 1;
2578 i = dolc;
2579 if (i < 0)
2580 i = 0;
2581 } else {
2582 i = -1;
2583 while (*wp++ != NULL);
2584 }
2585 vp = lookup(t->str);
2586 while (setjmp(bc.brkpt))
2587 if (isbreak)
2588 goto broken;
2589 brkset(&bc);
2590 for (t1 = t->left; i-- && *wp != NULL;) {
2591 setval(vp, *wp++);
2592 rv = execute(t1, pin, pout, 0);
2593 }
2594 brklist = brklist->nextlev;
2595 break;
2596
2597 case TWHILE:
2598 case TUNTIL:
2599 while (setjmp(bc.brkpt))
2600 if (isbreak)
2601 goto broken;
2602 brkset(&bc);
2603 t1 = t->left;
2604 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2605 rv = execute(t->right, pin, pout, 0);
2606 brklist = brklist->nextlev;
2607 break;
2608
2609 case TIF:
2610 case TELIF:
2611 if (t->right != NULL) {
2612 rv = !execute(t->left, pin, pout, 0) ?
2613 execute(t->right->left, pin, pout, 0) :
2614 execute(t->right->right, pin, pout, 0);
2615 }
2616 break;
2617
2618 case TCASE:
2619 cp = evalstr(t->str, DOSUB | DOTRIM);
2620 if (cp == NULL)
2621 cp = "";
2622
2623 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2624 ((t->str == NULL) ? "NULL" : t->str),
2625 ((cp == NULL) ? "NULL" : cp)));
2626
2627 t1 = findcase(t->left, cp);
2628 if (t1 != NULL) {
2629 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2630 rv = execute(t1, pin, pout, 0);
2631 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2632 }
2633 break;
2634
2635 case TBRACE:
2636/*
2637 iopp = t->ioact;
2638 if (i)
2639 while (*iopp)
2640 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2641 rv = -1;
2642 break;
2643 }
2644*/
2645 if (rv >= 0) {
2646 t1 = t->left;
2647 if (t1) {
2648 rv = execute(t1, pin, pout, 0);
2649 }
2650 }
2651 break;
2652
2653 };
2654
2655 broken:
2656 t->words = wp2;
2657 isbreak = 0;
2658 freehere(areanum);
2659 freearea(areanum);
2660 areanum = a;
2661 if (interactive && intr) {
2662 closeall();
2663 fail();
2664 }
2665
2666 i = trapset;
2667 if (i != 0) {
2668 trapset = 0;
2669 runtrap(i);
2670 }
2671
2672 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2673 return rv;
2674}
2675
2676typedef int (*builtin_func_ptr)(struct op *);
2677
2678static builtin_func_ptr inbuilt(const char *s)
2679{
2680 const struct builtincmd *bp;
2681
2682 for (bp = builtincmds; bp->name; bp++)
2683 if (strcmp(bp->name, s) == 0)
2684 return bp->builtinfunc;
2685 return NULL;
2686}
2687
2688static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
2689{
2690 pid_t newpid;
2691 int i, rv;
2692 builtin_func_ptr shcom = NULL;
2693 int f;
2694 const char *cp = NULL;
2695 struct ioword **iopp;
2696 int resetsig;
2697 char **owp;
2698 int forked = 0;
2699
2700 int *hpin = pin;
2701 int *hpout = pout;
2702 char *hwp;
2703 int hinteractive;
2704 int hintr;
2705 struct brkcon *hbrklist;
2706 int hexecflg;
2707
2708#if __GNUC__
2709 /* Avoid longjmp clobbering */
2710 (void) &pin;
2711 (void) &pout;
2712 (void) &wp;
2713 (void) &shcom;
2714 (void) &cp;
2715 (void) &resetsig;
2716 (void) &owp;
2717#endif
2718
2719 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
2720 pout, act));
2721 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2722 ((t->words == NULL) ? "NULL" : t->words[0])));
2723
2724 owp = wp;
2725 resetsig = 0;
2726 rv = -1; /* system-detected error */
2727 if (t->type == TCOM) {
2728 while (*wp++ != NULL)
2729 continue;
2730 cp = *wp;
2731
2732 /* strip all initial assignments */
2733 /* not correct wrt PATH=yyy command etc */
2734 if (FLAG['x']) {
2735 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2736 cp, wp, owp));
2737 echo(cp ? wp : owp);
2738 }
2739
2740 if (cp == NULL && t->ioact == NULL) {
2741 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2742 continue;
2743 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
2744 return setstatus(0);
2745 }
2746 if (cp != NULL) {
2747 shcom = inbuilt(cp);
2748 }
2749 }
2750
2751 t->words = wp;
2752 f = act;
2753
2754 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
2755 f & FEXEC, owp));
2756
2757 if (shcom == NULL && (f & FEXEC) == 0) {
2758 /* Save values in case the child process alters them */
2759 hpin = pin;
2760 hpout = pout;
2761 hwp = *wp;
2762 hinteractive = interactive;
2763 hintr = intr;
2764 hbrklist = brklist;
2765 hexecflg = execflg;
2766
2767 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2768
2769 newpid = vfork();
2770
2771 if (newpid == -1) {
2772 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
2773 return -1;
2774 }
2775
2776 if (newpid > 0) { /* Parent */
2777 /* Restore values */
2778 pin = hpin;
2779 pout = hpout;
2780 *wp = hwp;
2781 interactive = hinteractive;
2782 intr = hintr;
2783 brklist = hbrklist;
2784 execflg = hexecflg;
2785/* moved up
2786 if (i == -1)
2787 return rv;
2788*/
2789 if (pin != NULL)
2790 closepipe(pin);
2791
2792 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2793 }
2794
2795 /* Must be the child process, pid should be 0 */
2796 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
2797
2798 if (interactive) {
2799 signal(SIGINT, SIG_IGN);
2800 signal(SIGQUIT, SIG_IGN);
2801 resetsig = 1;
2802 }
2803 interactive = 0;
2804 intr = 0;
2805 forked = 1;
2806 brklist = 0;
2807 execflg = 0;
2808 }
2809
2810 if (owp != NULL)
2811 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2812 if (shcom == NULL)
2813 export(lookup(cp));
2814
2815#ifdef COMPIPE
2816 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2817 err("piping to/from shell builtins not yet done");
2818 if (forked)
2819 _exit(-1);
2820 return -1;
2821 }
2822#endif
2823
2824 if (pin != NULL) {
2825 xmove_fd(pin[0], 0);
2826 if (pin[1] != 0) close(pin[1]);
2827 }
2828 if (pout != NULL) {
2829 xmove_fd(pout[1], 1);
2830 if (pout[1] != 1) close(pout[0]);
2831 }
2832
2833 iopp = t->ioact;
2834 if (iopp != NULL) {
2835 if (shcom != NULL && shcom != doexec) {
2836 prs(cp);
2837 err(": cannot redirect shell command");
2838 if (forked)
2839 _exit(-1);
2840 return -1;
2841 }
2842 while (*iopp)
2843 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2844 if (forked)
2845 _exit(rv);
2846 return rv;
2847 }
2848 }
2849
2850 if (shcom) {
2851 i = setstatus((*shcom) (t));
2852 if (forked)
2853 _exit(i);
2854 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2855 return i;
2856 }
2857
2858 /* should use FIOCEXCL */
2859 for (i = FDBASE; i < NOFILE; i++)
2860 close(i);
2861 if (resetsig) {
2862 signal(SIGINT, SIG_DFL);
2863 signal(SIGQUIT, SIG_DFL);
2864 }
2865
2866 if (t->type == TPAREN)
2867 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2868 if (wp[0] == NULL)
2869 _exit(0);
2870
2871 cp = rexecve(wp[0], wp, makenv(0, NULL));
2872 prs(wp[0]);
2873 prs(": ");
2874 err(cp);
2875 if (!execflg)
2876 trap[0] = NULL;
2877
2878 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2879
2880 leave();
2881 /* NOTREACHED */
2882 _exit(1);
2883}
2884
2885/*
2886 * 0< 1> are ignored as required
2887 * within pipelines.
2888 */
2889static int iosetup(struct ioword *iop, int pipein, int pipeout)
2890{
2891 int u = -1;
2892 char *cp = NULL;
2893 const char *msg;
2894
2895 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2896 pipein, pipeout));
2897
2898 if (iop->io_unit == IODEFAULT) /* take default */
2899 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2900
2901 if (pipein && iop->io_unit == 0)
2902 return 0;
2903
2904 if (pipeout && iop->io_unit == 1)
2905 return 0;
2906
2907 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2908 if ((iop->io_flag & IOHERE) == 0) {
2909 cp = iop->io_name; /* huh?? */
2910 cp = evalstr(cp, DOSUB | DOTRIM);
2911 if (cp == NULL)
2912 return 1;
2913 }
2914
2915 if (iop->io_flag & IODUP) {
2916 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2917 prs(cp);
2918 err(": illegal >& argument");
2919 return 1;
2920 }
2921 if (*cp == '-')
2922 iop->io_flag = IOCLOSE;
2923 iop->io_flag &= ~(IOREAD | IOWRITE);
2924 }
2925 switch (iop->io_flag) {
2926 case IOREAD:
2927 u = open(cp, O_RDONLY);
2928 break;
2929
2930 case IOHERE:
2931 case IOHERE | IOXHERE:
2932 u = herein(iop->io_name, iop->io_flag & IOXHERE);
2933 cp = (char*)"here file";
2934 break;
2935
2936 case IOWRITE | IOCAT:
2937 u = open(cp, O_WRONLY);
2938 if (u >= 0) {
2939 lseek(u, (long) 0, SEEK_END);
2940 break;
2941 }
2942 case IOWRITE:
2943 u = creat(cp, 0666);
2944 break;
2945
2946 case IODUP:
2947 u = dup2(*cp - '0', iop->io_unit);
2948 break;
2949
2950 case IOCLOSE:
2951 close(iop->io_unit);
2952 return 0;
2953 }
2954 if (u < 0) {
2955 prs(cp);
2956 prs(": cannot ");
2957 warn(msg);
2958 return 1;
2959 }
2960 if (u != iop->io_unit) {
2961 dup2(u, iop->io_unit);
2962 close(u);
2963 }
2964 return 0;
2965}
2966
2967/*
2968 * Enter a new loop level (marked for break/continue).
2969 */
2970static void brkset(struct brkcon *bc)
2971{
2972 bc->nextlev = brklist;
2973 brklist = bc;
2974}
2975
2976/*
2977 * Wait for the last process created.
2978 * Print a message for each process found
2979 * that was killed by a signal.
2980 * Ignore interrupt signals while waiting
2981 * unless `canintr' is true.
2982 */
2983static int waitfor(int lastpid, int canintr)
2984{
2985 int pid, rv;
2986 int s;
2987 int oheedint = heedint;
2988
2989 heedint = 0;
2990 rv = 0;
2991 do {
2992 pid = wait(&s);
2993 if (pid == -1) {
2994 if (errno != EINTR || canintr)
2995 break;
2996 } else {
2997 rv = WAITSIG(s);
2998 if (rv != 0) {
2999 if (rv < ARRAY_SIZE(signame)) {
3000 if (signame[rv] != NULL) {
3001 if (pid != lastpid) {
3002 prn(pid);
3003 prs(": ");
3004 }
3005 prs(signame[rv]);
3006 }
3007 } else {
3008 if (pid != lastpid) {
3009 prn(pid);
3010 prs(": ");
3011 }
3012 prs("Signal ");
3013 prn(rv);
3014 prs(" ");
3015 }
3016 if (WAITCORE(s))
3017 prs(" - core dumped");
3018 if (rv >= ARRAY_SIZE(signame) || signame[rv])
3019 prs("\n");
3020 rv = -1;
3021 } else
3022 rv = WAITVAL(s);
3023 }
3024 } while (pid != lastpid);
3025 heedint = oheedint;
3026 if (intr) {
3027 if (interactive) {
3028 if (canintr)
3029 intr = 0;
3030 } else {
3031 if (exstat == 0)
3032 exstat = rv;
3033 onintr(0);
3034 }
3035 }
3036 return rv;
3037}
3038
3039static int setstatus(int s)
3040{
3041 exstat = s;
3042 setval(lookup("?"), putn(s));
3043 return s;
3044}
3045
3046/*
3047 * PATH-searching interface to execve.
3048 * If getenv("PATH") were kept up-to-date,
3049 * execvp might be used.
3050 */
3051static const char *rexecve(char *c, char **v, char **envp)
3052{
3053 int i;
3054 const char *sp;
3055 char *tp;
3056 int eacces = 0, asis = 0;
3057 char *name = c;
3058
3059 if (ENABLE_FEATURE_SH_STANDALONE) {
3060 if (find_applet_by_name(name)) {
3061 /* We have to exec here since we vforked. Running
3062 * run_applet_and_exit() won't work and bad things
3063 * will happen. */
3064 execve(bb_busybox_exec_path, v, envp);
3065 }
3066 }
3067
3068 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3069
3070 sp = any('/', c) ? "" : path->value;
3071 asis = (*sp == '\0');
3072 while (asis || *sp != '\0') {
3073 asis = 0;
3074 tp = e.linep;
3075 for (; *sp != '\0'; tp++) {
3076 *tp = *sp++;
3077 if (*tp == ':') {
3078 asis = (*sp == '\0');
3079 break;
3080 }
3081 }
3082 if (tp != e.linep)
3083 *tp++ = '/';
3084 for (i = 0; (*tp++ = c[i++]) != '\0';);
3085
3086 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3087
3088 execve(e.linep, v, envp);
3089
3090 switch (errno) {
3091 case ENOEXEC:
3092 *v = e.linep;
3093 tp = *--v;
3094 *v = e.linep;
3095 execve(DEFAULT_SHELL, v, envp);
3096 *v = tp;
3097 return "no Shell";
3098
3099 case ENOMEM:
3100 return (char *) bb_msg_memory_exhausted;
3101
3102 case E2BIG:
3103 return "argument list too long";
3104
3105 case EACCES:
3106 eacces++;
3107 break;
3108 }
3109 }
3110 return errno == ENOENT ? "not found" : "cannot execute";
3111}
3112
3113/*
3114 * Run the command produced by generator `f'
3115 * applied to stream `arg'.
3116 */
3117static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3118{
3119 struct op *otree;
3120 struct wdblock *swdlist;
3121 struct wdblock *siolist;
3122 jmp_buf ev, rt;
3123 xint *ofail;
3124 int rv;
3125
3126#if __GNUC__
3127 /* Avoid longjmp clobbering */
3128 (void) &rv;
3129#endif
3130
3131 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3132 areanum, outtree, failpt));
3133
3134 areanum++;
3135 swdlist = wdlist;
3136 siolist = iolist;
3137 otree = outtree;
3138 ofail = failpt;
3139 rv = -1;
3140
3141 errpt = ev;
3142 if (newenv(setjmp(errpt)) == 0) {
3143 wdlist = 0;
3144 iolist = 0;
3145 pushio(argp, f);
3146 e.iobase = e.iop;
3147 yynerrs = 0;
3148 failpt = rt;
3149 if (setjmp(failpt) == 0 && yyparse() == 0)
3150 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3151 quitenv();
3152 } else {
3153 DBGPRINTF(("RUN: error from newenv()!\n"));
3154 }
3155
3156 wdlist = swdlist;
3157 iolist = siolist;
3158 failpt = ofail;
3159 outtree = otree;
3160 freearea(areanum--);
3161
3162 return rv;
3163}
3164
3165/* -------- do.c -------- */
3166
3167/*
3168 * built-in commands: doX
3169 */
3170
3171static int dohelp(struct op *t)
3172{
3173 int col;
3174 const struct builtincmd *x;
3175
3176 puts("\nBuilt-in commands:\n"
3177 "-------------------");
3178
3179 col = 0;
3180 x = builtincmds;
3181 while (x->name) {
3182 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
3183 if (col > 60) {
3184 puts("");
3185 col = 0;
3186 }
3187 x++;
3188 }
3189#if ENABLE_FEATURE_SH_STANDALONE
3190 {
3191 const struct bb_applet *applet = applets;
3192
3193 while (applet->name) {
3194 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
3195 if (col > 60) {
3196 puts("");
3197 col = 0;
3198 }
3199 applet++;
3200 }
3201 }
3202#endif
3203 puts("\n");
3204 return EXIT_SUCCESS;
3205}
3206
3207static int dolabel(struct op *t)
3208{
3209 return 0;
3210}
3211
3212static int dochdir(struct op *t)
3213{
3214 const char *cp, *er;
3215
3216 cp = t->words[1];
3217 if (cp == NULL) {
3218 cp = homedir->value;
3219 if (cp != NULL)
3220 goto do_cd;
3221 er = ": no home directory";
3222 } else {
3223 do_cd:
3224 if (chdir(cp) >= 0)
3225 return 0;
3226 er = ": bad directory";
3227 }
3228 prs(cp != NULL ? cp : "cd");
3229 err(er);
3230 return 1;
3231}
3232
3233static int doshift(struct op *t)
3234{
3235 int n;
3236
3237 n = t->words[1] ? getn(t->words[1]) : 1;
3238 if (dolc < n) {
3239 err("nothing to shift");
3240 return 1;
3241 }
3242 dolv[n] = dolv[0];
3243 dolv += n;
3244 dolc -= n;
3245 setval(lookup("#"), putn(dolc));
3246 return 0;
3247}
3248
3249/*
3250 * execute login and newgrp directly
3251 */
3252static int dologin(struct op *t)
3253{
3254 const char *cp;
3255
3256 if (interactive) {
3257 signal(SIGINT, SIG_DFL);
3258 signal(SIGQUIT, SIG_DFL);
3259 }
3260 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3261 prs(t->words[0]);
3262 prs(": ");
3263 err(cp);
3264 return 1;
3265}
3266
3267static int doumask(struct op *t)
3268{
3269 int i, n;
3270 char *cp;
3271
3272 cp = t->words[1];
3273 if (cp == NULL) {
3274 i = umask(0);
3275 umask(i);
3276 for (n = 3 * 4; (n -= 3) >= 0;)
3277 putc('0' + ((i >> n) & 07), stderr);
3278 putc('\n', stderr);
3279 } else {
3280/* huh??? '8','9' are not allowed! */
3281 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3282 n = n * 8 + (*cp - '0');
3283 umask(n);
3284 }
3285 return 0;
3286}
3287
3288static int doexec(struct op *t)
3289{
3290 int i;
3291 jmp_buf ex;
3292 xint *ofail;
3293
3294 t->ioact = NULL;
3295 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
3296 if (i == 0)
3297 return 1;
3298 execflg = 1;
3299 ofail = failpt;
3300 failpt = ex;
3301 if (setjmp(failpt) == 0)
3302 execute(t, NOPIPE, NOPIPE, FEXEC);
3303 failpt = ofail;
3304 execflg = 0;
3305 return 1;
3306}
3307
3308static int dodot(struct op *t)
3309{
3310 int i;
3311 const char *sp;
3312 char *tp;
3313 char *cp;
3314 int maltmp;
3315
3316 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
3317
3318 cp = t->words[1];
3319 if (cp == NULL) {
3320 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3321 return 0;
3322 }
3323 DBGPRINTF(("DODOT: cp is %s\n", cp));
3324
3325 sp = any('/', cp) ? ":" : path->value;
3326
3327 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3328 ((sp == NULL) ? "NULL" : sp),
3329 ((e.linep == NULL) ? "NULL" : e.linep)));
3330
3331 while (*sp) {
3332 tp = e.linep;
3333 while (*sp && (*tp = *sp++) != ':')
3334 tp++;
3335 if (tp != e.linep)
3336 *tp++ = '/';
3337
3338 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3339
3340 /* Original code */
3341 i = open(e.linep, O_RDONLY);
3342 if (i >= 0) {
3343 exstat = 0;
3344 maltmp = remap(i);
3345 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3346
3347 next(maltmp); /* Basically a PUSHIO */
3348
3349 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3350
3351 return exstat;
3352 }
3353 } /* while */
3354
3355 prs(cp);
3356 err(": not found");
3357
3358 return -1;
3359}
3360
3361static int dowait(struct op *t)
3362{
3363 int i;
3364 char *cp;
3365
3366 cp = t->words[1];
3367 if (cp != NULL) {
3368 i = getn(cp);
3369 if (i == 0)
3370 return 0;
3371 } else
3372 i = -1;
3373 setstatus(waitfor(i, 1));
3374 return 0;
3375}
3376
3377static int doread(struct op *t)
3378{
3379 char *cp, **wp;
3380 int nb = 0;
3381 int nl = 0;
3382
3383 if (t->words[1] == NULL) {
3384 err("Usage: read name ...");
3385 return 1;
3386 }
3387 for (wp = t->words + 1; *wp; wp++) {
3388 for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
3389 nb = read(0, cp, sizeof(*cp));
3390 if (nb != sizeof(*cp))
3391 break;
3392 nl = (*cp == '\n');
3393 if (nl || (wp[1] && any(*cp, ifs->value)))
3394 break;
3395 }
3396 *cp = '\0';
3397 if (nb <= 0)
3398 break;
3399 setval(lookup(*wp), e.linep);
3400 }
3401 return nb <= 0;
3402}
3403
3404static int doeval(struct op *t)
3405{
3406 return RUN(awordlist, t->words + 1, wdchar);
3407}
3408
3409static int dotrap(struct op *t)
3410{
3411 int n, i;
3412 int resetsig;
3413
3414 if (t->words[1] == NULL) {
3415 for (i = 0; i <= _NSIG; i++)
3416 if (trap[i]) {
3417 prn(i);
3418 prs(": ");
3419 prs(trap[i]);
3420 prs("\n");
3421 }
3422 return 0;
3423 }
3424 resetsig = isdigit(*t->words[1]);
3425 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3426 n = getsig(t->words[i]);
3427 freecell(trap[n]);
3428 trap[n] = 0;
3429 if (!resetsig) {
3430 if (*t->words[1] != '\0') {
3431 trap[n] = strsave(t->words[1], 0);
3432 setsig(n, sig);
3433 } else
3434 setsig(n, SIG_IGN);
3435 } else {
3436 if (interactive) {
3437 if (n == SIGINT)
3438 setsig(n, onintr);
3439 else
3440 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3441 } else
3442 setsig(n, SIG_DFL);
3443 }
3444 }
3445 return 0;
3446}
3447
3448static int getsig(char *s)
3449{
3450 int n;
3451
3452 n = getn(s);
3453 if (n < 0 || n > _NSIG) {
3454 err("trap: bad signal number");
3455 n = 0;
3456 }
3457 return n;
3458}
3459
3460static void setsig(int n, sighandler_t f)
3461{
3462 if (n == 0)
3463 return;
3464 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3465 ourtrap[n] = 1;
3466 signal(n, f);
3467 }
3468}
3469
3470static int getn(char *as)
3471{
3472 char *s;
3473 int n, m;
3474
3475 s = as;
3476 m = 1;
3477 if (*s == '-') {
3478 m = -1;
3479 s++;
3480 }
3481 for (n = 0; isdigit(*s); s++)
3482 n = (n * 10) + (*s - '0');
3483 if (*s) {
3484 prs(as);
3485 err(": bad number");
3486 }
3487 return n * m;
3488}
3489
3490static int dobreak(struct op *t)
3491{
3492 return brkcontin(t->words[1], 1);
3493}
3494
3495static int docontinue(struct op *t)
3496{
3497 return brkcontin(t->words[1], 0);
3498}
3499
3500static int brkcontin(char *cp, int val)
3501{
3502 struct brkcon *bc;
3503 int nl;
3504
3505 nl = cp == NULL ? 1 : getn(cp);
3506 if (nl <= 0)
3507 nl = 999;
3508 do {
3509 bc = brklist;
3510 if (bc == NULL)
3511 break;
3512 brklist = bc->nextlev;
3513 } while (--nl);
3514 if (nl) {
3515 err("bad break/continue level");
3516 return 1;
3517 }
3518 isbreak = val;
3519 longjmp(bc->brkpt, 1);
3520 /* NOTREACHED */
3521}
3522
3523static int doexit(struct op *t)
3524{
3525 char *cp;
3526
3527 execflg = 0;
3528 cp = t->words[1];
3529 if (cp != NULL)
3530 setstatus(getn(cp));
3531
3532 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3533
3534 leave();
3535 /* NOTREACHED */
3536 return 0;
3537}
3538
3539static int doexport(struct op *t)
3540{
3541 rdexp(t->words + 1, export, EXPORT);
3542 return 0;
3543}
3544
3545static int doreadonly(struct op *t)
3546{
3547 rdexp(t->words + 1, ronly, RONLY);
3548 return 0;
3549}
3550
3551static void rdexp(char **wp, void (*f) (struct var *), int key)
3552{
3553 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3554 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3555
3556 if (*wp != NULL) {
3557 for (; *wp != NULL; wp++) {
3558 if (isassign(*wp)) {
3559 char *cp;
3560
3561 assign(*wp, COPYV);
3562 for (cp = *wp; *cp != '='; cp++);
3563 *cp = '\0';
3564 }
3565 if (checkname(*wp))
3566 (*f) (lookup(*wp));
3567 else
3568 badid(*wp);
3569 }
3570 } else
3571 putvlist(key, 1);
3572}
3573
3574static void badid(char *s)
3575{
3576 prs(s);
3577 err(": bad identifier");
3578}
3579
3580static int doset(struct op *t)
3581{
3582 struct var *vp;
3583 char *cp;
3584 int n;
3585
3586 cp = t->words[1];
3587 if (cp == NULL) {
3588 for (vp = vlist; vp; vp = vp->next)
3589 varput(vp->name, 1);
3590 return 0;
3591 }
3592 if (*cp == '-') {
3593 /* bad: t->words++; */
3594 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3595 if (*++cp == 0)
3596 FLAG['x'] = FLAG['v'] = 0;
3597 else {
3598 for (; *cp; cp++) {
3599 switch (*cp) {
3600 case 'e':
3601 if (!interactive)
3602 FLAG['e']++;
3603 break;
3604
3605 default:
3606 if (*cp >= 'a' && *cp <= 'z')
3607 FLAG[(int) *cp]++;
3608 break;
3609 }
3610 }
3611 }
3612 setdash();
3613 }
3614 if (t->words[1]) {
3615 t->words[0] = dolv[0];
3616 for (n = 1; t->words[n]; n++)
3617 setarea((char *) t->words[n], 0);
3618 dolc = n - 1;
3619 dolv = t->words;
3620 setval(lookup("#"), putn(dolc));
3621 setarea((char *) (dolv - 1), 0);
3622 }
3623 return 0;
3624}
3625
3626static void varput(char *s, int out)
3627{
3628 if (isalnum(*s) || *s == '_') {
3629 write(out, s, strlen(s));
3630 write(out, "\n", 1);
3631 }
3632}
3633
3634
3635/*
3636 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3637 * This file contains code for the times builtin.
3638 */
3639static int dotimes(struct op *t)
3640{
3641 struct tms buf;
3642 long clk_tck = sysconf(_SC_CLK_TCK);
3643
3644 times(&buf);
3645 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3646 (int) (buf.tms_utime / clk_tck / 60),
3647 ((double) buf.tms_utime) / clk_tck,
3648 (int) (buf.tms_stime / clk_tck / 60),
3649 ((double) buf.tms_stime) / clk_tck,
3650 (int) (buf.tms_cutime / clk_tck / 60),
3651 ((double) buf.tms_cutime) / clk_tck,
3652 (int) (buf.tms_cstime / clk_tck / 60),
3653 ((double) buf.tms_cstime) / clk_tck);
3654 return 0;
3655}
3656
3657
3658/* -------- eval.c -------- */
3659
3660/*
3661 * ${}
3662 * `command`
3663 * blank interpretation
3664 * quoting
3665 * glob
3666 */
3667
3668static char **eval(char **ap, int f)
3669{
3670 struct wdblock *wb;
3671 char **wp;
3672 char **wf;
3673 jmp_buf ev;
3674
3675#if __GNUC__
3676 /* Avoid longjmp clobbering */
3677 (void) &wp;
3678 (void) &ap;
3679#endif
3680
3681 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3682
3683 wp = NULL;
3684 wb = NULL;
3685 wf = NULL;
3686 errpt = ev;
3687 if (newenv(setjmp(errpt)) == 0) {
3688 while (*ap && isassign(*ap))
3689 expand(*ap++, &wb, f & ~DOGLOB);
3690 if (FLAG['k']) {
3691 for (wf = ap; *wf; wf++) {
3692 if (isassign(*wf))
3693 expand(*wf, &wb, f & ~DOGLOB);
3694 }
3695 }
3696 for (wb = addword((char *) 0, wb); *ap; ap++) {
3697 if (!FLAG['k'] || !isassign(*ap))
3698 expand(*ap, &wb, f & ~DOKEY);
3699 }
3700 wb = addword((char *) 0, wb);
3701 wp = getwords(wb);
3702 quitenv();
3703 } else
3704 gflg = 1;
3705
3706 return gflg ? (char **) NULL : wp;
3707}
3708
3709
3710/*
3711 * Make the exported environment from the exported
3712 * names in the dictionary. Keyword assignments
3713 * will already have been done.
3714 */
3715static char **makenv(int all, struct wdblock *wb)
3716{
3717 struct var *vp;
3718
3719 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3720
3721 for (vp = vlist; vp; vp = vp->next)
3722 if (all || vp->status & EXPORT)
3723 wb = addword(vp->name, wb);
3724 wb = addword((char *) 0, wb);
3725 return getwords(wb);
3726}
3727
3728static int expand(const char *cp, struct wdblock **wbp, int f)
3729{
3730 jmp_buf ev;
3731 char *xp;
3732
3733#if __GNUC__
3734 /* Avoid longjmp clobbering */
3735 (void) &cp;
3736#endif
3737
3738 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3739
3740 gflg = 0;
3741
3742 if (cp == NULL)
3743 return 0;
3744
3745 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3746 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3747 ) {
3748 xp = strsave(cp, areanum);
3749 if (f & DOTRIM)
3750 unquote(xp);
3751 *wbp = addword(xp, *wbp);
3752 return 1;
3753 }
3754 errpt = ev;
3755 if (newenv(setjmp(errpt)) == 0) {
3756 PUSHIO(aword, cp, strchar);
3757 e.iobase = e.iop;
3758 while ((xp = blank(f)) && gflg == 0) {
3759 e.linep = xp;
3760 xp = strsave(xp, areanum);
3761 if ((f & DOGLOB) == 0) {
3762 if (f & DOTRIM)
3763 unquote(xp);
3764 *wbp = addword(xp, *wbp);
3765 } else
3766 *wbp = glob(xp, *wbp);
3767 }
3768 quitenv();
3769 } else
3770 gflg = 1;
3771 return gflg == 0;
3772}
3773
3774static char *evalstr(char *cp, int f)
3775{
3776 struct wdblock *wb;
3777
3778 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3779
3780 wb = NULL;
3781 if (expand(cp, &wb, f)) {
3782 if (wb == NULL || wb->w_nword == 0
3783 || (cp = wb->w_words[0]) == NULL
3784 ) {
3785// TODO: I suspect that
3786// char *evalstr(char *cp, int f) is actually
3787// const char *evalstr(const char *cp, int f)!
3788 cp = (char*)"";
3789 }
3790 DELETE(wb);
3791 } else
3792 cp = NULL;
3793 return cp;
3794}
3795
3796
3797/*
3798 * Blank interpretation and quoting
3799 */
3800static char *blank(int f)
3801{
3802 int c, c1;
3803 char *sp;
3804 int scanequals, foundequals;
3805
3806 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3807
3808 sp = e.linep;
3809 scanequals = f & DOKEY;
3810 foundequals = 0;
3811
3812 loop:
3813 c = subgetc('"', foundequals);
3814 switch (c) {
3815 case 0:
3816 if (sp == e.linep)
3817 return 0;
3818 *e.linep++ = 0;
3819 return sp;
3820
3821 default:
3822 if (f & DOBLANK && any(c, ifs->value))
3823 goto loop;
3824 break;
3825
3826 case '"':
3827 case '\'':
3828 scanequals = 0;
3829 if (INSUB())
3830 break;
3831 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3832 if (c == 0)
3833 break;
3834 if (c == '\'' || !any(c, "$`\""))
3835 c |= QUOTE;
3836 *e.linep++ = c;
3837 }
3838 c = 0;
3839 }
3840 unget(c);
3841 if (!isalpha(c) && c != '_')
3842 scanequals = 0;
3843 for (;;) {
3844 c = subgetc('"', foundequals);
3845 if (c == 0 ||
3846 f & (DOBLANK && any(c, ifs->value)) ||
3847 (!INSUB() && any(c, "\"'"))) {
3848 scanequals = 0;
3849 unget(c);
3850 if (any(c, "\"'"))
3851 goto loop;
3852 break;
3853 }
3854 if (scanequals) {
3855 if (c == '=') {
3856 foundequals = 1;
3857 scanequals = 0;
3858 } else if (!isalnum(c) && c != '_')
3859 scanequals = 0;
3860 }
3861 *e.linep++ = c;
3862 }
3863 *e.linep++ = 0;
3864 return sp;
3865}
3866
3867/*
3868 * Get characters, substituting for ` and $
3869 */
3870static int subgetc(char ec, int quoted)
3871{
3872 char c;
3873
3874 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3875
3876 again:
3877 c = my_getc(ec);
3878 if (!INSUB() && ec != '\'') {
3879 if (c == '`') {
3880 if (grave(quoted) == 0)
3881 return 0;
3882 e.iop->task = XGRAVE;
3883 goto again;
3884 }
3885 if (c == '$') {
3886 c = dollar(quoted);
3887 if (c == 0) {
3888 e.iop->task = XDOLL;
3889 goto again;
3890 }
3891 }
3892 }
3893 return c;
3894}
3895
3896/*
3897 * Prepare to generate the string returned by ${} substitution.
3898 */
3899static int dollar(int quoted)
3900{
3901 int otask;
3902 struct io *oiop;
3903 char *dolp;
3904 char *s, c, *cp = NULL;
3905 struct var *vp;
3906
3907 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3908
3909 c = readc();
3910 s = e.linep;
3911 if (c != '{') {
3912 *e.linep++ = c;
3913 if (isalpha(c) || c == '_') {
3914 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3915 if (e.linep < elinep)
3916 *e.linep++ = c;
3917 unget(c);
3918 }
3919 c = 0;
3920 } else {
3921 oiop = e.iop;
3922 otask = e.iop->task;
3923
3924 e.iop->task = XOTHER;
3925 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3926 if (e.linep < elinep)
3927 *e.linep++ = c;
3928 if (oiop == e.iop)
3929 e.iop->task = otask;
3930 if (c != '}') {
3931 err("unclosed ${");
3932 gflg++;
3933 return c;
3934 }
3935 }
3936 if (e.linep >= elinep) {
3937 err("string in ${} too long");
3938 gflg++;
3939 e.linep -= 10;
3940 }
3941 *e.linep = 0;
3942 if (*s)
3943 for (cp = s + 1; *cp; cp++)
3944 if (any(*cp, "=-+?")) {
3945 c = *cp;
3946 *cp++ = 0;
3947 break;
3948 }
3949 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3950 if (dolc > 1) {
3951 /* currently this does not distinguish $* and $@ */
3952 /* should check dollar */
3953 e.linep = s;
3954 PUSHIO(awordlist, dolv + 1, dolchar);
3955 return 0;
3956 } else { /* trap the nasty ${=} */
3957 s[0] = '1';
3958 s[1] = '\0';
3959 }
3960 }
3961 vp = lookup(s);
3962 dolp = vp->value;
3963 if (dolp == null) {
3964 switch (c) {
3965 case '=':
3966 if (isdigit(*s)) {
3967 err("cannot use ${...=...} with $n");
3968 gflg++;
3969 break;
3970 }
3971 setval(vp, cp);
3972 dolp = vp->value;
3973 break;
3974
3975 case '-':
3976 dolp = strsave(cp, areanum);
3977 break;
3978
3979 case '?':
3980 if (*cp == 0) {
3981 prs("missing value for ");
3982 err(s);
3983 } else
3984 err(cp);
3985 gflg++;
3986 break;
3987 }
3988 } else if (c == '+')
3989 dolp = strsave(cp, areanum);
3990 if (FLAG['u'] && dolp == null) {
3991 prs("unset variable: ");
3992 err(s);
3993 gflg++;
3994 }
3995 e.linep = s;
3996 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
3997 return 0;
3998}
3999
4000/*
4001 * Run the command in `...` and read its output.
4002 */
4003
4004static int grave(int quoted)
4005{
4006 /* moved to G: static char child_cmd[LINELIM]; */
4007
4008 const char *cp;
4009 int i;
4010 int j;
4011 int pf[2];
4012 const char *src;
4013 char *dest;
4014 int count;
4015 int ignore;
4016 int ignore_once;
4017 char *argument_list[4];
4018 struct wdblock *wb = NULL;
4019
4020#if __GNUC__
4021 /* Avoid longjmp clobbering */
4022 (void) &cp;
4023#endif
4024
4025 for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
4026 if (*cp == 0) {
4027 err("no closing `");
4028 return 0;
4029 }
4030 }
4031
4032 /* string copy with dollar expansion */
4033 src = e.iop->argp->aword;
4034 dest = child_cmd;
4035 count = 0;
4036 ignore = 0;
4037 ignore_once = 0;
4038 while ((*src != '`') && (count < LINELIM)) {
4039 if (*src == '\'')
4040 ignore = !ignore;
4041 if (*src == '\\')
4042 ignore_once = 1;
4043 if (*src == '$' && !ignore && !ignore_once) {
4044 struct var *vp;
4045 char var_name[LINELIM];
4046 char alt_value[LINELIM];
4047 int var_index = 0;
4048 int alt_index = 0;
4049 char operator = 0;
4050 int braces = 0;
4051 char *value;
4052
4053 src++;
4054 if (*src == '{') {
4055 braces = 1;
4056 src++;
4057 }
4058
4059 var_name[var_index++] = *src++;
4060 while (isalnum(*src) || *src=='_')
4061 var_name[var_index++] = *src++;
4062 var_name[var_index] = 0;
4063
4064 if (braces) {
4065 switch (*src) {
4066 case '}':
4067 break;
4068 case '-':
4069 case '=':
4070 case '+':
4071 case '?':
4072 operator = * src;
4073 break;
4074 default:
4075 err("unclosed ${\n");
4076 return 0;
4077 }
4078 if (operator) {
4079 src++;
4080 while (*src && (*src != '}')) {
4081 alt_value[alt_index++] = *src++;
4082 }
4083 alt_value[alt_index] = 0;
4084 if (*src != '}') {
4085 err("unclosed ${\n");
4086 return 0;
4087 }
4088 }
4089 src++;
4090 }
4091
4092 if (isalpha(*var_name)) {
4093 /* let subshell handle it instead */
4094
4095 char *namep = var_name;
4096
4097 *dest++ = '$';
4098 if (braces)
4099 *dest++ = '{';
4100 while (*namep)
4101 *dest++ = *namep++;
4102 if (operator) {
4103 char *altp = alt_value;
4104 *dest++ = operator;
4105 while (*altp)
4106 *dest++ = *altp++;
4107 }
4108 if (braces)
4109 *dest++ = '}';
4110
4111 wb = addword(lookup(var_name)->name, wb);
4112 } else {
4113 /* expand */
4114
4115 vp = lookup(var_name);
4116 if (vp->value != null)
4117 value = (operator == '+') ?
4118 alt_value : vp->value;
4119 else if (operator == '?') {
4120 err(alt_value);
4121 return 0;
4122 } else if (alt_index && (operator != '+')) {
4123 value = alt_value;
4124 if (operator == '=')
4125 setval(vp, value);
4126 } else
4127 continue;
4128
4129 while (*value && (count < LINELIM)) {
4130 *dest++ = *value++;
4131 count++;
4132 }
4133 }
4134 } else {
4135 *dest++ = *src++;
4136 count++;
4137 ignore_once = 0;
4138 }
4139 }
4140 *dest = '\0';
4141
4142 if (openpipe(pf) < 0)
4143 return 0;
4144
4145 while ((i = vfork()) == -1 && errno == EAGAIN);
4146
4147 DBGPRINTF3(("GRAVE: i is %p\n", io));
4148
4149 if (i < 0) {
4150 closepipe(pf);
4151 err((char *) bb_msg_memory_exhausted);
4152 return 0;
4153 }
4154 if (i != 0) {
4155 waitpid(i, NULL, 0);
4156 e.iop->argp->aword = ++cp;
4157 close(pf[1]);
4158 PUSHIO(afile, remap(pf[0]),
4159 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
4160 return 1;
4161 }
4162 /* allow trapped signals */
4163 /* XXX - Maybe this signal stuff should go as well? */
4164 for (j = 0; j <= _NSIG; j++)
4165 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4166 signal(j, SIG_DFL);
4167
4168 /* Testcase where below checks are needed:
4169 * close stdout & run this script:
4170 * files=`ls`
4171 * echo "$files" >zz
4172 */
4173 xmove_fd(pf[1], 1);
4174 if (pf[0] != 1) close(pf[0]);
4175
4176 argument_list[0] = (char *) DEFAULT_SHELL;
4177 argument_list[1] = (char *) "-c";
4178 argument_list[2] = child_cmd;
4179 argument_list[3] = NULL;
4180
4181 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4182 prs(argument_list[0]);
4183 prs(": ");
4184 err(cp);
4185 _exit(1);
4186}
4187
4188
4189static char *unquote(char *as)
4190{
4191 char *s;
4192
4193 s = as;
4194 if (s != NULL)
4195 while (*s)
4196 *s++ &= ~QUOTE;
4197 return as;
4198}
4199
4200/* -------- glob.c -------- */
4201
4202/*
4203 * glob
4204 */
4205
4206#define scopy(x) strsave((x), areanum)
4207#define BLKSIZ 512
4208#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4209
4210static struct wdblock *cl, *nl;
4211static const char spcl[] ALIGN1= "[?*";
4212
4213static struct wdblock *glob(char *cp, struct wdblock *wb)
4214{
4215 int i;
4216 char *pp;
4217
4218 if (cp == 0)
4219 return wb;
4220 i = 0;
4221 for (pp = cp; *pp; pp++)
4222 if (any(*pp, spcl))
4223 i++;
4224 else if (!any(*pp & ~QUOTE, spcl))
4225 *pp &= ~QUOTE;
4226 if (i != 0) {
4227 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
4228 nl = newword(cl->w_nword * 2);
4229 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
4230 for (pp = cl->w_words[i]; *pp; pp++)
4231 if (any(*pp, spcl)) {
4232 globname(cl->w_words[i], pp);
4233 break;
4234 }
4235 if (*pp == '\0')
4236 nl = addword(scopy(cl->w_words[i]), nl);
4237 }
4238 for (i = 0; i < cl->w_nword; i++)
4239 DELETE(cl->w_words[i]);
4240 DELETE(cl);
4241 }
4242 for (i = 0; i < cl->w_nword; i++)
4243 unquote(cl->w_words[i]);
4244 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4245 if (cl->w_nword) {
4246 for (i = 0; i < cl->w_nword; i++)
4247 wb = addword(cl->w_words[i], wb);
4248 DELETE(cl);
4249 return wb;
4250 }
4251 }
4252 wb = addword(unquote(cp), wb);
4253 return wb;
4254}
4255
4256static void globname(char *we, char *pp)
4257{
4258 char *np, *cp;
4259 char *name, *gp, *dp;
4260 int k;
4261 DIR *dirp;
4262 struct dirent *de;
4263 char dname[NAME_MAX + 1];
4264 struct stat dbuf;
4265
4266 for (np = we; np != pp; pp--)
4267 if (pp[-1] == '/')
4268 break;
4269 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4270 *cp++ = *np++;
4271 *cp++ = '.';
4272 *cp = '\0';
4273 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4274 *cp++ = *np++;
4275 *cp = '\0';
4276 dirp = opendir(dp);
4277 if (dirp == 0) {
4278 DELETE(dp);
4279 DELETE(gp);
4280 return;
4281 }
4282 dname[NAME_MAX] = '\0';
4283 while ((de = readdir(dirp)) != NULL) {
4284 /* XXX Hmmm... What this could be? (abial) */
4285 /*
4286 if (ent[j].d_ino == 0)
4287 continue;
4288 */
4289 strncpy(dname, de->d_name, NAME_MAX);
4290 if (dname[0] == '.')
4291 if (*gp != '.')
4292 continue;
4293 for (k = 0; k < NAME_MAX; k++)
4294 if (any(dname[k], spcl))
4295 dname[k] |= QUOTE;
4296 if (gmatch(dname, gp)) {
4297 name = generate(we, pp, dname, np);
4298 if (*np && !anys(np, spcl)) {
4299 if (stat(name, &dbuf)) {
4300 DELETE(name);
4301 continue;
4302 }
4303 }
4304 nl = addword(name, nl);
4305 }
4306 }
4307 closedir(dirp);
4308 DELETE(dp);
4309 DELETE(gp);
4310}
4311
4312/*
4313 * generate a pathname as below.
4314 * start..end1 / middle end
4315 * the slashes come for free
4316 */
4317static char *generate(char *start1, char *end1, char *middle, char *end)
4318{
4319 char *p;
4320 char *op, *xp;
4321
4322 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4323 for (xp = start1; xp != end1;)
4324 *op++ = *xp++;
4325 for (xp = middle; (*op++ = *xp++) != '\0';);
4326 op--;
4327 for (xp = end; (*op++ = *xp++) != '\0';);
4328 return p;
4329}
4330
4331static int anyspcl(struct wdblock *wb)
4332{
4333 int i;
4334 char **wd;
4335
4336 wd = wb->w_words;
4337 for (i = 0; i < wb->w_nword; i++)
4338 if (anys(spcl, *wd++))
4339 return 1;
4340 return 0;
4341}
4342
4343static int xstrcmp(char *p1, char *p2)
4344{
4345 return strcmp(*(char **) p1, *(char **) p2);
4346}
4347
4348
4349/* -------- word.c -------- */
4350
4351static struct wdblock *newword(int nw)
4352{
4353 struct wdblock *wb;
4354
4355 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4356 wb->w_bsize = nw;
4357 wb->w_nword = 0;
4358 return wb;
4359}
4360
4361static struct wdblock *addword(char *wd, struct wdblock *wb)
4362{
4363 struct wdblock *wb2;
4364 int nw;
4365
4366 if (wb == NULL)
4367 wb = newword(NSTART);
4368 nw = wb->w_nword;
4369 if (nw >= wb->w_bsize) {
4370 wb2 = newword(nw * 2);
4371 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4372 nw * sizeof(char *));
4373 wb2->w_nword = nw;
4374 DELETE(wb);
4375 wb = wb2;
4376 }
4377 wb->w_words[wb->w_nword++] = wd;
4378 return wb;
4379}
4380
4381static char **getwords(struct wdblock *wb)
4382{
4383 char **wd;
4384 int nb;
4385
4386 if (wb == NULL)
4387 return NULL;
4388 if (wb->w_nword == 0) {
4389 DELETE(wb);
4390 return NULL;
4391 }
4392 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4393 memcpy((char *) wd, (char *) wb->w_words, nb);
4394 DELETE(wb); /* perhaps should done by caller */
4395 return wd;
4396}
4397
4398static int (*func) (char *, char *);
4399static int globv;
4400
4401static void glob3(char *i, char *j, char *k)
4402{
4403 char *index1, *index2, *index3;
4404 int c;
4405 int m;
4406
4407 m = globv;
4408 index1 = i;
4409 index2 = j;
4410 index3 = k;
4411 do {
4412 c = *index1;
4413 *index1++ = *index3;
4414 *index3++ = *index2;
4415 *index2++ = c;
4416 } while (--m);
4417}
4418
4419static void glob2(char *i, char *j)
4420{
4421 char *index1, *index2, c;
4422 int m;
4423
4424 m = globv;
4425 index1 = i;
4426 index2 = j;
4427 do {
4428 c = *index1;
4429 *index1++ = *index2;
4430 *index2++ = c;
4431 } while (--m);
4432}
4433
4434static void glob1(char *base, char *lim)
4435{
4436 char *i, *j;
4437 int v2;
4438 char *lptr, *hptr;
4439 int c;
4440 unsigned n;
4441
4442 v2 = globv;
4443
4444 top:
4445 n = (int) (lim - base);
4446 if (n <= v2)
4447 return;
4448 n = v2 * (n / (2 * v2));
4449 hptr = lptr = base + n;
4450 i = base;
4451 j = lim - v2;
4452 for (;;) {
4453 if (i < lptr) {
4454 c = (*func) (i, lptr);
4455 if (c == 0) {
4456 lptr -= v2;
4457 glob2(i, lptr);
4458 continue;
4459 }
4460 if (c < 0) {
4461 i += v2;
4462 continue;
4463 }
4464 }
4465
4466 begin:
4467 if (j > hptr) {
4468 c = (*func) (hptr, j);
4469 if (c == 0) {
4470 hptr += v2;
4471 glob2(hptr, j);
4472 goto begin;
4473 }
4474 if (c > 0) {
4475 if (i == lptr) {
4476 hptr += v2;
4477 glob3(i, hptr, j);
4478 i = (lptr += v2);
4479 goto begin;
4480 }
4481 glob2(i, j);
4482 j -= v2;
4483 i += v2;
4484 continue;
4485 }
4486 j -= v2;
4487 goto begin;
4488 }
4489
4490
4491 if (i == lptr) {
4492 if (lptr - base >= lim - hptr) {
4493 glob1(hptr + v2, lim);
4494 lim = lptr;
4495 } else {
4496 glob1(base, lptr);
4497 base = hptr + v2;
4498 }
4499 goto top;
4500 }
4501
4502 lptr -= v2;
4503 glob3(j, lptr, i);
4504 j = (hptr -= v2);
4505 }
4506}
4507
4508static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
4509{
4510 func = a3;
4511 globv = a2;
4512 glob1(a0, a0 + a1 * a2);
4513}
4514
4515
4516/* -------- io.c -------- */
4517
4518/*
4519 * shell IO
4520 */
4521
4522static int my_getc(int ec)
4523{
4524 int c;
4525
4526 if (e.linep > elinep) {
4527 while ((c = readc()) != '\n' && c);
4528 err("input line too long");
4529 gflg++;
4530 return c;
4531 }
4532 c = readc();
4533 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
4534 if (c == '\\') {
4535 c = readc();
4536 if (c == '\n' && ec != '\"')
4537 return my_getc(ec);
4538 c |= QUOTE;
4539 }
4540 }
4541 return c;
4542}
4543
4544static void unget(int c)
4545{
4546 if (e.iop >= e.iobase)
4547 e.iop->peekc = c;
4548}
4549
4550static int eofc(void)
4551{
4552 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4553}
4554
4555static int readc(void)
4556{
4557 int c;
4558
4559 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
4560
4561 for (; e.iop >= e.iobase; e.iop--) {
4562 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
4563 c = e.iop->peekc;
4564 if (c != '\0') {
4565 e.iop->peekc = 0;
4566 return c;
4567 }
4568 if (e.iop->prev != 0) {
4569 c = (*e.iop->iofn)(e.iop->argp, e.iop);
4570 if (c != '\0') {
4571 if (c == -1) {
4572 e.iop++;
4573 continue;
4574 }
4575 if (e.iop == iostack)
4576 ioecho(c);
4577 e.iop->prev = c;
4578 return e.iop->prev;
4579 }
4580 if (e.iop->task == XIO && e.iop->prev != '\n') {
4581 e.iop->prev = 0;
4582 if (e.iop == iostack)
4583 ioecho('\n');
4584 return '\n';
4585 }
4586 }
4587 if (e.iop->task == XIO) {
4588 if (multiline) {
4589 e.iop->prev = 0;
4590 return e.iop->prev;
4591 }
4592 if (interactive && e.iop == iostack + 1) {
4593#if ENABLE_FEATURE_EDITING
4594 current_prompt = prompt->value;
4595#else
4596 prs(prompt->value);
4597#endif
4598 }
4599 }
4600 } /* FOR */
4601
4602 if (e.iop >= iostack) {
4603 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
4604 return 0;
4605 }
4606
4607 DBGPRINTF(("READC: leave()...\n"));
4608 leave();
4609
4610 /* NOTREACHED */
4611 return 0;
4612}
4613
4614static void ioecho(char c)
4615{
4616 if (FLAG['v'])
4617 write(2, &c, sizeof c);
4618}
4619
4620
4621static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4622{
4623 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
4624 argp->afid, e.iop));
4625
4626 /* Set env ptr for io source to next array spot and check for array overflow */
4627 if (++e.iop >= &iostack[NPUSH]) {
4628 e.iop--;
4629 err("Shell input nested too deeply");
4630 gflg++;
4631 return;
4632 }
4633
4634 /* We did not overflow the NPUSH array spots so setup data structs */
4635
4636 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
4637
4638 if (argp->afid != AFID_NOBUF)
4639 e.iop->argp = argp;
4640 else {
4641
4642 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4643 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4644
4645 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4646
4647 if (e.iop == &iostack[0])
4648 e.iop->argp->afbuf = &mainbuf;
4649 else
4650 e.iop->argp->afbuf = &sharedbuf;
4651
4652 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4653 /* This line appears to be active when running scripts from command line */
4654 if ((isatty(e.iop->argp->afile) == 0)
4655 && (e.iop == &iostack[0]
4656 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4657 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4658 bufid = AFID_ID; /* AFID_ID = 0 */
4659
4660 e.iop->argp->afid = bufid; /* assign buffer id */
4661 }
4662
4663 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
4664 iostack, e.iop, e.iop->argp->afbuf));
4665 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
4666 &mainbuf, &sharedbuf, bufid, e.iop));
4667
4668 }
4669
4670 e.iop->prev = ~'\n';
4671 e.iop->peekc = 0;
4672 e.iop->xchar = 0;
4673 e.iop->nlcount = 0;
4674
4675 if (fn == filechar || fn == linechar)
4676 e.iop->task = XIO;
4677 else if (fn == (int (*)(struct ioarg *)) gravechar
4678 || fn == (int (*)(struct ioarg *)) qgravechar)
4679 e.iop->task = XGRAVE;
4680 else
4681 e.iop->task = XOTHER;
4682}
4683
4684static struct io *setbase(struct io *ip)
4685{
4686 struct io *xp;
4687
4688 xp = e.iobase;
4689 e.iobase = ip;
4690 return xp;
4691}
4692
4693/*
4694 * Input generating functions
4695 */
4696
4697/*
4698 * Produce the characters of a string, then a newline, then EOF.
4699 */
4700static int nlchar(struct ioarg *ap)
4701{
4702 int c;
4703
4704 if (ap->aword == NULL)
4705 return 0;
4706 c = *ap->aword++;
4707 if (c == 0) {
4708 ap->aword = NULL;
4709 return '\n';
4710 }
4711 return c;
4712}
4713
4714/*
4715 * Given a list of words, produce the characters
4716 * in them, with a space after each word.
4717 */
4718static int wdchar(struct ioarg *ap)
4719{
4720 char c;
4721 char **wl;
4722
4723 wl = ap->awordlist;
4724 if (wl == NULL)
4725 return 0;
4726 if (*wl != NULL) {
4727 c = *(*wl)++;
4728 if (c != 0)
4729 return c & 0177;
4730 ap->awordlist++;
4731 return ' ';
4732 }
4733 ap->awordlist = NULL;
4734 return '\n';
4735}
4736
4737/*
4738 * Return the characters of a list of words,
4739 * producing a space between them.
4740 */
4741static int dolchar(struct ioarg *ap)
4742{
4743 char *wp;
4744
4745 wp = *ap->awordlist++;
4746 if (wp != NULL) {
4747 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4748 return -1;
4749 }
4750 return 0;
4751}
4752
4753static int xxchar(struct ioarg *ap)
4754{
4755 int c;
4756
4757 if (ap->aword == NULL)
4758 return 0;
4759 c = *ap->aword++;
4760 if (c == '\0') {
4761 ap->aword = NULL;
4762 return ' ';
4763 }
4764 return c;
4765}
4766
4767/*
4768 * Produce the characters from a single word (string).
4769 */
4770static int strchar(struct ioarg *ap)
4771{
4772 if (ap->aword == NULL)
4773 return 0;
4774 return *ap->aword++;
4775}
4776
4777/*
4778 * Produce quoted characters from a single word (string).
4779 */
4780static int qstrchar(struct ioarg *ap)
4781{
4782 int c;
4783
4784 if (ap->aword == NULL)
4785 return 0;
4786 c = *ap->aword++;
4787 if (c)
4788 c |= QUOTE;
4789 return c;
4790}
4791
4792/*
4793 * Return the characters from a file.
4794 */
4795static int filechar(struct ioarg *ap)
4796{
4797 int i;
4798 char c;
4799 struct iobuf *bp = ap->afbuf;
4800
4801 if (ap->afid != AFID_NOBUF) {
4802 i = (ap->afid != bp->id);
4803 if (i || bp->bufp == bp->ebufp) {
4804 if (i)
4805 lseek(ap->afile, ap->afpos, SEEK_SET);
4806
4807 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4808 if (i <= 0) {
4809 closef(ap->afile);
4810 return 0;
4811 }
4812
4813 bp->id = ap->afid;
4814 bp->bufp = bp->buf;
4815 bp->ebufp = bp->bufp + i;
4816 }
4817
4818 ap->afpos++;
4819 return *bp->bufp++ & 0177;
4820 }
4821#if ENABLE_FEATURE_EDITING
4822 if (interactive && isatty(ap->afile)) {
4823 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
4824 static int position = 0, size = 0;
4825
4826 while (size == 0 || position >= size) {
4827 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4828 size = strlen(filechar_cmdbuf);
4829 position = 0;
4830 }
4831 c = filechar_cmdbuf[position];
4832 position++;
4833 return c;
4834 }
4835#endif
4836 i = safe_read(ap->afile, &c, sizeof(c));
4837 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4838}
4839
4840/*
4841 * Return the characters from a here temp file.
4842 */
4843static int herechar(struct ioarg *ap)
4844{
4845 char c;
4846
4847 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4848 close(ap->afile);
4849 c = '\0';
4850 }
4851 return c;
4852}
4853
4854/*
4855 * Return the characters produced by a process (`...`).
4856 * Quote them if required, and remove any trailing newline characters.
4857 */
4858static int gravechar(struct ioarg *ap, struct io *iop)
4859{
4860 int c;
4861
4862 c = qgravechar(ap, iop) & ~QUOTE;
4863 if (c == '\n')
4864 c = ' ';
4865 return c;
4866}
4867
4868static int qgravechar(struct ioarg *ap, struct io *iop)
4869{
4870 int c;
4871
4872 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4873
4874 if (iop->xchar) {
4875 if (iop->nlcount) {
4876 iop->nlcount--;
4877 return '\n' | QUOTE;
4878 }
4879 c = iop->xchar;
4880 iop->xchar = 0;
4881 } else if ((c = filechar(ap)) == '\n') {
4882 iop->nlcount = 1;
4883 while ((c = filechar(ap)) == '\n')
4884 iop->nlcount++;
4885 iop->xchar = c;
4886 if (c == 0)
4887 return c;
4888 iop->nlcount--;
4889 c = '\n';
4890 }
4891 return c != 0 ? c | QUOTE : 0;
4892}
4893
4894/*
4895 * Return a single command (usually the first line) from a file.
4896 */
4897static int linechar(struct ioarg *ap)
4898{
4899 int c;
4900
4901 c = filechar(ap);
4902 if (c == '\n') {
4903 if (!multiline) {
4904 closef(ap->afile);
4905 ap->afile = -1; /* illegal value */
4906 }
4907 }
4908 return c;
4909}
4910
4911/*
4912 * remap fd into Shell's fd space
4913 */
4914static int remap(int fd)
4915{
4916 int i;
4917 int map[NOFILE];
4918 int newfd;
4919
4920 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
4921
4922 if (fd < e.iofd) {
4923 for (i = 0; i < NOFILE; i++)
4924 map[i] = 0;
4925
4926 do {
4927 map[fd] = 1;
4928 newfd = dup(fd);
4929 fd = newfd;
4930 } while (fd >= 0 && fd < e.iofd);
4931
4932 for (i = 0; i < NOFILE; i++)
4933 if (map[i])
4934 close(i);
4935
4936 if (fd < 0)
4937 err("too many files open in shell");
4938 }
4939
4940 return fd;
4941}
4942
4943static int openpipe(int *pv)
4944{
4945 int i;
4946
4947 i = pipe(pv);
4948 if (i < 0)
4949 err("can't create pipe - try again");
4950 return i;
4951}
4952
4953static void closepipe(int *pv)
4954{
4955 if (pv != NULL) {
4956 close(*pv++);
4957 close(*pv);
4958 }
4959}
4960
4961
4962/* -------- here.c -------- */
4963
4964/*
4965 * here documents
4966 */
4967
4968static void markhere(char *s, struct ioword *iop)
4969{
4970 struct here *h, *lh;
4971
4972 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
4973
4974 h = (struct here *) space(sizeof(struct here));
4975 if (h == NULL)
4976 return;
4977
4978 h->h_tag = evalstr(s, DOSUB);
4979 if (h->h_tag == 0)
4980 return;
4981
4982 h->h_iop = iop;
4983 iop->io_name = 0;
4984 h->h_next = NULL;
4985 if (inhere == 0)
4986 inhere = h;
4987 else {
4988 for (lh = inhere; lh != NULL; lh = lh->h_next) {
4989 if (lh->h_next == 0) {
4990 lh->h_next = h;
4991 break;
4992 }
4993 }
4994 }
4995 iop->io_flag |= IOHERE | IOXHERE;
4996 for (s = h->h_tag; *s; s++) {
4997 if (*s & QUOTE) {
4998 iop->io_flag &= ~IOXHERE;
4999 *s &= ~QUOTE;
5000 }
5001 }
5002 h->h_dosub = iop->io_flag & IOXHERE;
5003}
5004
5005static void gethere(void)
5006{
5007 struct here *h, *hp;
5008
5009 DBGPRINTF7(("GETHERE: enter...\n"));
5010
5011 /* Scan here files first leaving inhere list in place */
5012 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5013 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
5014
5015 /* Make inhere list active - keep list intact for scraphere */
5016 if (hp != NULL) {
5017 hp->h_next = acthere;
5018 acthere = inhere;
5019 inhere = NULL;
5020 }
5021}
5022
5023static void readhere(char **name, char *s, int ec)
5024{
5025 int tf;
5026 char tname[30] = ".msh_XXXXXX";
5027 int c;
5028 jmp_buf ev;
5029 char myline[LINELIM + 1];
5030 char *thenext;
5031
5032 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
5033
5034 tf = mkstemp(tname);
5035 if (tf < 0)
5036 return;
5037
5038 *name = strsave(tname, areanum);
5039 errpt = ev;
5040 if (newenv(setjmp(errpt)) != 0)
5041 unlink(tname);
5042 else {
5043 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
5044 e.iobase = e.iop;
5045 for (;;) {
5046 if (interactive && e.iop <= iostack) {
5047#if ENABLE_FEATURE_EDITING
5048 current_prompt = cprompt->value;
5049#else
5050 prs(cprompt->value);
5051#endif
5052 }
5053 thenext = myline;
5054 while ((c = my_getc(ec)) != '\n' && c) {
5055 if (ec == '\'')
5056 c &= ~QUOTE;
5057 if (thenext >= &myline[LINELIM]) {
5058 c = 0;
5059 break;
5060 }
5061 *thenext++ = c;
5062 }
5063 *thenext = 0;
5064 if (strcmp(s, myline) == 0 || c == 0)
5065 break;
5066 *thenext++ = '\n';
5067 write(tf, myline, (int) (thenext - myline));
5068 }
5069 if (c == 0) {
5070 prs("here document `");
5071 prs(s);
5072 err("' unclosed");
5073 }
5074 quitenv();
5075 }
5076 close(tf);
5077}
5078
5079/*
5080 * open here temp file.
5081 * if unquoted here, expand here temp file into second temp file.
5082 */
5083static int herein(char *hname, int xdoll)
5084{
5085 int hf;
5086 int tf;
5087
5088#if __GNUC__
5089 /* Avoid longjmp clobbering */
5090 (void) &tf;
5091#endif
5092 if (hname == NULL)
5093 return -1;
5094
5095 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5096
5097 hf = open(hname, O_RDONLY);
5098 if (hf < 0)
5099 return -1;
5100
5101 if (xdoll) {
5102 char c;
5103 char tname[30] = ".msh_XXXXXX";
5104 jmp_buf ev;
5105
5106 tf = mkstemp(tname);
5107 if (tf < 0)
5108 return -1;
5109 errpt = ev;
5110 if (newenv(setjmp(errpt)) == 0) {
5111 PUSHIO(afile, hf, herechar);
5112 setbase(e.iop);
5113 while ((c = subgetc(0, 0)) != 0) {
5114 c &= ~QUOTE;
5115 write(tf, &c, sizeof c);
5116 }
5117 quitenv();
5118 } else
5119 unlink(tname);
5120 close(tf);
5121 tf = open(tname, O_RDONLY);
5122 unlink(tname);
5123 return tf;
5124 }
5125 return hf;
5126}
5127
5128static void scraphere(void)
5129{
5130 struct here *h;
5131
5132 DBGPRINTF7(("SCRAPHERE: enter...\n"));
5133
5134 for (h = inhere; h != NULL; h = h->h_next) {
5135 if (h->h_iop && h->h_iop->io_name)
5136 unlink(h->h_iop->io_name);
5137 }
5138 inhere = NULL;
5139}
5140
5141/* unlink here temp files before a freearea(area) */
5142static void freehere(int area)
5143{
5144 struct here *h, *hl;
5145
5146 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5147
5148 hl = NULL;
5149 for (h = acthere; h != NULL; h = h->h_next)
5150 if (getarea((char *) h) >= area) {
5151 if (h->h_iop->io_name != NULL)
5152 unlink(h->h_iop->io_name);
5153 if (hl == NULL)
5154 acthere = h->h_next;
5155 else
5156 hl->h_next = h->h_next;
5157 } else
5158 hl = h;
5159}
5160
5161
5162/* -------- sh.c -------- */
5163/*
5164 * shell
5165 */
5166
5167int msh_main(int argc, char **argv);
5168int msh_main(int argc, char **argv)
5169{
5170 int f;
5171 char *s;
5172 int cflag;
5173 char *name, **ap;
5174 int (*iof) (struct ioarg *);
5175
5176 PTR_TO_GLOBALS = xzalloc(sizeof(G));
5177 sharedbuf.id = AFID_NOBUF;
5178 mainbuf.id = AFID_NOBUF;
5179 e.linep = line;
5180 elinep = line + sizeof(line) - 5;
5181
5182#if ENABLE_FEATURE_EDITING
5183 line_input_state = new_line_input_t(FOR_SHELL);
5184#endif
5185
5186 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5187
5188 initarea();
5189 ap = environ;
5190 if (ap != NULL) {
5191 while (*ap)
5192 assign(*ap++, !COPYV);
5193 for (ap = environ; *ap;)
5194 export(lookup(*ap++));
5195 }
5196 closeall();
5197 areanum = 1;
5198
5199 shell = lookup("SHELL");
5200 if (shell->value == null)
5201 setval(shell, (char *)DEFAULT_SHELL);
5202 export(shell);
5203
5204 homedir = lookup("HOME");
5205 if (homedir->value == null)
5206 setval(homedir, "/");
5207 export(homedir);
5208
5209 setval(lookup("$"), putn(getpid()));
5210
5211 path = lookup("PATH");
5212 if (path->value == null) {
5213 /* Can be merged with same string elsewhere in bbox */
5214 if (geteuid() == 0)
5215 setval(path, bb_default_root_path);
5216 else
5217 setval(path, bb_default_path);
5218 }
5219 export(path);
5220
5221 ifs = lookup("IFS");
5222 if (ifs->value == null)
5223 setval(ifs, " \t\n");
5224
5225#ifdef MSHDEBUG
5226 mshdbg_var = lookup("MSHDEBUG");
5227 if (mshdbg_var->value == null)
5228 setval(mshdbg_var, "0");
5229#endif
5230
5231 prompt = lookup("PS1");
5232#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5233 if (prompt->value == null)
5234#endif
5235 setval(prompt, DEFAULT_USER_PROMPT);
5236 if (geteuid() == 0) {
5237 setval(prompt, DEFAULT_ROOT_PROMPT);
5238 prompt->status &= ~EXPORT;
5239 }
5240 cprompt = lookup("PS2");
5241#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5242 if (cprompt->value == null)
5243#endif
5244 setval(cprompt, "> ");
5245
5246 iof = filechar;
5247 cflag = 0;
5248 name = *argv++;
5249 if (--argc >= 1) {
5250 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5251 for (s = argv[0] + 1; *s; s++)
5252 switch (*s) {
5253 case 'c':
5254 prompt->status &= ~EXPORT;
5255 cprompt->status &= ~EXPORT;
5256 setval(prompt, "");
5257 setval(cprompt, "");
5258 cflag = 1;
5259 if (--argc > 0)
5260 PUSHIO(aword, *++argv, iof = nlchar);
5261 break;
5262
5263 case 'q':
5264 qflag = SIG_DFL;
5265 break;
5266
5267 case 's':
5268 /* standard input */
5269 break;
5270
5271 case 't':
5272 prompt->status &= ~EXPORT;
5273 setval(prompt, "");
5274 iof = linechar;
5275 break;
5276
5277 case 'i':
5278 interactive++;
5279 default:
5280 if (*s >= 'a' && *s <= 'z')
5281 FLAG[(int) *s]++;
5282 }
5283 } else {
5284 argv--;
5285 argc++;
5286 }
5287
5288 if (iof == filechar && --argc > 0) {
5289 setval(prompt, "");
5290 setval(cprompt, "");
5291 prompt->status &= ~EXPORT;
5292 cprompt->status &= ~EXPORT;
5293
5294/* Shell is non-interactive, activate printf-based debug */
5295#ifdef MSHDEBUG
5296 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5297 if (mshdbg < 0)
5298 mshdbg = 0;
5299#endif
5300 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5301
5302 name = *++argv;
5303 if (newfile(name))
5304 exit(1); /* Exit on error */
5305 }
5306 }
5307
5308 setdash();
5309
5310 /* This won't be true if PUSHIO has been called, say from newfile() above */
5311 if (e.iop < iostack) {
5312 PUSHIO(afile, 0, iof);
5313 if (isatty(0) && isatty(1) && !cflag) {
5314 interactive++;
5315#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5316#ifdef MSHDEBUG
5317 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
5318#else
5319 printf("\n\n%s built-in shell (msh)\n", bb_banner);
5320#endif
5321 printf("Enter 'help' for a list of built-in commands.\n\n");
5322#endif
5323 }
5324 }
5325
5326 signal(SIGQUIT, qflag);
5327 if (name && name[0] == '-') {
5328 interactive++;
5329 f = open(".profile", O_RDONLY);
5330 if (f >= 0)
5331 next(remap(f));
5332 f = open("/etc/profile", O_RDONLY);
5333 if (f >= 0)
5334 next(remap(f));
5335 }
5336 if (interactive)
5337 signal(SIGTERM, sig);
5338
5339 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5340 signal(SIGINT, onintr);
5341 dolv = argv;
5342 dolc = argc;
5343 dolv[0] = name;
5344 if (dolc > 1) {
5345 for (ap = ++argv; --argc > 0;) {
5346 *ap = *argv++;
5347 if (assign(*ap, !COPYV)) {
5348 dolc--; /* keyword */
5349 } else {
5350 ap++;
5351 }
5352 }
5353 }
5354 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5355
5356 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
5357
5358 for (;;) {
5359 if (interactive && e.iop <= iostack) {
5360#if ENABLE_FEATURE_EDITING
5361 current_prompt = prompt->value;
5362#else
5363 prs(prompt->value);
5364#endif
5365 }
5366 onecommand();
5367 /* Ensure that getenv("PATH") stays current */
5368 setenv("PATH", path->value, 1);
5369 }
5370
5371 DBGPRINTF(("MSH_MAIN: returning.\n"));
5372}
5373
5374
5375/*
5376 * Copyright (c) 1987,1997, Prentice Hall
5377 * All rights reserved.
5378 *
5379 * Redistribution and use of the MINIX operating system in source and
5380 * binary forms, with or without modification, are permitted provided
5381 * that the following conditions are met:
5382 *
5383 * Redistributions of source code must retain the above copyright
5384 * notice, this list of conditions and the following disclaimer.
5385 *
5386 * Redistributions in binary form must reproduce the above
5387 * copyright notice, this list of conditions and the following
5388 * disclaimer in the documentation and/or other materials provided
5389 * with the distribution.
5390 *
5391 * Neither the name of Prentice Hall nor the names of the software
5392 * authors or contributors may be used to endorse or promote
5393 * products derived from this software without specific prior
5394 * written permission.
5395 *
5396 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5397 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5398 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5399 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5400 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5401 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5402 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5403 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5404 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5405 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5406 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5407 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5408 *
5409 */
Note: See TracBrowser for help on using the repository browser.