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