Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/sh/main.c
39481 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1991, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Kenneth Almquist.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include <stdio.h>
36
#include <signal.h>
37
#include <sys/stat.h>
38
#include <unistd.h>
39
#include <fcntl.h>
40
#include <locale.h>
41
#include <errno.h>
42
43
#include "shell.h"
44
#include "main.h"
45
#include "mail.h"
46
#include "options.h"
47
#include "output.h"
48
#include "parser.h"
49
#include "nodes.h"
50
#include "expand.h"
51
#include "eval.h"
52
#include "jobs.h"
53
#include "input.h"
54
#include "trap.h"
55
#include "var.h"
56
#include "show.h"
57
#include "memalloc.h"
58
#include "error.h"
59
#include "mystring.h"
60
#include "exec.h"
61
#include "cd.h"
62
#include "redir.h"
63
#include "builtins.h"
64
#ifndef NO_HISTORY
65
#include "myhistedit.h"
66
#endif
67
68
int rootpid;
69
int rootshell;
70
struct jmploc main_handler;
71
int localeisutf8, initial_localeisutf8;
72
73
static void reset(void);
74
static void cmdloop(int);
75
static void read_profile(const char *);
76
static char *find_dot_file(char *);
77
78
/*
79
* Main routine. We initialize things, parse the arguments, execute
80
* profiles if we're a login shell, and then call cmdloop to execute
81
* commands. The setjmp call sets up the location to jump to when an
82
* exception occurs. When an exception occurs the variable "state"
83
* is used to figure out how far we had gotten.
84
*/
85
86
int
87
main(int argc, char *argv[])
88
{
89
/*
90
* As smark is accessed after a longjmp, it cannot be a local in main().
91
* The C standard specifies that the values of non-volatile local
92
* variables are unspecified after a jump if modified between the
93
* setjmp and longjmp.
94
*/
95
static struct stackmark smark, smark2;
96
volatile int state;
97
char *shinit;
98
int login;
99
100
(void) setlocale(LC_ALL, "");
101
initcharset();
102
state = 0;
103
if (setjmp(main_handler.loc)) {
104
if (state == 0 || iflag == 0 || ! rootshell ||
105
exception == EXEXIT)
106
exitshell(exitstatus);
107
reset();
108
if (exception == EXINT)
109
out2fmt_flush("\n");
110
popstackmark(&smark);
111
FORCEINTON; /* enable interrupts */
112
if (state == 1)
113
goto state1;
114
else if (state == 2)
115
goto state2;
116
else if (state == 3)
117
goto state3;
118
else
119
goto state4;
120
}
121
handler = &main_handler;
122
#ifdef DEBUG
123
opentrace();
124
trputs("Shell args: "); trargs(argv);
125
#endif
126
rootpid = getpid();
127
rootshell = 1;
128
INTOFF;
129
initvar();
130
setstackmark(&smark);
131
setstackmark(&smark2);
132
login = procargs(argc, argv);
133
trap_init();
134
pwd_init(iflag);
135
INTON;
136
if (iflag)
137
chkmail(1);
138
if (login) {
139
state = 1;
140
read_profile("/etc/profile");
141
state1:
142
state = 2;
143
if (privileged == 0)
144
read_profile("${HOME-}/.profile");
145
else
146
read_profile("/etc/suid_profile");
147
}
148
state2:
149
state = 3;
150
if (!privileged && iflag) {
151
if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
152
state = 3;
153
read_profile(shinit);
154
}
155
}
156
#ifndef NO_HISTORY
157
if (iflag)
158
histload();
159
#endif
160
state3:
161
state = 4;
162
popstackmark(&smark2);
163
if (minusc) {
164
evalstring(minusc, sflag ? 0 : EV_EXIT);
165
}
166
state4:
167
if (sflag || minusc == NULL) {
168
cmdloop(1);
169
}
170
exitshell(exitstatus);
171
/*NOTREACHED*/
172
return 0;
173
}
174
175
static void
176
reset(void)
177
{
178
reseteval();
179
resetinput();
180
}
181
182
/*
183
* Read and execute commands. "Top" is nonzero for the top level command
184
* loop; it turns on prompting if the shell is interactive.
185
*/
186
187
static void
188
cmdloop(int top)
189
{
190
union node *n;
191
struct stackmark smark;
192
int inter;
193
int numeof = 0;
194
195
TRACE(("cmdloop(%d) called\n", top));
196
setstackmark(&smark);
197
for (;;) {
198
if (pendingsig)
199
dotrap();
200
inter = 0;
201
if (iflag && top) {
202
inter++;
203
showjobs(1, SHOWJOBS_DEFAULT);
204
chkmail(0);
205
flushout(&output);
206
}
207
n = parsecmd(inter);
208
/* showtree(n); DEBUG */
209
if (n == NEOF) {
210
if (!top || numeof >= 50)
211
break;
212
if (!stoppedjobs()) {
213
if (!Iflag)
214
break;
215
out2fmt_flush("\nUse \"exit\" to leave shell.\n");
216
}
217
numeof++;
218
} else if (n != NULL && nflag == 0) {
219
job_warning = (job_warning == 2) ? 1 : 0;
220
numeof = 0;
221
evaltree(n, 0);
222
}
223
popstackmark(&smark);
224
setstackmark(&smark);
225
if (evalskip != 0) {
226
if (evalskip == SKIPRETURN)
227
evalskip = 0;
228
break;
229
}
230
}
231
popstackmark(&smark);
232
if (top && iflag) {
233
out2c('\n');
234
flushout(out2);
235
}
236
}
237
238
239
240
/*
241
* Read /etc/profile or .profile. Return on error.
242
*/
243
244
static void
245
read_profile(const char *name)
246
{
247
int fd;
248
const char *expandedname;
249
int oflags = O_RDONLY | O_CLOEXEC;
250
251
if (verifyflag)
252
oflags |= O_VERIFY;
253
254
expandedname = expandstr(name);
255
if (expandedname == NULL)
256
return;
257
INTOFF;
258
if ((fd = open(expandedname, oflags)) >= 0)
259
setinputfd(fd, 1);
260
INTON;
261
if (fd < 0)
262
return;
263
cmdloop(0);
264
popfile();
265
}
266
267
268
269
/*
270
* Read a file containing shell functions.
271
*/
272
273
void
274
readcmdfile(const char *name, int verify)
275
{
276
setinputfile(name, 1, verify);
277
cmdloop(0);
278
popfile();
279
}
280
281
282
283
/*
284
* Take commands from a file. To be compatible we should do a path
285
* search for the file, which is necessary to find sub-commands.
286
*/
287
288
289
static char *
290
find_dot_file(char *basename)
291
{
292
char *fullname;
293
const char *opt;
294
const char *path = pathval();
295
struct stat statb;
296
297
/* don't try this for absolute or relative paths */
298
if( strchr(basename, '/'))
299
return basename;
300
301
while ((fullname = padvance(&path, &opt, basename)) != NULL) {
302
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
303
/*
304
* Don't bother freeing here, since it will
305
* be freed by the caller.
306
*/
307
return fullname;
308
}
309
stunalloc(fullname);
310
}
311
return basename;
312
}
313
314
int
315
dotcmd(int argc, char **argv)
316
{
317
char *filename, *fullname;
318
319
if (argc < 2)
320
error("missing filename");
321
322
exitstatus = 0;
323
324
/*
325
* Because we have historically not supported any options,
326
* only treat "--" specially.
327
*/
328
filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1];
329
330
fullname = find_dot_file(filename);
331
setinputfile(fullname, 1, -1 /* verify */);
332
commandname = fullname;
333
cmdloop(0);
334
popfile();
335
return exitstatus;
336
}
337
338
339
int
340
exitcmd(int argc, char **argv)
341
{
342
if (stoppedjobs())
343
return 0;
344
if (argc > 1)
345
exitshell(number(argv[1]));
346
else
347
exitshell_savedstatus();
348
}
349
350