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