system.c revision 43811
1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
7 * $Id: system.c,v 1.88 1999/02/05 22:15:52 jkh Exp $
8 *
9 * Jordan Hubbard
10 *
11 * My contributions are in the public domain.
12 *
13 * Parts of this file are also blatently stolen from Poul-Henning Kamp's
14 * previous version of sysinstall, and as such fall under his "BEERWARE license"
15 * so buy him a beer if you like it!  Buy him a beer for me, too!
16 * Heck, get him completely drunk and send me pictures! :-)
17 */
18
19#include "sysinstall.h"
20#include <signal.h>
21#include <sys/reboot.h>
22#include <machine/console.h>
23#include <sys/fcntl.h>
24#include <sys/ioctl.h>
25#include <sys/stat.h>
26
27
28/* Where we stick our temporary expanded doc file */
29#define	DOC_TMP_DIR	"/tmp/.doc"
30#define	DOC_TMP_FILE	"/tmp/.doc/doc.tmp"
31
32static pid_t ehs_pid;
33
34/*
35 * Handle interrupt signals - this probably won't work in all cases
36 * due to our having bogotified the internal state of dialog or curses,
37 * but we'll give it a try.
38 */
39static void
40handle_intr(int sig)
41{
42    WINDOW *save = savescr();
43
44    if (!msgYesNo("Are you sure you want to abort the installation?"))
45	systemShutdown(-1);
46    else
47	restorescr(save);
48}
49
50/* Expand a file into a convenient location, nuking it each time */
51static char *
52expand(char *fname)
53{
54    char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip";
55
56    if (!directory_exists(DOC_TMP_DIR)) {
57	Mkdir(DOC_TMP_DIR);
58	if (chown(DOC_TMP_DIR, 0, 0) < 0)
59	    return NULL;
60	if (chmod(DOC_TMP_DIR, S_IRWXU) < 0)
61	    return NULL;
62    }
63    else
64	unlink(DOC_TMP_FILE);
65    if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE))
66	return NULL;
67    return DOC_TMP_FILE;
68}
69
70/* Initialize system defaults */
71void
72systemInitialize(int argc, char **argv)
73{
74    int i;
75
76    signal(SIGINT, SIG_IGN);
77    globalsInit();
78
79    /* Are we running as init? */
80    if (getpid() == 1) {
81	int fd, type;
82
83	RunningAsInit = 1;
84	setsid();
85	close(0);
86	fd = open("/dev/ttyv0", O_RDWR);
87	if (fd == -1)
88	    fd = open("/dev/console", O_RDWR);	/* fallback */
89	else
90	    OnVTY = TRUE;
91	/*
92	 * To make _sure_ we're on a VTY and don't have /dev/console switched
93	 * away to a serial port or something, attempt to set the cursor appearance.
94	 */
95	type = 0;	/* normal */
96	if (OnVTY) {
97	    int fd2;
98
99	    if ((fd2 = open("/dev/console", O_RDWR)) != -1) {
100		if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) {
101		    OnVTY = FALSE;
102		    close(fd); close(fd2);
103		    open("/dev/console", O_RDWR);
104		}
105		else
106		    close(fd2);
107	    }
108	}
109	close(1); dup(0);
110	close(2); dup(0);
111	printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console");
112	i = ioctl(0, TIOCSCTTY, (char *)NULL);
113	setlogin("root");
114	setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1);
115	setbuf(stdin, 0);
116	setbuf(stderr, 0);
117    }
118    else {
119	char hname[256];
120
121	/* Initalize various things for a multi-user environment */
122	if (!gethostname(hname, sizeof hname))
123	    variable_set2(VAR_HOSTNAME, hname, 1);
124    }
125
126    if (set_termcap() == -1) {
127	printf("Can't find terminal entry\n");
128	exit(-1);
129    }
130
131    /* XXX - libdialog has particularly bad return value checking */
132    init_dialog();
133
134    /* If we haven't crashed I guess dialog is running ! */
135    DialogActive = TRUE;
136
137    /* Make sure HOME is set for those utilities that need it */
138    if (!getenv("HOME"))
139	setenv("HOME", "/", 1);
140    signal(SIGINT, handle_intr);
141    (void)vsystem("rm -rf %s", DOC_TMP_DIR);
142}
143
144/* Close down and prepare to exit */
145void
146systemShutdown(int status)
147{
148    /* If some media is open, close it down */
149    if (status >=0 && mediaDevice)
150	mediaDevice->shutdown(mediaDevice);
151
152    /* write out any changes to rc.conf .. */
153    configRC_conf();
154
155    /* Shut down the dialog library */
156    if (DialogActive) {
157	end_dialog();
158	DialogActive = FALSE;
159    }
160
161    /* Shut down curses */
162    endwin();
163
164    /* If we have a temporary doc dir lying around, nuke it */
165    (void)vsystem("rm -rf %s", DOC_TMP_DIR);
166
167    /* REALLY exit! */
168    if (RunningAsInit) {
169	/* Put the console back */
170	ioctl(0, VT_ACTIVATE, 2);
171#ifdef __alpha__
172	reboot(RB_HALT);
173#else
174	reboot(0);
175#endif
176    }
177    else
178	exit(status);
179}
180
181/* Run some general command */
182int
183systemExecute(char *command)
184{
185    int status;
186    struct termios foo;
187
188    dialog_update();
189    end_dialog();
190    DialogActive = FALSE;
191    if (tcgetattr(0, &foo) != -1) {
192	foo.c_cc[VERASE] = '\010';
193	tcsetattr(0, TCSANOW, &foo);
194    }
195    if (!Fake)
196	status = system(command);
197    else {
198	status = 0;
199	msgDebug("systemExecute:  Faked execution of `%s'\n", command);
200    }
201    DialogActive = TRUE;
202    return status;
203}
204
205/* Display a help file in a filebox */
206int
207systemDisplayHelp(char *file)
208{
209    char *fname = NULL;
210    char buf[FILENAME_MAX];
211    int ret = 0;
212
213    fname = systemHelpFile(file, buf);
214    if (!fname) {
215	snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file);
216	use_helpfile(NULL);
217	use_helpline(NULL);
218	dialog_mesgbox("Sorry!", buf, -1, -1);
219	ret = 1;
220    }
221    else {
222	use_helpfile(NULL);
223	use_helpline(NULL);
224	dialog_textbox(file, fname, LINES, COLS);
225    }
226    return ret;
227}
228
229char *
230systemHelpFile(char *file, char *buf)
231{
232    if (!file)
233	return NULL;
234
235    snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file);
236    if (file_readable(buf))
237	return expand(buf);
238    snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file);
239    if (file_readable(buf))
240	return expand(buf);
241    snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.hlp", file);
242    if (file_readable(buf))
243	return buf;
244    snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.TXT", file);
245    if (file_readable(buf))
246	return buf;
247    return NULL;
248}
249
250void
251systemChangeTerminal(char *color, const u_char c_term[],
252		     char *mono, const u_char m_term[])
253{
254    extern void init_acs(void);
255
256    if (OnVTY) {
257	if (ColorDisplay) {
258	    setenv("TERM", color, 1);
259	    setenv("TERMCAP", c_term, 1);
260	    reset_shell_mode();
261	    setterm(color);
262	    init_acs();
263	    cbreak(); noecho();
264	}
265	else {
266	    setenv("TERM", mono, 1);
267	    setenv("TERMCAP", m_term, 1);
268	    reset_shell_mode();
269	    setterm(mono);
270	    init_acs();
271	    cbreak(); noecho();
272	}
273    }
274    clear();
275    refresh();
276    dialog_clear();
277}
278
279int
280vsystem(char *fmt, ...)
281{
282    va_list args;
283    int pstat;
284    pid_t pid;
285    int omask;
286    sig_t intsave, quitsave;
287    char *cmd;
288    int i;
289
290    cmd = (char *)alloca(FILENAME_MAX);
291    cmd[0] = '\0';
292    va_start(args, fmt);
293    vsnprintf(cmd, FILENAME_MAX, fmt, args);
294    va_end(args);
295
296    omask = sigblock(sigmask(SIGCHLD));
297    if (Fake) {
298	msgDebug("vsystem:  Faked execution of `%s'\n", cmd);
299	return 0;
300    }
301    if (isDebug())
302	msgDebug("Executing command `%s'\n", cmd);
303    pid = fork();
304    if (pid == -1) {
305	(void)sigsetmask(omask);
306	i = 127;
307    }
308    else if (!pid) {	/* Junior */
309	(void)sigsetmask(omask);
310	if (DebugFD != -1) {
311	    dup2(DebugFD, 0);
312	    dup2(DebugFD, 1);
313	    dup2(DebugFD, 2);
314	}
315	else {
316	    close(1); open("/dev/null", O_WRONLY);
317	    dup2(1, 2);
318	}
319	if (!RunningAsInit)
320	    execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
321	else
322	    execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL);
323	exit(1);
324    }
325    else {
326	intsave = signal(SIGINT, SIG_IGN);
327	quitsave = signal(SIGQUIT, SIG_IGN);
328	pid = waitpid(pid, &pstat, 0);
329	(void)sigsetmask(omask);
330	(void)signal(SIGINT, intsave);
331	(void)signal(SIGQUIT, quitsave);
332	i = (pid == -1) ? -1 : WEXITSTATUS(pstat);
333	if (isDebug())
334	    msgDebug("Command `%s' returns status of %d\n", cmd, i);
335    }
336    return i;
337}
338
339void
340systemCreateHoloshell(void)
341{
342    if (OnVTY && RunningAsInit) {
343
344	if (ehs_pid != 0) {
345	    int pstat;
346
347	    if (kill(ehs_pid, 0) == 0) {
348
349		if (msgYesNo("There seems to be an emergency holographic shell\n"
350			     "already running von VTY 4.\n"
351			     "Kill it and start a new one?"))
352		    return;
353
354		/* try cleaning up as much as possible */
355		(void) kill(ehs_pid, SIGHUP);
356		sleep(1);
357		(void) kill(ehs_pid, SIGKILL);
358	    }
359
360	    /* avoid too many zombies */
361	    (void) waitpid(ehs_pid, &pstat, WNOHANG);
362	}
363
364	if ((ehs_pid = fork()) == 0) {
365	    int i, fd;
366	    struct termios foo;
367	    extern int login_tty(int);
368
369	    ioctl(0, TIOCNOTTY, NULL);
370	    for (i = getdtablesize(); i >= 0; --i)
371		close(i);
372	    fd = open("/dev/ttyv3", O_RDWR);
373	    ioctl(0, TIOCSCTTY, &fd);
374	    dup2(0, 1);
375	    dup2(0, 2);
376	    DebugFD = 2;
377	    if (login_tty(fd) == -1)
378		msgDebug("Doctor: I can't set the controlling terminal.\n");
379	    signal(SIGTTOU, SIG_IGN);
380	    if (tcgetattr(fd, &foo) != -1) {
381		foo.c_cc[VERASE] = '\010';
382		if (tcsetattr(fd, TCSANOW, &foo) == -1)
383		    msgDebug("Doctor: I'm unable to set the erase character.\n");
384	    }
385	    else
386		msgDebug("Doctor: I'm unable to get the terminal attributes!\n");
387	    execlp("sh", "-sh", 0);
388	    msgDebug("Was unable to execute sh for Holographic shell!\n");
389	    exit(1);
390	}
391	else {
392	    msgNotify("Starting an emergency holographic shell on VTY4");
393	    sleep(2);
394	}
395    }
396}
397