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