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