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