]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sade/system.c
This commit was generated by cvs2svn to compensate for changes in r102550,
[FreeBSD/FreeBSD.git] / usr.sbin / sade / system.c
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  * $FreeBSD$
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 <termios.h>
22 #include <sys/reboot.h>
23 #include <sys/consio.h>
24 #include <sys/fcntl.h>
25 #include <sys/ioctl.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
29
30
31 /* Where we stick our temporary expanded doc file */
32 #define DOC_TMP_DIR     "/tmp/.doc"
33 #define DOC_TMP_FILE    "/tmp/.doc/doc.tmp"
34
35 static pid_t ehs_pid;
36
37 /*
38  * Handle interrupt signals - this probably won't work in all cases
39  * due to our having bogotified the internal state of dialog or curses,
40  * but we'll give it a try.
41  */
42 static int
43 intr_continue(dialogMenuItem *self)
44 {
45     return DITEM_LEAVE_MENU;
46 }
47
48 static int
49 intr_reboot(dialogMenuItem *self)
50 {
51     systemShutdown(-1);
52     /* NOTREACHED */
53     return 0;
54 }
55
56 static int
57 intr_restart(dialogMenuItem *self)
58 {
59     int ret, fd, fdmax;
60
61     mediaClose();
62     free_variables();
63     fdmax = getdtablesize();
64     for (fd = 3; fd < fdmax; fd++)
65         close(fd);
66     ret = execl(StartName, StartName, "-restart", (char *)NULL);
67     msgDebug("execl failed (%s)\n", strerror(errno));
68     /* NOTREACHED */
69     return -1;
70 }
71
72 static dialogMenuItem intrmenu[] = {
73     { "Abort",   "Abort the installation", NULL, intr_reboot },
74     { "Restart", "Restart the installation program", NULL, intr_restart },
75     { "Continue", "Continue the installation", NULL, intr_continue },
76 };
77
78
79 static void
80 handle_intr(int sig)
81 {
82     WINDOW *save = savescr();
83
84     use_helpline(NULL);
85     use_helpfile(NULL);
86     if (OnVTY) {
87         ioctl(0, VT_ACTIVATE, 1);       /* Switch back */
88         msgInfo(NULL);
89     }
90     (void)dialog_menu("Installation interrupt",
91                      "Do you want to abort the installation?",
92                      -1, -1, 3, -3, intrmenu, NULL, NULL, NULL);
93     restorescr(save);
94 }
95
96 /*
97  * Harvest children if we are init.
98  */
99 static void
100 reap_children(int sig)
101 {
102     int errbak = errno;
103
104     while (waitpid(-1, NULL, WNOHANG) > 0)
105         ;
106     errno = errbak;
107 }
108
109 /* Expand a file into a convenient location, nuking it each time */
110 static char *
111 expand(char *fname)
112 {
113     char *gunzip = RunningAsInit ? "/stand/gunzip" : "/usr/bin/gunzip";
114
115     if (!directory_exists(DOC_TMP_DIR)) {
116         Mkdir(DOC_TMP_DIR);
117         if (chown(DOC_TMP_DIR, 0, 0) < 0)
118             return NULL;
119         if (chmod(DOC_TMP_DIR, S_IRWXU) < 0)
120             return NULL;
121     }
122     else
123         unlink(DOC_TMP_FILE);
124     if (!file_readable(fname) || vsystem("%s < %s > %s", gunzip, fname, DOC_TMP_FILE))
125         return NULL;
126     return DOC_TMP_FILE;
127 }
128
129 /* Initialize system defaults */
130 void
131 systemInitialize(int argc, char **argv)
132 {
133     size_t i;
134     int boothowto;
135     sigset_t signalset;
136
137     signal(SIGINT, SIG_IGN);
138     globalsInit();
139
140     i = sizeof(boothowto);
141     if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, NULL) &&
142         (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE))
143         variable_set2(VAR_DEBUG, "YES", 0);
144
145     /* Are we running as init? */
146     if (getpid() == 1) {
147         int fd;
148
149         RunningAsInit = 1;
150         setsid();
151         close(0);
152         fd = open("/dev/ttyv0", O_RDWR);
153         if (fd == -1) {
154             fd = open("/dev/console", O_RDWR);  /* fallback */
155             variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */
156         } else
157             OnVTY = TRUE;
158         /*
159          * To make _sure_ we're on a VTY and don't have /dev/console switched
160          * away to a serial port or something, attempt to set the cursor appearance.
161          */
162         if (OnVTY) {
163             int fd2, type;
164
165             type = 0;   /* normal */
166             if ((fd2 = open("/dev/console", O_RDWR)) != -1) {
167                 if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) {
168                     OnVTY = FALSE;
169                     variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit
170                                                                   the console
171                                                                   type */
172                     close(fd); close(fd2);
173                     open("/dev/console", O_RDWR);
174                 }
175                 else
176                     close(fd2);
177             }
178         }
179         close(1); dup(0);
180         close(2); dup(0);
181         printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console");
182         ioctl(0, TIOCSCTTY, (char *)NULL);
183         setlogin("root");
184         setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1);
185         setbuf(stdin, 0);
186         setbuf(stderr, 0);
187 #ifdef __alpha__
188         i = 0;
189         sysctlbyname("machdep.unaligned_print", NULL, 0, &i, sizeof(i));
190 #endif
191 #if 0
192         signal(SIGCHLD, reap_children);
193 #endif
194     }
195     else {
196         char hname[256];
197
198         /* Initalize various things for a multi-user environment */
199         if (!gethostname(hname, sizeof hname))
200             variable_set2(VAR_HOSTNAME, hname, 0);
201     }
202
203     if (set_termcap() == -1) {
204         printf("Can't find terminal entry\n");
205         exit(-1);
206     }
207
208     /* XXX - libdialog has particularly bad return value checking */
209     init_dialog();
210
211     /* If we haven't crashed I guess dialog is running ! */
212     DialogActive = TRUE;
213
214     /* Make sure HOME is set for those utilities that need it */
215     if (!getenv("HOME"))
216         setenv("HOME", "/", 1);
217     signal(SIGINT, handle_intr);
218     /*
219      * Make sure we can be interrupted even if we were re-executed
220      * from an interrupt.
221      */
222     sigemptyset(&signalset);
223     sigaddset(&signalset, SIGINT);
224     sigprocmask(SIG_UNBLOCK, &signalset, NULL);
225
226     (void)vsystem("rm -rf %s", DOC_TMP_DIR);
227 }
228
229 /* Close down and prepare to exit */
230 void
231 systemShutdown(int status)
232 {
233     /* If some media is open, close it down */
234     if (status >=0)
235         mediaClose();
236
237     /* write out any changes to rc.conf .. */
238     configRC_conf();
239
240     /* Shut down the dialog library */
241     if (DialogActive) {
242         end_dialog();
243         DialogActive = FALSE;
244     }
245
246     /* Shut down curses */
247     endwin();
248
249     /* If we have a temporary doc dir lying around, nuke it */
250     (void)vsystem("rm -rf %s", DOC_TMP_DIR);
251
252     /* REALLY exit! */
253     if (RunningAsInit) {
254         /* Put the console back */
255         ioctl(0, VT_ACTIVATE, 2);
256 #ifdef __alpha__
257         reboot(RB_HALT);
258 #else
259         reboot(0);
260 #endif
261     }
262     else
263         exit(status);
264 }
265
266 /* Run some general command */
267 int
268 systemExecute(char *command)
269 {
270     int status;
271     struct termios foo;
272     WINDOW *w = savescr();
273
274     dialog_clear();
275     dialog_update();
276     end_dialog();
277     DialogActive = FALSE;
278     if (tcgetattr(0, &foo) != -1) {
279         foo.c_cc[VERASE] = '\010';
280         tcsetattr(0, TCSANOW, &foo);
281     }
282     if (!Fake)
283         status = system(command);
284     else {
285         status = 0;
286         msgDebug("systemExecute:  Faked execution of `%s'\n", command);
287     }
288     DialogActive = TRUE;
289     restorescr(w);
290     return status;
291 }
292
293 /* suspend/resume libdialog/curses screen */
294 static    WINDOW *oldW;
295
296 void
297 systemSuspendDialog(void)
298 {
299
300     oldW  = savescr();
301     dialog_clear();
302     dialog_update();
303     end_dialog();
304     DialogActive = FALSE;
305 }
306
307 void
308 systemResumeDialog(void)
309 {
310
311     DialogActive = TRUE;
312     restorescr(oldW);
313 }
314
315 /* Display a help file in a filebox */
316 int
317 systemDisplayHelp(char *file)
318 {
319     char *fname = NULL;
320     char buf[FILENAME_MAX];
321     int ret = 0;
322     WINDOW *w = savescr();
323     
324     fname = systemHelpFile(file, buf);
325     if (!fname) {
326         snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file);
327         use_helpfile(NULL);
328         use_helpline(NULL);
329         dialog_mesgbox("Sorry!", buf, -1, -1);
330         ret = 1;
331     }
332     else {
333         use_helpfile(NULL);
334         use_helpline(NULL);
335         dialog_textbox(file, fname, LINES, COLS);
336     }
337     restorescr(w);
338     return ret;
339 }
340
341 char *
342 systemHelpFile(char *file, char *buf)
343 {
344     if (!file)
345         return NULL;
346     if (file[0] == '/')
347         return file;
348     snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file);
349     if (file_readable(buf)) 
350         return expand(buf);
351     snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp", file);
352     if (file_readable(buf)) 
353         return expand(buf);
354     snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file);
355     if (file_readable(buf)) 
356         return expand(buf);
357     snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT", file);
358     if (file_readable(buf)) 
359         return expand(buf);
360     snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/sysinstall/help/%s.hlp", file);
361     if (file_readable(buf))
362         return buf;
363     snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/sysinstall/help/%s.TXT", file);
364     if (file_readable(buf))
365         return buf;
366     return NULL;
367 }
368
369 void
370 systemChangeTerminal(char *color, const u_char c_term[],
371                      char *mono, const u_char m_term[])
372 {
373     if (OnVTY) {
374         int setupterm(char *color, int, int *);
375
376         if (ColorDisplay) {
377             setenv("TERM", color, 1);
378             setenv("TERMCAP", c_term, 1);
379             reset_shell_mode();
380             setterm(color);
381             cbreak(); noecho();
382         }
383         else {
384             setenv("TERM", mono, 1);
385             setenv("TERMCAP", m_term, 1);
386             reset_shell_mode();
387             setterm(mono);
388             cbreak(); noecho();
389         }
390     }
391     clear();
392     refresh();
393     dialog_clear();
394 }
395
396 int
397 vsystem(char *fmt, ...)
398 {
399     va_list args;
400     int pstat;
401     pid_t pid;
402     int omask;
403     sig_t intsave, quitsave;
404     char *cmd;
405     int i;
406
407     cmd = (char *)alloca(FILENAME_MAX);
408     cmd[0] = '\0';
409     va_start(args, fmt);
410     vsnprintf(cmd, FILENAME_MAX, fmt, args);
411     va_end(args);
412
413     omask = sigblock(sigmask(SIGCHLD));
414     if (Fake) {
415         msgDebug("vsystem:  Faked execution of `%s'\n", cmd);
416         return 0;
417     }
418     if (isDebug())
419         msgDebug("Executing command `%s'\n", cmd);
420     pid = fork();
421     if (pid == -1) {
422         (void)sigsetmask(omask);
423         i = 127;
424     }
425     else if (!pid) {    /* Junior */
426         (void)sigsetmask(omask);
427         if (DebugFD != -1) {
428             dup2(DebugFD, 0);
429             dup2(DebugFD, 1);
430             dup2(DebugFD, 2);
431         }
432         else {
433             close(1); open("/dev/null", O_WRONLY);
434             dup2(1, 2);
435         }
436         if (!RunningAsInit)
437             execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
438         else
439             execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL);
440         exit(1);
441     }
442     else {
443         intsave = signal(SIGINT, SIG_IGN);
444         quitsave = signal(SIGQUIT, SIG_IGN);
445         pid = waitpid(pid, &pstat, 0);
446         (void)sigsetmask(omask);
447         (void)signal(SIGINT, intsave);
448         (void)signal(SIGQUIT, quitsave);
449         i = (pid == -1) ? -1 : WEXITSTATUS(pstat);
450         if (isDebug())
451             msgDebug("Command `%s' returns status of %d\n", cmd, i);
452     }
453     return i;
454 }
455
456 void
457 systemCreateHoloshell(void)
458 {
459     int waitstatus;
460
461     if ((FixItMode || OnVTY) && RunningAsInit) {
462
463         if (ehs_pid != 0) {
464             int pstat;
465
466             if (kill(ehs_pid, 0) == 0) {
467
468                 if (msgNoYes("There seems to be an emergency holographic shell\n"
469                              "already running on VTY 4.\n\n"
470                              "Kill it and start a new one?"))
471                     return;
472
473                 /* try cleaning up as much as possible */
474                 (void) kill(ehs_pid, SIGHUP);
475                 sleep(1);
476                 (void) kill(ehs_pid, SIGKILL);
477             }
478
479             /* avoid too many zombies */
480             (void) waitpid(ehs_pid, &pstat, WNOHANG);
481         }
482
483         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
484             systemSuspendDialog();      /* must be before the fork() */
485         if ((ehs_pid = fork()) == 0) {
486             int i, fd;
487             struct termios foo;
488             extern int login_tty(int);
489             
490             ioctl(0, TIOCNOTTY, NULL);
491             for (i = getdtablesize(); i >= 0; --i)
492                 close(i);
493             if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
494                 fd = open("/dev/console", O_RDWR);
495             else
496                 fd = open("/dev/ttyv3", O_RDWR);
497             ioctl(0, TIOCSCTTY, &fd);
498             dup2(0, 1);
499             dup2(0, 2);
500             DebugFD = 2;
501             if (login_tty(fd) == -1)
502                 msgDebug("Doctor: I can't set the controlling terminal.\n");
503             signal(SIGTTOU, SIG_IGN);
504             if (tcgetattr(fd, &foo) != -1) {
505                 foo.c_cc[VERASE] = '\010';
506                 if (tcsetattr(fd, TCSANOW, &foo) == -1)
507                     msgDebug("Doctor: I'm unable to set the erase character.\n");
508             }
509             else
510                 msgDebug("Doctor: I'm unable to get the terminal attributes!\n");
511             if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) {
512                 printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n");
513                 fflush(stdout);
514             }
515             execlp("sh", "-sh", 0);
516             msgDebug("Was unable to execute sh for Holographic shell!\n");
517             exit(1);
518         }
519         else {
520             if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) {
521                 WINDOW *w = savescr();
522
523                 msgNotify("Starting an emergency holographic shell on VTY4");
524                 sleep(2);
525                 restorescr(w);
526             }
527             else {
528                 (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for
529                                                            shell to finish 
530                                                            it serial mode
531                                                            since there is no
532                                                            virtual console */
533                 systemResumeDialog();
534             }
535         }
536     }
537 }