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