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