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