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