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