1 /* $NetBSD: main.c,v 1.27 2021/01/31 22:45:46 rillig Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 18 * or promote products derived from this software without specific prior 19 * written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 /* main sysinst program. */ 36 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/syslimits.h> 40 #include <sys/uio.h> 41 #include <stdio.h> 42 #include <signal.h> 43 #include <curses.h> 44 #include <unistd.h> 45 #include <fcntl.h> 46 #include <dirent.h> 47 #include <locale.h> 48 49 #include "defs.h" 50 #include "md.h" 51 #include "msg_defs.h" 52 #include "menu_defs.h" 53 #include "txtwalk.h" 54 55 int debug; 56 char machine[SSTRSIZE]; 57 int ignorerror; 58 int ttysig_ignore; 59 pid_t ttysig_forward; 60 uint sizemult; 61 int partman_go; 62 FILE *logfp; 63 FILE *script; 64 daddr_t root_limit; 65 struct pm_head_t pm_head; 66 struct pm_devs *pm; 67 struct pm_devs *pm_new; 68 char xfer_dir[STRSIZE]; 69 int clean_xfer_dir; 70 char ext_dir_bin[STRSIZE]; 71 char ext_dir_src[STRSIZE]; 72 char ext_dir_pkgsrc[STRSIZE]; 73 char set_dir_bin[STRSIZE]; 74 char set_dir_src[STRSIZE]; 75 char pkg_dir[STRSIZE]; 76 char pkgsrc_dir[STRSIZE]; 77 const char *ushell; 78 struct ftpinfo ftp, pkg, pkgsrc; 79 int (*fetch_fn)(const char *); 80 char nfs_host[STRSIZE]; 81 char nfs_dir[STRSIZE]; 82 char cdrom_dev[SSTRSIZE]; 83 char fd_dev[SSTRSIZE]; 84 const char *fd_type; 85 char localfs_dev[SSTRSIZE]; 86 char localfs_fs[SSTRSIZE]; 87 char localfs_dir[STRSIZE]; 88 char targetroot_mnt[SSTRSIZE]; 89 int mnt2_mounted; 90 char dist_postfix[SSTRSIZE]; 91 char dist_tgz_postfix[SSTRSIZE]; 92 WINDOW *mainwin; 93 94 static void select_language(void); 95 __dead static void usage(void); 96 __dead static void miscsighandler(int); 97 static void ttysighandler(int); 98 static void cleanup(void); 99 static void process_f_flag(char *); 100 101 static int exit_cleanly = 0; /* Did we finish nicely? */ 102 FILE *logfp; /* log file */ 103 FILE *script; /* script file */ 104 105 const char *multname; 106 const char *err_outofmem; 107 108 #ifdef DEBUG 109 extern int log_flip(void); 110 #endif 111 112 /* Definion for colors */ 113 114 struct { 115 unsigned int bg; 116 unsigned int fg; 117 } clr_arg; 118 119 /* String defaults and stuff for processing the -f file argument. */ 120 121 struct f_arg { 122 const char *name; 123 const char *dflt; 124 char *var; 125 int size; 126 }; 127 128 static const struct f_arg fflagopts[] = { 129 {"release", REL, NULL, 0}, 130 {"machine", MACH, machine, sizeof machine}, 131 {"xfer dir", "/usr/INSTALL", xfer_dir, sizeof xfer_dir}, 132 {"ext dir", "", ext_dir_bin, sizeof ext_dir_bin}, 133 {"ext src dir", "", ext_dir_src, sizeof ext_dir_src}, 134 {"ftp host", SYSINST_FTP_HOST, ftp.xfer_host[XFER_FTP], sizeof ftp.xfer_host[XFER_FTP]}, 135 {"http host", SYSINST_HTTP_HOST, ftp.xfer_host[XFER_HTTP], sizeof ftp.xfer_host[XFER_HTTP]}, 136 {"ftp dir", SYSINST_FTP_DIR, ftp.dir, sizeof ftp.dir}, 137 {"ftp prefix", "/" ARCH_SUBDIR "/binary/sets", set_dir_bin, sizeof set_dir_bin}, 138 {"ftp src prefix", "/source/sets", set_dir_src, sizeof set_dir_src}, 139 {"ftp user", "ftp", ftp.user, sizeof ftp.user}, 140 {"ftp pass", "", ftp.pass, sizeof ftp.pass}, 141 {"ftp proxy", "", ftp.proxy, sizeof ftp.proxy}, 142 {"nfs host", "", nfs_host, sizeof nfs_host}, 143 {"nfs dir", "/bsd/release", nfs_dir, sizeof nfs_dir}, 144 {"cd dev", 0, cdrom_dev, sizeof cdrom_dev}, /* default filled in init */ 145 {"fd dev", "/dev/fd0a", fd_dev, sizeof fd_dev}, 146 {"local dev", "", localfs_dev, sizeof localfs_dev}, 147 {"local fs", "ffs", localfs_fs, sizeof localfs_fs}, 148 {"local dir", "release", localfs_dir, sizeof localfs_dir}, 149 {"targetroot mount", "/targetroot", targetroot_mnt, sizeof targetroot_mnt}, 150 {"dist postfix", "." SETS_TAR_SUFF, dist_postfix, sizeof dist_postfix}, 151 {"dist tgz postfix", ".tgz", dist_tgz_postfix, sizeof dist_tgz_postfix}, 152 {"pkg host", SYSINST_PKG_HOST, pkg.xfer_host[XFER_FTP], sizeof pkg.xfer_host[XFER_FTP]}, 153 {"pkg http host", SYSINST_PKG_HTTP_HOST, pkg.xfer_host[XFER_HTTP], sizeof pkg.xfer_host[XFER_HTTP]}, 154 {"pkg dir", SYSINST_PKG_DIR, pkg.dir, sizeof pkg.dir}, 155 {"pkg prefix", "/" PKG_ARCH_SUBDIR "/" PKG_SUBDIR "/All", pkg_dir, sizeof pkg_dir}, 156 {"pkg user", "ftp", pkg.user, sizeof pkg.user}, 157 {"pkg pass", "", pkg.pass, sizeof pkg.pass}, 158 {"pkg proxy", "", pkg.proxy, sizeof pkg.proxy}, 159 {"pkgsrc host", SYSINST_PKGSRC_HOST, pkgsrc.xfer_host[XFER_FTP], sizeof pkgsrc.xfer_host[XFER_FTP]}, 160 {"pkgsrc http host", SYSINST_PKGSRC_HTTP_HOST, pkgsrc.xfer_host[XFER_HTTP], sizeof pkgsrc.xfer_host[XFER_HTTP]}, 161 {"pkgsrc dir", "", pkgsrc.dir, sizeof pkgsrc.dir}, 162 {"pkgsrc prefix", "pub/pkgsrc/stable", pkgsrc_dir, sizeof pkgsrc_dir}, 163 {"pkgsrc user", "ftp", pkgsrc.user, sizeof pkgsrc.user}, 164 {"pkgsrc pass", "", pkgsrc.pass, sizeof pkgsrc.pass}, 165 {"pkgsrc proxy", "", pkgsrc.proxy, sizeof pkgsrc.proxy}, 166 167 {NULL, NULL, NULL, 0} 168 }; 169 170 static void 171 init(void) 172 { 173 const struct f_arg *arg; 174 175 sizemult = 1; 176 clean_xfer_dir = 0; 177 mnt2_mounted = 0; 178 fd_type = "msdos"; 179 180 pm_head = (struct pm_head_t) SLIST_HEAD_INITIALIZER(pm_head); 181 SLIST_INIT(&pm_head); 182 pm_new = malloc(sizeof (struct pm_devs)); 183 memset(pm_new, 0, sizeof *pm_new); 184 185 for (arg = fflagopts; arg->name != NULL; arg++) { 186 if (arg->var == NULL) 187 continue; 188 if (arg->var == cdrom_dev) 189 get_default_cdrom(arg->var, arg->size); 190 else 191 strlcpy(arg->var, arg->dflt, arg->size); 192 } 193 pkg.xfer = pkgsrc.xfer = XFER_HTTP; 194 195 clr_arg.bg=COLOR_BLUE; 196 clr_arg.fg=COLOR_WHITE; 197 } 198 199 static void 200 init_lang(void) 201 { 202 sizemult = 1; 203 err_outofmem = msg_string(MSG_out_of_memory); 204 multname = msg_string(MSG_secname); 205 } 206 207 int 208 main(int argc, char **argv) 209 { 210 int ch; 211 212 init(); 213 214 #ifdef DEBUG 215 log_flip(); 216 #endif 217 218 /* Check for TERM ... */ 219 if (!getenv("TERM")) { 220 (void)fprintf(stderr, 221 "sysinst: environment variable TERM not set.\n"); 222 exit(4); 223 } 224 225 /* argv processing */ 226 while ((ch = getopt(argc, argv, "Dr:f:C:" 227 #ifndef NO_PARTMAN 228 "p" 229 #endif 230 )) != -1) 231 switch(ch) { 232 case 'D': /* set to get past certain errors in testing */ 233 debug = 1; 234 break; 235 case 'r': 236 /* Release name - ignore for compatibility with older versions */ 237 break; 238 case 'f': 239 /* Definition file to read. */ 240 process_f_flag(optarg); 241 break; 242 case 'C': 243 /* Define colors */ 244 sscanf(optarg, "%u:%u", &clr_arg.bg, &clr_arg.fg); 245 break; 246 #ifndef NO_PARTMAN 247 case 'p': 248 /* Partition tool */ 249 partman_go = 1; 250 break; 251 #endif 252 case '?': 253 default: 254 usage(); 255 } 256 257 md_init(); 258 259 /* Initialize the partitioning subsystem */ 260 partitions_init(); 261 262 /* initialize message window */ 263 if (menu_init()) { 264 __menu_initerror(); 265 exit(4); 266 } 267 268 /* 269 * Put 'messages' in a window that has a one-character border 270 * on the real screen. 271 */ 272 mainwin = newwin(getmaxy(stdscr) - 2, getmaxx(stdscr) - 2, 1, 1); 273 if (mainwin == NULL) { 274 (void)fprintf(stderr, 275 "sysinst: screen too small\n"); 276 exit(1); 277 } 278 if (has_colors()) { 279 start_color(); 280 do_coloring(clr_arg.fg,clr_arg.bg); 281 } else { 282 remove_color_options(); 283 } 284 msg_window(mainwin); 285 286 /* Watch for signals and clean up */ 287 (void)atexit(cleanup); 288 (void)signal(SIGINT, ttysighandler); 289 (void)signal(SIGQUIT, ttysighandler); 290 (void)signal(SIGHUP, miscsighandler); 291 292 /* redraw screen */ 293 touchwin(stdscr); 294 refresh(); 295 296 /* Ensure we have mountpoint for target filesystems */ 297 mkdir(targetroot_mnt, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); 298 299 select_language(); 300 get_kb_encoding(); 301 init_lang(); 302 303 /* Menu processing */ 304 if (partman_go) 305 partman(); 306 else 307 process_menu(MENU_netbsd, NULL); 308 309 #ifndef NO_PARTMAN 310 /* clean up internal storage */ 311 pm_destroy_all(); 312 #endif 313 314 partitions_cleanup(); 315 316 exit_cleanly = 1; 317 return 0; 318 } 319 320 static int 321 set_language(menudesc *m, void *arg) 322 { 323 char **fnames = arg; 324 325 msg_file(fnames[m->cursel]); 326 return 1; 327 } 328 329 static void 330 select_language(void) 331 { 332 DIR *dir; 333 struct dirent *dirent; 334 char **lang_msg, **fnames; 335 char prefix[PATH_MAX], fname[PATH_MAX]; 336 int max_lang = 16, num_lang = 0; 337 const char *cp; 338 menu_ent *opt = 0; 339 int lang_menu = -1; 340 int lang; 341 342 #ifdef CATALOG_DIR 343 strcpy(prefix, CATALOG_DIR "/"); 344 dir = opendir(CATALOG_DIR); 345 if (!dir) { 346 strcpy(prefix, "./"); 347 dir = opendir("."); 348 } 349 #else 350 dir = opendir("."); 351 strcpy(prefix, "./"); 352 #endif 353 if (!dir) 354 return; 355 356 lang_msg = malloc(max_lang * sizeof *lang_msg); 357 fnames = malloc(max_lang * sizeof *fnames); 358 if (!lang_msg || !fnames) 359 goto done; 360 361 lang_msg[0] = strdup(msg_string(MSG_sysinst_message_language)); 362 fnames[0] = 0; 363 num_lang = 1; 364 365 while ((dirent = readdir(dir)) != 0) { 366 if (memcmp(dirent->d_name, "sysinstmsgs.", 12)) 367 continue; 368 strcpy(fname, prefix); 369 strcat(fname, dirent->d_name); 370 if (msg_file(fname)) 371 continue; 372 cp = msg_string(MSG_sysinst_message_language); 373 if (!strcmp(cp, lang_msg[0])) 374 continue; 375 if (num_lang == max_lang) { 376 char **new; 377 max_lang *= 2; 378 new = realloc(lang_msg, max_lang * sizeof *lang_msg); 379 if (!new) 380 break; 381 lang_msg = new; 382 new = realloc(fnames, max_lang * sizeof *fnames); 383 if (!new) 384 break; 385 fnames = new; 386 } 387 fnames[num_lang] = strdup(fname); 388 lang_msg[num_lang++] = strdup(cp); 389 } 390 msg_file(0); 391 closedir(dir); 392 dir = 0; 393 394 if (num_lang == 1) 395 goto done; 396 397 opt = calloc(num_lang, sizeof *opt); 398 if (!opt) 399 goto done; 400 401 for (lang = 0; lang < num_lang; lang++) { 402 opt[lang].opt_name = lang_msg[lang]; 403 opt[lang].opt_action = set_language; 404 } 405 406 lang_menu = new_menu(NULL, opt, num_lang, -1, 12, 0, 0, MC_NOEXITOPT, 407 NULL, NULL, NULL, NULL, NULL); 408 409 if (lang_menu != -1) { 410 msg_display(MSG_hello); 411 process_menu(lang_menu, fnames); 412 } 413 414 done: 415 if (dir) 416 closedir(dir); 417 if (lang_menu != -1) 418 free_menu(lang_menu); 419 free(opt); 420 while (num_lang) { 421 free(lang_msg[--num_lang]); 422 free(fnames[num_lang]); 423 } 424 free(lang_msg); 425 free(fnames); 426 427 /* set locale according to selected language */ 428 cp = msg_string(MSG_sysinst_message_locale); 429 if (cp) { 430 setlocale(LC_CTYPE, cp); 431 setenv("LC_CTYPE", cp, 1); 432 } 433 } 434 435 #ifndef md_may_remove_boot_medium 436 #define md_may_remove_boot_medium() (boot_media_still_needed()<=0) 437 #endif 438 439 /* toplevel menu handler ... */ 440 void 441 toplevel(void) 442 { 443 /* 444 * Undo any stateful side-effects of previous menu choices. 445 * XXX must be idempotent, since we get run each time the main 446 * menu is displayed. 447 */ 448 char *home = getenv("HOME"); 449 if (home != NULL) 450 if (chdir(home) != 0) 451 (void)chdir("/"); 452 unwind_mounts(); 453 clear_swap(); 454 455 /* Display banner message in (english, francais, deutsch..) */ 456 msg_display(MSG_hello); 457 msg_display_add(MSG_md_hello); 458 if (md_may_remove_boot_medium()) 459 msg_display_add(MSG_md_may_remove_boot_medium); 460 msg_display_add(MSG_thanks); 461 } 462 463 464 /* The usage ... */ 465 466 static void 467 usage(void) 468 { 469 470 (void)fprintf(stderr, "usage: sysinst [-D] [-f definition_file] " 471 "[-r release] [-C bg:fg]" 472 #ifndef NO_PARTMAN 473 " [-p]" 474 #endif 475 "\n" 476 "where:\n" 477 "\t-D\n\t\trun in debug mode\n" 478 "\t-f definition_file\n\t\toverride built-in defaults from file\n" 479 "\t-r release\n\t\toverride release name\n" 480 "\t-C bg:fg\n\t\tuse different color scheme\n" 481 #ifndef NO_PARTMAN 482 "\t-p\n\t\tonly run the partition editor, no installation\n" 483 #endif 484 ); 485 486 exit(1); 487 } 488 489 /* ARGSUSED */ 490 static void 491 miscsighandler(int signo) 492 { 493 494 /* 495 * we need to cleanup(), but it was already scheduled with atexit(), 496 * so it'll be invoked on exit(). 497 */ 498 exit(1); 499 } 500 501 static void 502 ttysighandler(int signo) 503 { 504 505 /* 506 * if we want to ignore a TTY signal (SIGINT or SIGQUIT), then we 507 * just return. If we want to forward a TTY signal, we forward it 508 * to the specified process group. 509 * 510 * This functionality is used when setting up and displaying child 511 * output so that the child gets the signal and presumably dies, 512 * but sysinst continues. We use this rather than actually ignoring 513 * the signals, because that will be passed on to a child 514 * through fork/exec, whereas special handlers get reset on exec.. 515 */ 516 if (ttysig_ignore) 517 return; 518 if (ttysig_forward) { 519 killpg(ttysig_forward, signo); 520 return; 521 } 522 523 /* 524 * we need to cleanup(), but it was already scheduled with atexit(), 525 * so it'll be invoked on exit(). 526 */ 527 exit(1); 528 } 529 530 static void 531 cleanup(void) 532 { 533 time_t tloc; 534 535 (void)time(&tloc); 536 537 #if 0 538 restore_etc(); 539 #endif 540 /* Ensure we aren't inside the target tree */ 541 chdir(getenv("HOME")); 542 unwind_mounts(); 543 umount_mnt2(); 544 clear_swap(); 545 546 endwin(); 547 548 if (logfp) { 549 fprintf(logfp, "Log ended at: %s\n", safectime(&tloc)); 550 fflush(logfp); 551 fclose(logfp); 552 logfp = NULL; 553 } 554 if (script) { 555 fprintf(script, "# Script ended at: %s\n", safectime(&tloc)); 556 fflush(script); 557 fclose(script); 558 script = NULL; 559 } 560 561 if (!exit_cleanly) 562 fprintf(stderr, "\n\nsysinst terminated.\n"); 563 } 564 565 566 /* process function ... */ 567 568 void 569 process_f_flag(char *f_name) 570 { 571 char buffer[STRSIZE]; 572 int len; 573 const struct f_arg *arg; 574 FILE *fp; 575 char *cp, *cp1, *err; 576 577 /* open the file */ 578 fp = fopen(f_name, "r"); 579 if (fp == NULL) { 580 const char *args[] = { f_name }; 581 err = str_arg_subst(msg_string(MSG_config_open_error), 582 __arraycount(args), args); 583 fprintf(stderr, "%s\n", err); 584 free(err); 585 exit(1); 586 } 587 588 while (fgets(buffer, sizeof buffer, fp) != NULL) { 589 cp = buffer + strspn(buffer, " \t"); 590 if (strchr("#\r\n", *cp) != NULL) 591 continue; 592 for (arg = fflagopts; arg->name != NULL; arg++) { 593 len = strlen(arg->name); 594 if (memcmp(cp, arg->name, len) != 0) 595 continue; 596 if (arg->var == NULL || arg->size == 0) 597 continue; 598 cp1 = cp + len; 599 cp1 += strspn(cp1, " \t"); 600 if (*cp1++ != '=') 601 continue; 602 cp1 += strspn(cp1, " \t"); 603 len = strcspn(cp1, " \n\r\t"); 604 cp1[len] = 0; 605 strlcpy(arg->var, cp1, arg->size); 606 break; 607 } 608 } 609 610 fclose(fp); 611 } 612