system.c revision 70005
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 70005 2000-12-14 02:49:02Z jkh $ 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, 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/* Expand a file into a convenient location, nuking it each time */ 89static char * 90expand(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 */ 109void 110systemInitialize(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 */ 205void 206systemShutdown(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 */ 242int 243systemExecute(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 */ 269static WINDOW *oldW; 270 271void 272systemSuspendDialog(void) 273{ 274 275 oldW = savescr(); 276 dialog_clear(); 277 dialog_update(); 278 end_dialog(); 279 DialogActive = FALSE; 280} 281 282void 283systemResumeDialog(void) 284{ 285 286 DialogActive = TRUE; 287 restorescr(oldW); 288} 289 290/* Display a help file in a filebox */ 291int 292systemDisplayHelp(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 316char * 317systemHelpFile(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/release/sysinstall/help/%s.hlp", file); 330 if (file_readable(buf)) 331 return buf; 332 snprintf(buf, FILENAME_MAX, "/usr/src/release/sysinstall/help/%s.TXT", file); 333 if (file_readable(buf)) 334 return buf; 335 return NULL; 336} 337 338void 339systemChangeTerminal(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 365int 366vsystem(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 425void 426systemCreateHoloshell(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} 507