1 /* $NetBSD: main.c,v 1.39 2026/06/28 11:03:14 gson 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(const char*); 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 #ifndef NO_HTTPS 101 static bool no_openssl_trust_anchors_available(void); 102 #endif 103 #ifdef BUILD_TIMESTAMP 104 static void check_todr_sanity(void); 105 #endif 106 107 static int exit_cleanly = 0; /* Did we finish nicely? */ 108 FILE *logfp; /* log file */ 109 FILE *script; /* script file */ 110 111 const char *multname; 112 const char *err_outofmem; 113 114 #ifdef DEBUG 115 extern int log_flip(void); 116 #endif 117 118 /* Definition for colors */ 119 120 struct { 121 unsigned int bg; 122 unsigned int fg; 123 } clr_arg; 124 125 /* String defaults and stuff for processing the -f file argument. */ 126 127 struct f_arg { 128 const char *name; 129 const char *dflt; 130 char *var; 131 int size; 132 }; 133 134 static const struct f_arg fflagopts[] = { 135 {"release", REL, NULL, 0}, 136 {"machine", MACH, machine, sizeof machine}, 137 {"xfer dir", "/usr/INSTALL", xfer_dir, sizeof xfer_dir}, 138 {"ext dir", "", ext_dir_bin, sizeof ext_dir_bin}, 139 {"ext src dir", "", ext_dir_src, sizeof ext_dir_src}, 140 {"ftp host", SYSINST_FTP_HOST, ftp.xfer_host[XFER_HOST(XFER_FTP)], sizeof ftp.xfer_host[XFER_HOST(XFER_FTP)]}, 141 {"http host", SYSINST_HTTP_HOST, ftp.xfer_host[XFER_HOST(XFER_HTTP)], sizeof ftp.xfer_host[XFER_HOST(XFER_HTTP)]}, 142 {"ftp dir", SYSINST_FTP_DIR, ftp.dir, sizeof ftp.dir}, 143 {"ftp prefix", "/" ARCH_SUBDIR "/binary/sets", set_dir_bin, sizeof set_dir_bin}, 144 {"ftp src prefix", "/source/sets", set_dir_src, sizeof set_dir_src}, 145 {"ftp user", "ftp", ftp.user, sizeof ftp.user}, 146 {"ftp pass", "", ftp.pass, sizeof ftp.pass}, 147 {"ftp proxy", "", ftp.proxy, sizeof ftp.proxy}, 148 {"nfs host", "", nfs_host, sizeof nfs_host}, 149 {"nfs dir", "/bsd/release", nfs_dir, sizeof nfs_dir}, 150 {"cd dev", 0, cdrom_dev, sizeof cdrom_dev}, /* default filled in init */ 151 {"fd dev", "/dev/fd0a", fd_dev, sizeof fd_dev}, 152 {"local dev", "", localfs_dev, sizeof localfs_dev}, 153 {"local fs", "ffs", localfs_fs, sizeof localfs_fs}, 154 {"local dir", "release", localfs_dir, sizeof localfs_dir}, 155 {"targetroot mount", "/targetroot", targetroot_mnt, sizeof targetroot_mnt}, 156 {"dist postfix", "." SETS_TAR_SUFF, dist_postfix, sizeof dist_postfix}, 157 {"dist tgz postfix", ".tgz", dist_tgz_postfix, sizeof dist_tgz_postfix}, 158 {"pkg host", SYSINST_PKG_HOST, pkg.xfer_host[XFER_HOST(XFER_FTP)], sizeof pkg.xfer_host[XFER_HOST(XFER_FTP)]}, 159 {"pkg http host", SYSINST_PKG_HTTP_HOST, pkg.xfer_host[XFER_HOST(XFER_HTTP)], sizeof pkg.xfer_host[XFER_HOST(XFER_HTTP)]}, 160 {"pkg dir", SYSINST_PKG_DIR, pkg.dir, sizeof pkg.dir}, 161 {"pkg prefix", "/" PKG_ARCH_SUBDIR "/" PKG_SUBDIR "/All", pkg_dir, sizeof pkg_dir}, 162 {"pkg user", "ftp", pkg.user, sizeof pkg.user}, 163 {"pkg pass", "", pkg.pass, sizeof pkg.pass}, 164 {"pkg proxy", "", pkg.proxy, sizeof pkg.proxy}, 165 {"pkgsrc host", SYSINST_PKGSRC_HOST, pkgsrc.xfer_host[XFER_HOST(XFER_FTP)], sizeof pkgsrc.xfer_host[XFER_HOST(XFER_FTP)]}, 166 {"pkgsrc http host", SYSINST_PKGSRC_HTTP_HOST, pkgsrc.xfer_host[XFER_HOST(XFER_HTTP)], sizeof pkgsrc.xfer_host[XFER_HOST(XFER_HTTP)]}, 167 {"pkgsrc dir", "", pkgsrc.dir, sizeof pkgsrc.dir}, 168 {"pkgsrc prefix", "pub/pkgsrc/stable", pkgsrc_dir, sizeof pkgsrc_dir}, 169 {"pkgsrc user", "ftp", pkgsrc.user, sizeof pkgsrc.user}, 170 {"pkgsrc pass", "", pkgsrc.pass, sizeof pkgsrc.pass}, 171 {"pkgsrc proxy", "", pkgsrc.proxy, sizeof pkgsrc.proxy}, 172 173 {NULL, NULL, NULL, 0} 174 }; 175 176 static void 177 init(void) 178 { 179 const struct f_arg *arg; 180 181 sizemult = 1; 182 clean_xfer_dir = 0; 183 mnt2_mounted = 0; 184 fd_type = "msdos"; 185 186 pm_head = (struct pm_head_t) SLIST_HEAD_INITIALIZER(pm_head); 187 SLIST_INIT(&pm_head); 188 pm_new = malloc(sizeof (struct pm_devs)); 189 memset(pm_new, 0, sizeof *pm_new); 190 191 for (arg = fflagopts; arg->name != NULL; arg++) { 192 if (arg->var == NULL) 193 continue; 194 if (arg->var == cdrom_dev) 195 get_default_cdrom(arg->var, arg->size); 196 else 197 strlcpy(arg->var, arg->dflt, arg->size); 198 } 199 pkg.xfer = pkgsrc.xfer = XFER_HTTPS; 200 #ifdef NO_HTTPS 201 ftp.xfer = XFER_HTTP; 202 #else 203 ftp.xfer = XFER_HTTPS; 204 #endif 205 206 clr_arg.bg=COLOR_BLUE; 207 clr_arg.fg=COLOR_WHITE; 208 } 209 210 static void 211 init_lang(void) 212 { 213 sizemult = 1; 214 err_outofmem = msg_string(MSG_out_of_memory); 215 multname = msg_string(MSG_secname); 216 } 217 218 int 219 main(int argc, char **argv) 220 { 221 int ch; 222 const char *msg_cat_dir = NULL; 223 224 init(); 225 226 #ifdef DEBUG 227 log_flip(); 228 #endif 229 230 /* Check for TERM ... */ 231 if (!getenv("TERM")) { 232 (void)fprintf(stderr, 233 "sysinst: environment variable TERM not set.\n"); 234 exit(4); 235 } 236 237 /* argv processing */ 238 while ((ch = getopt(argc, argv, "Dr:f:C:m:" 239 #ifndef NO_PARTMAN 240 "p" 241 #endif 242 )) != -1) 243 switch(ch) { 244 case 'D': /* set to get past certain errors in testing */ 245 debug = 1; 246 break; 247 case 'r': 248 /* Release name - ignore for compatibility with older versions */ 249 break; 250 case 'f': 251 /* Definition file to read. */ 252 process_f_flag(optarg); 253 break; 254 case 'C': 255 /* Define colors */ 256 sscanf(optarg, "%u:%u", &clr_arg.bg, &clr_arg.fg); 257 break; 258 case 'm': 259 /* set message catalog directory */ 260 msg_cat_dir = optarg; 261 break; 262 #ifndef NO_PARTMAN 263 case 'p': 264 /* Partition tool */ 265 partman_go = 1; 266 break; 267 #endif 268 case '?': 269 default: 270 usage(); 271 } 272 273 md_init(); 274 275 /* Initialize the partitioning subsystem */ 276 partitions_init(); 277 278 /* 279 * Do we need to tell ftp(1) to avoid checking certificate chains? 280 * Does the ftp(1) that comes with this installer support https 281 * at all? 282 */ 283 #ifndef NO_HTTPS 284 if (no_openssl_trust_anchors_available()) 285 #endif 286 setenv("FTPSSLNOVERIFY", "1", 1); 287 288 /* Prevent kernel conole messages from messing up the display */ 289 discard_console_output(); 290 291 /* initialize message window */ 292 if (menu_init()) { 293 __menu_initerror(); 294 exit(4); 295 } 296 297 /* 298 * Put 'messages' in a window that has a one-character border 299 * on the real screen. 300 */ 301 mainwin = newwin(getmaxy(stdscr) - 2, getmaxx(stdscr) - 2, 1, 1); 302 if (mainwin == NULL) { 303 (void)fprintf(stderr, 304 "sysinst: screen too small\n"); 305 exit(1); 306 } 307 if (has_colors()) { 308 start_color(); 309 do_coloring(clr_arg.fg,clr_arg.bg); 310 } 311 msg_window(mainwin); 312 313 /* Watch for signals and clean up */ 314 (void)atexit(cleanup); 315 (void)signal(SIGINT, ttysighandler); 316 (void)signal(SIGQUIT, ttysighandler); 317 (void)signal(SIGHUP, miscsighandler); 318 319 /* redraw screen */ 320 touchwin(stdscr); 321 refresh(); 322 323 /* Ensure we have mountpoint for target filesystems */ 324 mkdir(targetroot_mnt, S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); 325 326 select_language(msg_cat_dir); 327 get_kb_encoding(); 328 init_lang(); 329 330 #ifdef BUILD_TIMESTAMP 331 check_todr_sanity(); 332 #endif 333 334 /* remove some invalid menu entries */ 335 if (!has_colors()) 336 remove_color_options(); 337 338 /* Menu processing */ 339 if (partman_go) 340 partman(NULL); 341 else 342 process_menu(MENU_netbsd, NULL); 343 344 #ifndef NO_PARTMAN 345 /* clean up internal storage */ 346 pm_destroy_all(); 347 #endif 348 349 partitions_cleanup(); 350 351 exit_cleanly = 1; 352 return 0; 353 } 354 355 static int 356 set_language(menudesc *m, void *arg) 357 { 358 char **fnames = arg; 359 360 msg_file(fnames[m->cursel]); 361 return 1; 362 } 363 364 /* 365 * Search for sysinstmsg.* files in the given dir, collect 366 * their names and return the number of files found. 367 * fnames[0] is preallocated and duplicates are ignored. 368 */ 369 struct found_msgs { 370 char **lang_msg, **fnames; 371 int max_lang, num_lang; 372 373 }; 374 static void 375 find_language_files(const char *path, struct found_msgs *res) 376 { 377 DIR *dir; 378 struct dirent *dirent; 379 char fname[PATH_MAX]; 380 const char *cp; 381 382 res->num_lang = 0; 383 dir = opendir(path); 384 if (!dir) 385 return; 386 387 while ((dirent = readdir(dir)) != 0) { 388 if (memcmp(dirent->d_name, "sysinstmsgs.", 12)) 389 continue; 390 391 if (res->num_lang == 0) 392 res->num_lang = 1; 393 strcpy(fname, path); 394 strcat(fname, "/"); 395 strcat(fname, dirent->d_name); 396 if (msg_file(fname)) 397 continue; 398 cp = msg_string(MSG_sysinst_message_language); 399 if (!strcmp(cp, res->lang_msg[0])) 400 continue; 401 if (res->num_lang == res->max_lang) { 402 char **new; 403 res->max_lang *= 2; 404 new = realloc(res->lang_msg, 405 res->max_lang * sizeof *res->lang_msg); 406 if (!new) 407 break; 408 res->lang_msg = new; 409 new = realloc(res->fnames, 410 res->max_lang * sizeof *res->fnames); 411 if (!new) 412 break; 413 res->fnames = new; 414 } 415 res->fnames[res->num_lang] = strdup(fname); 416 res->lang_msg[res->num_lang++] = strdup(cp); 417 } 418 419 closedir(dir); 420 } 421 422 static void 423 select_language(const char *msg_cat_path) 424 { 425 struct found_msgs found; 426 menu_ent *opt = 0; 427 const char *cp; 428 int lang_menu = -1; 429 int lang; 430 431 found.max_lang = 16; 432 found.num_lang = 0; 433 found.lang_msg = malloc(found.max_lang * sizeof *found.lang_msg); 434 found.fnames = malloc(found.max_lang * sizeof *found.fnames); 435 if (!found.lang_msg || !found.fnames) 436 goto done; 437 found.lang_msg[0] = strdup(msg_string(MSG_sysinst_message_language)); 438 found.fnames[0] = NULL; 439 440 if (msg_cat_path != NULL) 441 find_language_files(msg_cat_path, &found); 442 if (found.num_lang == 0) 443 find_language_files(".", &found); 444 #ifdef CATALOG_DIR 445 if (found.num_lang == 0) 446 find_language_files(CATALOG_DIR, &found); 447 #endif 448 449 msg_file(0); 450 451 if (found.num_lang <= 1) 452 goto done; 453 454 opt = calloc(found.num_lang, sizeof *opt); 455 if (!opt) 456 goto done; 457 458 for (lang = 0; lang < found.num_lang; lang++) { 459 opt[lang].opt_name = found.lang_msg[lang]; 460 opt[lang].opt_action = set_language; 461 } 462 463 lang_menu = new_menu(NULL, opt, found.num_lang, -1, 12, 0, 0, 464 MC_NOEXITOPT, NULL, NULL, NULL, NULL, NULL); 465 466 if (lang_menu != -1) { 467 msg_display(MSG_hello); 468 process_menu(lang_menu, found.fnames); 469 } 470 471 done: 472 if (lang_menu != -1) 473 free_menu(lang_menu); 474 free(opt); 475 for (int i = 0; i < found.num_lang; i++) { 476 free(found.lang_msg[i]); 477 free(found.fnames[i]); 478 } 479 free(found.lang_msg); 480 free(found.fnames); 481 482 /* set locale according to selected language */ 483 cp = msg_string(MSG_sysinst_message_locale); 484 if (cp) { 485 setlocale(LC_CTYPE, cp); 486 setenv("LC_CTYPE", cp, 1); 487 } 488 } 489 490 #ifndef md_may_remove_boot_medium 491 #define md_may_remove_boot_medium() (boot_media_still_needed()<=0) 492 #endif 493 494 /* toplevel menu handler ... */ 495 void 496 toplevel(void) 497 { 498 /* 499 * Undo any stateful side-effects of previous menu choices. 500 * XXX must be idempotent, since we get run each time the main 501 * menu is displayed. 502 */ 503 char *home = getenv("HOME"); 504 if (home != NULL) 505 if (chdir(home) != 0) 506 (void)chdir("/"); 507 unwind_mounts(); 508 clear_swap(); 509 510 /* Display banner message in (english, francais, deutsch..) */ 511 msg_display(MSG_hello); 512 msg_display_add(MSG_md_hello); 513 if (md_may_remove_boot_medium()) 514 msg_display_add(MSG_md_may_remove_boot_medium); 515 msg_display_add(MSG_thanks); 516 } 517 518 519 /* The usage ... */ 520 521 static void 522 usage(void) 523 { 524 525 (void)fprintf(stderr, "usage: sysinst [-C bg:fg] [-D" 526 #ifndef NO_PARTMAN 527 "p" 528 #endif 529 "] [-f definition_file] " 530 "[-m message_catalog_dir]" 531 "\n" 532 "where:\n" 533 "\t-C bg:fg\n\t\tuse different color scheme\n" 534 "\t-D\n\t\trun in debug mode\n" 535 "\t-f definition_file\n\t\toverride built-in defaults from file\n" 536 "\t-m msg_catalog_dir\n\t\tuse translation files from msg_catalog_dir\n" 537 #ifndef NO_PARTMAN 538 "\t-p\n\t\tonly run the partition editor, no installation\n" 539 #endif 540 ); 541 542 exit(1); 543 } 544 545 /* ARGSUSED */ 546 static void 547 miscsighandler(int signo) 548 { 549 550 /* 551 * we need to cleanup(), but it was already scheduled with atexit(), 552 * so it'll be invoked on exit(). 553 */ 554 exit(1); 555 } 556 557 static void 558 ttysighandler(int signo) 559 { 560 561 /* 562 * if we want to ignore a TTY signal (SIGINT or SIGQUIT), then we 563 * just return. If we want to forward a TTY signal, we forward it 564 * to the specified process group. 565 * 566 * This functionality is used when setting up and displaying child 567 * output so that the child gets the signal and presumably dies, 568 * but sysinst continues. We use this rather than actually ignoring 569 * the signals, because that will be passed on to a child 570 * through fork/exec, whereas special handlers get reset on exec.. 571 */ 572 if (ttysig_ignore) 573 return; 574 if (ttysig_forward) { 575 killpg(ttysig_forward, signo); 576 return; 577 } 578 579 /* 580 * we need to cleanup(), but it was already scheduled with atexit(), 581 * so it'll be invoked on exit(). 582 */ 583 exit(1); 584 } 585 586 static void 587 cleanup(void) 588 { 589 time_t tloc; 590 591 (void)time(&tloc); 592 593 #if 0 594 restore_etc(); 595 #endif 596 /* Ensure we aren't inside the target tree */ 597 chdir(getenv("HOME")); 598 unwind_mounts(); 599 umount_mnt2(); 600 clear_swap(); 601 602 endwin(); 603 604 if (logfp) { 605 fprintf(logfp, "Log ended at: %s\n", safectime(&tloc)); 606 fflush(logfp); 607 fclose(logfp); 608 logfp = NULL; 609 } 610 if (script) { 611 fprintf(script, "# Script ended at: %s\n", safectime(&tloc)); 612 fflush(script); 613 fclose(script); 614 script = NULL; 615 } 616 617 if (!exit_cleanly) 618 fprintf(stderr, "\n\nsysinst terminated.\n"); 619 } 620 621 622 /* process function ... */ 623 624 void 625 process_f_flag(char *f_name) 626 { 627 char buffer[STRSIZE]; 628 int len; 629 const struct f_arg *arg; 630 FILE *fp; 631 char *cp, *cp1, *err; 632 633 /* open the file */ 634 fp = fopen(f_name, "r"); 635 if (fp == NULL) { 636 const char *args[] = { f_name }; 637 err = str_arg_subst(msg_string(MSG_config_open_error), 638 __arraycount(args), args); 639 fprintf(stderr, "%s\n", err); 640 free(err); 641 exit(1); 642 } 643 644 while (fgets(buffer, sizeof buffer, fp) != NULL) { 645 cp = buffer + strspn(buffer, " \t"); 646 if (strchr("#\r\n", *cp) != NULL) 647 continue; 648 for (arg = fflagopts; arg->name != NULL; arg++) { 649 len = strlen(arg->name); 650 if (memcmp(cp, arg->name, len) != 0) 651 continue; 652 if (arg->var == NULL || arg->size == 0) 653 continue; 654 cp1 = cp + len; 655 cp1 += strspn(cp1, " \t"); 656 if (*cp1++ != '=') 657 continue; 658 cp1 += strspn(cp1, " \t"); 659 len = strcspn(cp1, " \n\r\t"); 660 cp1[len] = 0; 661 strlcpy(arg->var, cp1, arg->size); 662 break; 663 } 664 } 665 666 fclose(fp); 667 } 668 669 #ifndef NO_HTTPS 670 /* 671 * return true if we do not have any root certificates installed, 672 * so can not verify any trust chain. 673 * We rely on /etc/openssl being the OPENSSLDIR and test the 674 * "all in one" /etc/openssl/cert.pem first, if that is not found 675 * check if there are multiple regular files or symlinks in 676 * /etc/openssl/certs/. 677 */ 678 static bool 679 no_openssl_trust_anchors_available(void) 680 { 681 struct stat sb; 682 DIR *dir; 683 struct dirent *ent; 684 size_t cnt; 685 686 /* check the omnibus single file variant first */ 687 if (stat("/etc/openssl/cert.pem", &sb) == 0 && 688 S_ISREG(sb.st_mode) && sb.st_size > 0) 689 return false; /* exists and is a non-empty file */ 690 691 /* look for files/symlinks in the certs subdirectory */ 692 dir = opendir("/etc/openssl/certs"); 693 if (dir == NULL) 694 return true; 695 for (cnt = 0; cnt < 2; ) { 696 ent = readdir(dir); 697 if (ent == NULL) 698 break; 699 switch (ent->d_type) { 700 case DT_REG: 701 case DT_LNK: 702 cnt++; 703 break; 704 default: 705 break; 706 } 707 } 708 closedir(dir); 709 710 return cnt < 2; 711 } 712 #endif 713 714 #ifdef BUILD_TIMESTAMP 715 static void 716 check_todr_sanity(void) 717 { 718 time_t now = time(NULL); 719 720 if (now >= BUILD_TIMESTAMP - 2*86400) 721 return; 722 723 do_time_and_date_setup(MSG_todr_old); 724 } 725 #endif 726 727