blob: b2fd2442694c0c38979c44401d040826a3c962ca [file] [log] [blame]
Denis Vlasenko395ae452008-07-14 06:29:38 +000012008-07-14
2
3 Command parsing
4
5Command parsing results in "pipe" structures. "Pipe" structure
6does not always correspond to what sh language calls "pipe",
7it also controls execution of if, while, etc statements.
8
9struct pipe fields:
10 smallint res_word - "none" for normal commands,
11 "if" for if condition etc
12 struct child_prog progs[] - array of commands in pipe
13 smallint followup - how this pipe is related to next: is it
14 "pipe; pipe", "pipe & pipe" "pipe && pipe",
15 "pipe || pipe"?
16
17Blocks of commands { pipe; pipe; } and (pipe; pipe) are represented
18as one pipe struct with one progs[0] element which is a "group" -
19struct child_prog can contain a list of pipes. Sometimes these
20"groups" are created implicitly, e.g. every control
21statement (if, while, etc) sits inside its own "pipe" struct).
22
23res_word controls statement execution. Examples:
24
25"echo Hello" -
26pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello'
27pipe 1 res_word=NONE followup=1 SEQ
28
29"echo foo || echo bar" -
30pipe 0 res_word=NONE followup=OR prog[0] 'echo' 'foo'
31pipe 1 res_word=NONE followup=SEQ prog[0] 'echo' 'bar'
32pipe 2 res_word=NONE followup=SEQ
33
34"if true; then echo Hello; true; fi" -
35res_word=NONE followup=SEQ
36 prog 0 group {}:
37 pipe 0 res_word=IF followup=SEQ prog[0] 'true'
38 pipe 1 res_word=THEN followup=SEQ prog[0] 'echo' 'Hello'
39 pipe 2 res_word=THEN followup=SEQ prog[0] 'true'
40 pipe 3 res_word=FI followup=SEQ
41 pipe 4 res_word=NONE followup=(null)
42pipe 1 res_word=NONE followup=SEQ
43
44"if true; then { echo Hello; true; }; fi" -
45pipe 0 res_word=NONE followup=SEQ
46 prog 0 group {}:
47 pipe 0 res_word=IF followup=SEQ prog[0] 'true'
48 pipe 1 res_word=THEN followup=SEQ
49 prog 0 group {}:
50 pipe 0 res_word=NONE followup=SEQ prog[0] 'echo' 'Hello'
51 pipe 1 res_word=NONE followup=SEQ prog[0] 'true'
52 pipe 2 res_word=NONE followup=SEQ
53 pipe 2 res_word=NONE followup=(null)
54pipe 1 res_word=NONE followup=1 SEQ
55
56"for v in a b; do echo $v; true; done" -
57pipe 0 res_word=NONE followup=SEQ
58 prog 0 group {}:
59 pipe 0 res_word=FOR followup=SEQ prog[0] 'v'
60 pipe 1 res_word=IN followup=SEQ prog[0] 'a' 'b'
61 pipe 2 res_word=DO followup=SEQ prog[0] 'echo' '$v'
62 pipe 3 res_word=DO followup=SEQ prog[0] 'true'
63 pipe 4 res_word=DONE followup=SEQ
64 pipe 5 res_word=NONE followup=(null)
65pipe 1 res_word=NONE followup=SEQ
66
67Note how "THEN" and "DO" does not just mark the first pipe,
68it "sticks" to all pipes in the body. This is used when
69hush executes parsed pipes.
70
71Dummy trailing pipes with no commands are artifacts of imperfect
72parsing algorithm - done_pipe() appends new pipe struct beforehand
73and last one ends up empty and unused.
74
Denis Vlasenko757361f2008-07-14 08:26:47 +000075"for" and "case" statements (ab)use progs[] to keep their data
76instead of argv vector progs[] usually do. "for" keyword is forcing
77pipe termination after first word, which makes hush see
78"for v in..." as "for v; in...". "case" keyword does the same.
79Other judiciuosly placed hacks make hush see
80"case word in a) cmd1;; b) cmd2;; esac" as if it was
81"case word; match a; cmd; match b; cmd2; esac"
82("match" is a fictitious keyword here):
83
84"case word in a) cmd1;; b) cmd2; esac" -
85pipe 0 res_word=NONE followup=1 SEQ
86 prog 0 group {}:
87 pipe 0 res_word=CASE followup=SEQ prog[0] 'word'
88 pipe 1 res_word=MATCH followup=SEQ prog[0] 'a'
89 pipe 2 res_word=CASEI followup=SEQ prog[0] 'cmd1'
90 pipe 3 res_word=MATCH followup=SEQ prog[0] 'b'
91 pipe 4 res_word=CASEI followup=SEQ prog[0] 'cmd2'
92 pipe 5 res_word=CASEI followup=SEQ prog[0] 'cmd3'
93 pipe 6 res_word=ESAC followup=SEQ
94 pipe 7 res_word=NONE followup=(null)
95pipe 1 res_word=NONE followup=1 SEQ
96
Denis Vlasenko395ae452008-07-14 06:29:38 +000097
982008-01
99
Denis Vlasenko757361f2008-07-14 08:26:47 +0000100 Command execution
Denis Vlasenko05743d72008-02-10 12:10:08 +0000101
102/* callsite: process_command_subs */
103generate_stream_from_list(struct pipe *head) - handles `cmds`
104 create UNIX pipe
105 [v]fork
106 child:
107 redirect pipe output to stdout
108 _exit(run_list(head)); /* leaks memory */
109 parent:
110 return UNIX pipe's output fd
111 /* head is freed by the caller */
112
113/* callsite: parse_and_run_stream */
114run_and_free_list(struct pipe *)
115 run_list(struct pipe *)
116 free_pipe_list(struct pipe *)
117
118/* callsites: generate_stream_from_list, run_and_free_list, pseudo_exec, run_pipe */
119run_list(struct pipe *) - handles "cmd; cmd2 && cmd3", while/for/do loops
120 run_pipe - for every pipe in list
121
122/* callsite: run_list */
123run_pipe - runs "cmd1 | cmd2 | cmd3 [&]"
Denis Vlasenko0ef240d2008-02-10 16:00:30 +0000124 run_list - used if only one cmd and it is of the form "{cmds;}"
Denis Vlasenko05743d72008-02-10 12:10:08 +0000125 forks for every cmd if more than one cmd or if & is there
126 pseudo_exec - runs each "cmdN" (handles builtins etc)
127
Denis Vlasenko0ef240d2008-02-10 16:00:30 +0000128/* callsite: run_pipe */
Denis Vlasenko05743d72008-02-10 12:10:08 +0000129pseudo_exec - runs "cmd" (handles builtins etc)
130 exec - execs external programs
131 run_list - used if cmdN is "(cmds)" or "{cmds;}"
132 /* problem: putenv's malloced strings into environ -
133 ** with vfork they will leak into parent process
134 */
135 /* problem with ENABLE_FEATURE_SH_STANDALONE:
136 ** run_applet_no_and_exit(a, argv) uses exit - this can interfere
137 ** with vfork - switch to _exit there?
138 */