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