1/* $NetBSD: util.c,v 1.173.2.1 2012/05/17 18:57:11 sborrill 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/* util.c -- routines that don't really fit anywhere else... */ 36 37#include <stdio.h> 38#include <stdarg.h> 39#include <string.h> 40#include <unistd.h> 41#include <sys/mount.h> 42#include <sys/disklabel.h> 43#include <sys/dkio.h> 44#include <sys/ioctl.h> 45#include <sys/types.h> 46#include <sys/param.h> 47#include <sys/sysctl.h> 48#include <sys/stat.h> 49#include <sys/statvfs.h> 50#include <isofs/cd9660/iso.h> 51#include <curses.h> 52#include <err.h> 53#include <errno.h> 54#include <dirent.h> 55#include <util.h> 56#include "defs.h" 57#include "md.h" 58#include "msg_defs.h" 59#include "menu_defs.h" 60 61#ifndef MD_SETS_SELECTED 62#define MD_SETS_SELECTED SET_KERNEL_1, SET_SYSTEM, SET_X11, SET_MD 63#endif 64#ifndef MD_SETS_SELECTED_MINIMAL 65#define MD_SETS_SELECTED_MINIMAL SET_KERNEL_1, SET_CORE 66#endif 67#ifndef MD_SETS_SELECTED_NOX 68#define MD_SETS_SELECTED_NOX SET_KERNEL_1, SET_SYSTEM, SET_MD 69#endif 70#ifndef MD_SETS_VALID 71#define MD_SETS_VALID SET_KERNEL, SET_SYSTEM, SET_X11, SET_MD, SET_SOURCE 72#endif 73 74#define MAX_CD_DEVS 256 /* how many cd drives do we expect to attach */ 75#define ISO_BLKSIZE ISO_DEFAULT_BLOCK_SIZE 76 77static const char *msg_yes, *msg_no, *msg_all, *msg_some, *msg_none; 78static const char *msg_cur_distsets_row; 79static int select_menu_width; 80 81static uint8_t set_status[SET_GROUP_END]; 82#define SET_VALID 0x01 83#define SET_SELECTED 0x02 84#define SET_SKIPPED 0x04 85#define SET_INSTALLED 0x08 86 87struct tarstats { 88 int nselected; 89 int nfound; 90 int nnotfound; 91 int nerror; 92 int nsuccess; 93 int nskipped; 94} tarstats; 95 96distinfo dist_list[] = { 97#ifdef SET_KERNEL_1_NAME 98 {SET_KERNEL_1_NAME, SET_KERNEL_1, MSG_set_kernel_1, NULL}, 99#endif 100#ifdef SET_KERNEL_2_NAME 101 {SET_KERNEL_2_NAME, SET_KERNEL_2, MSG_set_kernel_2, NULL}, 102#endif 103#ifdef SET_KERNEL_3_NAME 104 {SET_KERNEL_3_NAME, SET_KERNEL_3, MSG_set_kernel_3, NULL}, 105#endif 106#ifdef SET_KERNEL_4_NAME 107 {SET_KERNEL_4_NAME, SET_KERNEL_4, MSG_set_kernel_4, NULL}, 108#endif 109#ifdef SET_KERNEL_5_NAME 110 {SET_KERNEL_5_NAME, SET_KERNEL_5, MSG_set_kernel_5, NULL}, 111#endif 112#ifdef SET_KERNEL_6_NAME 113 {SET_KERNEL_6_NAME, SET_KERNEL_6, MSG_set_kernel_6, NULL}, 114#endif 115#ifdef SET_KERNEL_7_NAME 116 {SET_KERNEL_7_NAME, SET_KERNEL_7, MSG_set_kernel_7, NULL}, 117#endif 118#ifdef SET_KERNEL_8_NAME 119 {SET_KERNEL_8_NAME, SET_KERNEL_8, MSG_set_kernel_8, NULL}, 120#endif 121 122 {"modules", SET_MODULES, MSG_set_modules, NULL}, 123 {"base", SET_BASE, MSG_set_base, NULL}, 124 {"etc", SET_ETC, MSG_set_system, NULL}, 125 {"comp", SET_COMPILER, MSG_set_compiler, NULL}, 126 {"games", SET_GAMES, MSG_set_games, NULL}, 127 {"man", SET_MAN_PAGES, MSG_set_man_pages, NULL}, 128 {"misc", SET_MISC, MSG_set_misc, NULL}, 129 {"tests", SET_TESTS, MSG_set_tests, NULL}, 130 {"text", SET_TEXT_TOOLS, MSG_set_text_tools, NULL}, 131 132 {NULL, SET_GROUP, MSG_set_X11, NULL}, 133 {"xbase", SET_X11_BASE, MSG_set_X11_base, NULL}, 134 {"xcomp", SET_X11_PROG, MSG_set_X11_prog, NULL}, 135 {"xetc", SET_X11_ETC, MSG_set_X11_etc, NULL}, 136 {"xfont", SET_X11_FONTS, MSG_set_X11_fonts, NULL}, 137 {"xserver", SET_X11_SERVERS, MSG_set_X11_servers, NULL}, 138 {NULL, SET_GROUP_END, NULL, NULL}, 139 140#ifdef SET_MD_1_NAME 141 {SET_MD_1_NAME, SET_MD_1, MSG_set_md_1, NULL}, 142#endif 143#ifdef SET_MD_2_NAME 144 {SET_MD_2_NAME, SET_MD_2, MSG_set_md_2, NULL}, 145#endif 146#ifdef SET_MD_3_NAME 147 {SET_MD_3_NAME, SET_MD_3, MSG_set_md_3, NULL}, 148#endif 149#ifdef SET_MD_4_NAME 150 {SET_MD_4_NAME, SET_MD_4, MSG_set_md_4, NULL}, 151#endif 152 153 {NULL, SET_GROUP, MSG_set_source, NULL}, 154 {"syssrc", SET_SYSSRC, MSG_set_syssrc, NULL}, 155 {"src", SET_SRC, MSG_set_src, NULL}, 156 {"sharesrc", SET_SHARESRC, MSG_set_sharesrc, NULL}, 157 {"gnusrc", SET_GNUSRC, MSG_set_gnusrc, NULL}, 158 {"xsrc", SET_XSRC, MSG_set_xsrc, NULL}, 159 {NULL, SET_GROUP_END, NULL, NULL}, 160 161 {NULL, SET_LAST, NULL, NULL}, 162}; 163 164#define MAX_CD_INFOS 16 /* how many media can be found? */ 165struct cd_info { 166 char device_name[16]; 167 char menu[100]; 168}; 169static struct cd_info cds[MAX_CD_INFOS]; 170 171/* 172 * local prototypes 173 */ 174 175static int check_for(unsigned int mode, const char *pathname); 176static int get_iso9660_volname(int dev, int sess, char *volname); 177static int get_available_cds(void); 178 179void 180init_set_status(int flags) 181{ 182 static const uint8_t sets_valid[] = {MD_SETS_VALID}; 183 static const uint8_t sets_selected_full[] = {MD_SETS_SELECTED}; 184 static const uint8_t sets_selected_minimal[] = {MD_SETS_SELECTED_MINIMAL}; 185 static const uint8_t sets_selected_nox[] = {MD_SETS_SELECTED_NOX}; 186 static const uint8_t *sets_selected; 187 unsigned int nelem_selected; 188 unsigned int i, len; 189 const char *longest; 190 191 if (flags & SFLAG_MINIMAL) { 192 sets_selected = sets_selected_minimal; 193 nelem_selected = nelem(sets_selected_minimal); 194 } else if (flags & SFLAG_NOX) { 195 sets_selected = sets_selected_nox; 196 nelem_selected = nelem(sets_selected_nox); 197 } else { 198 sets_selected = sets_selected_full; 199 nelem_selected = nelem(sets_selected_full); 200 } 201 202 for (i = 0; i < nelem(sets_valid); i++) 203 set_status[sets_valid[i]] = SET_VALID; 204 for (i = 0; i < nelem_selected; i++) 205 set_status[sets_selected[i]] |= SET_SELECTED; 206 207 set_status[SET_GROUP] = SET_VALID; 208 209 /* Lookup some strings we need lots of times */ 210 msg_yes = msg_string(MSG_Yes); 211 msg_no = msg_string(MSG_No); 212 msg_all = msg_string(MSG_All); 213 msg_some = msg_string(MSG_Some); 214 msg_none = msg_string(MSG_None); 215 msg_cur_distsets_row = msg_string(MSG_cur_distsets_row); 216 217 /* Find longest and use it to determine width of selection menu */ 218 len = strlen(msg_no); longest = msg_no; 219 i = strlen(msg_yes); if (i > len) {len = i; longest = msg_yes; } 220 i = strlen(msg_all); if (i > len) {len = i; longest = msg_all; } 221 i = strlen(msg_some); if (i > len) {len = i; longest = msg_some; } 222 i = strlen(msg_none); if (i > len) {len = i; longest = msg_none; } 223 select_menu_width = snprintf(NULL, 0, msg_cur_distsets_row, "",longest); 224 225 /* Give the md code a chance to choose the right kernel, etc. */ 226 md_init_set_status(flags); 227} 228 229int 230dir_exists_p(const char *path) 231{ 232 233 return file_mode_match(path, S_IFDIR); 234} 235 236int 237file_exists_p(const char *path) 238{ 239 240 return file_mode_match(path, S_IFREG); 241} 242 243int 244file_mode_match(const char *path, unsigned int mode) 245{ 246 struct stat st; 247 248 return (stat(path, &st) == 0 && (st.st_mode & S_IFMT) == mode); 249} 250 251uint 252get_ramsize(void) 253{ 254 uint64_t ramsize; 255 size_t len = sizeof ramsize; 256 int mib[2] = {CTL_HW, HW_PHYSMEM64}; 257 258 sysctl(mib, 2, &ramsize, &len, NULL, 0); 259 260 /* Find out how many Megs ... round up. */ 261 return (ramsize + MEG - 1) / MEG; 262} 263 264void 265run_makedev(void) 266{ 267 char *owd; 268 269 msg_display_add("\n\n"); 270 msg_display_add(MSG_makedev); 271 272 owd = getcwd(NULL, 0); 273 274 /* make /dev, in case the user didn't extract it. */ 275 make_target_dir("/dev"); 276 target_chdir_or_die("/dev"); 277 run_program(0, "/bin/sh MAKEDEV all"); 278 279 chdir(owd); 280 free(owd); 281} 282 283/* 284 * Performs in-place replacement of a set of patterns in a file that lives 285 * inside the installed system. The patterns must be separated by a semicolon. 286 * For example: 287 * 288 * replace("/etc/some-file.conf", "s/prop1=NO/prop1=YES/;s/foo/bar/"); 289 */ 290void 291replace(const char *path, const char *patterns, ...) 292{ 293 char *spatterns; 294 va_list ap; 295 296 va_start(ap, patterns); 297 vasprintf(&spatterns, patterns, ap); 298 va_end(ap); 299 if (spatterns == NULL) 300 err(1, "vasprintf(&spatterns, \"%s\", ...)", patterns); 301 302 run_program(RUN_CHROOT, "sed -an -e '%s;H;$!d;g;w %s' %s", spatterns, 303 path, path); 304 305 free(spatterns); 306} 307 308static int 309floppy_fetch(const char *set_name) 310{ 311 char post[4]; 312 msg errmsg; 313 int menu; 314 int status; 315 const char *write_mode = ">"; 316 317 strcpy(post, "aa"); 318 319 errmsg = ""; 320 menu = MENU_fdok; 321 for (;;) { 322 umount_mnt2(); 323 msg_display(errmsg); 324 msg_display_add(MSG_fdmount, set_name, post); 325 process_menu(menu, &status); 326 if (status != SET_CONTINUE) 327 return status; 328 menu = MENU_fdremount; 329 errmsg = MSG_fdremount; 330 if (run_program(0, "/sbin/mount -r -t %s %s /mnt2", 331 fd_type, fd_dev)) 332 continue; 333 mnt2_mounted = 1; 334 errmsg = MSG_fdnotfound; 335 336 /* Display this because it might take a while.... */ 337 if (run_program(RUN_DISPLAY, 338 "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'", 339 set_name, post, write_mode, 340 target_prefix(), xfer_dir, set_name, dist_postfix)) 341 /* XXX: a read error will give a corrupt file! */ 342 continue; 343 344 /* We got that file, advance to next fragment */ 345 if (post[1] < 'z') 346 post[1]++; 347 else 348 post[1] = 'a', post[0]++; 349 write_mode = ">>"; 350 errmsg = ""; 351 menu = MENU_fdok; 352 } 353} 354 355/* 356 * Load files from floppy. Requires a /mnt2 directory for mounting them. 357 */ 358int 359get_via_floppy(void) 360{ 361 362 process_menu(MENU_floppysource, NULL); 363 364 fetch_fn = floppy_fetch; 365 366 /* Set ext_dir for absolute path. */ 367 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", target_prefix(), xfer_dir); 368 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", target_prefix(), xfer_dir); 369 370 return SET_OK; 371} 372 373/* 374 * Get the volume name of a ISO9660 file system 375 */ 376static int 377get_iso9660_volname(int dev, int sess, char *volname) 378{ 379 int blkno, error, last; 380 char buf[ISO_BLKSIZE]; 381 struct iso_volume_descriptor *vd = NULL; 382 struct iso_primary_descriptor *pd = NULL; 383 384 for (blkno = sess+16; blkno < sess+16+100; blkno++) { 385 error = pread(dev, buf, ISO_BLKSIZE, blkno*ISO_BLKSIZE); 386 if (error == -1) 387 return -1; 388 vd = (struct iso_volume_descriptor *)&buf; 389 if (memcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0) 390 return -1; 391 if (isonum_711((const unsigned char *)&vd->type) 392 == ISO_VD_PRIMARY) { 393 pd = (struct iso_primary_descriptor*)buf; 394 strncpy(volname, pd->volume_id, sizeof pd->volume_id); 395 last = sizeof pd->volume_id-1; 396 while (last >= 0 397 && (volname[last] == ' ' || volname[last] == 0)) 398 last--; 399 volname[last+1] = 0; 400 return 0; 401 } 402 } 403 return -1; 404} 405 406/* 407 * Get a list of all available CD media (not drives!), return 408 * the number of entries collected. 409 */ 410static int 411get_available_cds(void) 412{ 413 char dname[16], volname[80]; 414 struct cd_info *info = cds; 415 struct disklabel label; 416 int i, part, dev, error, sess, ready, count = 0; 417 418 for (i = 0; i < MAX_CD_DEVS; i++) { 419 sprintf(dname, "/dev/rcd%d%c", i, 'a'+RAW_PART); 420 dev = open(dname, O_RDONLY, 0); 421 if (dev == -1) 422 break; 423 ready = 0; 424 error = ioctl(dev, DIOCTUR, &ready); 425 if (error != 0 || ready == 0) { 426 close(dev); 427 continue; 428 } 429 error = ioctl(dev, DIOCGDINFO, &label); 430 close(dev); 431 if (error == 0) { 432 for (part = 0; part < label.d_npartitions; part++) { 433 if (label.d_partitions[part].p_fstype 434 == FS_UNUSED 435 || label.d_partitions[part].p_size == 0) 436 continue; 437 if (label.d_partitions[part].p_fstype 438 == FS_ISO9660) { 439 sess = label.d_partitions[part] 440 .p_cdsession; 441 sprintf(dname, "/dev/rcd%d%c", i, 442 'a'+part); 443 dev = open(dname, O_RDONLY, 0); 444 if (dev == -1) 445 continue; 446 error = get_iso9660_volname(dev, sess, 447 volname); 448 close(dev); 449 if (error) continue; 450 sprintf(info->device_name, "cd%d%c", 451 i, 'a'+part); 452 sprintf(info->menu, "%s (%s)", 453 info->device_name, 454 volname); 455 } else { 456 /* 457 * All install CDs use partition 458 * a for the sets. 459 */ 460 if (part > 0) 461 continue; 462 sprintf(info->device_name, "cd%d%c", 463 i, 'a'+part); 464 strcpy(info->menu, info->device_name); 465 } 466 info++; 467 if (++count >= MAX_CD_INFOS) 468 break; 469 } 470 } 471 } 472 return count; 473} 474 475static int 476cd_has_sets(void) 477{ 478 /* Mount it */ 479 if (run_program(RUN_SILENT, "/sbin/mount -rt cd9660 /dev/%s /mnt2", 480 cdrom_dev) != 0) 481 return 0; 482 483 mnt2_mounted = 1; 484 485 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", "/mnt2", set_dir_bin); 486 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", "/mnt2", set_dir_src); 487 return dir_exists_p(ext_dir_bin); 488} 489 490 491static int 492set_cd_select(menudesc *m, void *arg) 493{ 494 *(int *)arg = m->cursel; 495 return 1; 496} 497 498/* 499 * Check whether we can remove the boot media. 500 * If it is not a local filesystem, return -1. 501 * If we can not decide for sure (can not tell MD content from plain ffs 502 * on hard disk, for example), return 0. 503 * If it is a CD/DVD, return 1. 504 */ 505int 506boot_media_still_needed(void) 507{ 508 struct statvfs sb; 509 510 if (statvfs("/", &sb) == 0) { 511 if (!(sb.f_flag & ST_LOCAL)) 512 return -1; 513 if (strcmp(sb.f_fstypename, MOUNT_CD9660) == 0 514 || strcmp(sb.f_fstypename, MOUNT_UDF) == 0) 515 return 1; 516 } 517 518 return 0; 519} 520 521/* 522 * Get from a CDROM distribution. 523 * Also used on "installation using bootable install media" 524 * as the default option in the "distmedium" menu. 525 */ 526int 527get_via_cdrom(void) 528{ 529 menu_ent cd_menu[MAX_CD_INFOS]; 530 struct stat sb; 531 int num_cds, menu_cd, i, selected_cd = 0; 532 bool silent = false; 533 int mib[2]; 534 char rootdev[SSTRSIZE] = ""; 535 size_t varlen; 536 537 /* If root is not md(4) and we have set dir, skip this step. */ 538 mib[0] = CTL_KERN; 539 mib[1] = KERN_ROOT_DEVICE; 540 varlen = sizeof(rootdev); 541 (void)sysctl(mib, 2, rootdev, &varlen, NULL, 0); 542 if (stat(set_dir_bin, &sb) == 0 && S_ISDIR(sb.st_mode) && 543 strncmp("md", rootdev, 2) != 0) { 544 strlcpy(ext_dir_bin, set_dir_bin, sizeof ext_dir_bin); 545 strlcpy(ext_dir_src, set_dir_src, sizeof ext_dir_src); 546 return SET_OK; 547 } 548 549 num_cds = get_available_cds(); 550 if (num_cds <= 0) { 551 silent = true; 552 } else if (num_cds == 1) { 553 /* single CD found, check for sets on it */ 554 strcpy(cdrom_dev, cds[0].device_name); 555 if (cd_has_sets()) 556 return SET_OK; 557 } else { 558 for (i = 0; i< num_cds; i++) { 559 cd_menu[i].opt_name = cds[i].menu; 560 cd_menu[i].opt_menu = OPT_NOMENU; 561 cd_menu[i].opt_flags = OPT_EXIT; 562 cd_menu[i].opt_action = set_cd_select; 563 } 564 /* create a menu offering available choices */ 565 menu_cd = new_menu(MSG_Available_cds, 566 cd_menu, num_cds, -1, 4, 0, 0, 567 MC_SCROLL | MC_NOEXITOPT, 568 NULL, NULL, NULL, NULL, NULL); 569 if (menu_cd == -1) 570 return SET_RETRY; 571 msg_display(MSG_ask_cd); 572 process_menu(menu_cd, &selected_cd); 573 free_menu(menu_cd); 574 strcpy(cdrom_dev, cds[selected_cd].device_name); 575 if (cd_has_sets()) 576 return SET_OK; 577 } 578 579 if (silent) 580 msg_display(""); 581 else { 582 umount_mnt2(); 583 msg_display(MSG_cd_path_not_found); 584 process_menu(MENU_ok, NULL); 585 } 586 587 /* ask for paths on the CD */ 588 process_menu(MENU_cdromsource, NULL); 589 590 if (cd_has_sets()) 591 return SET_OK; 592 593 return SET_RETRY; 594} 595 596 597/* 598 * Get from a pathname inside an unmounted local filesystem 599 * (e.g., where sets were preloaded onto a local DOS partition) 600 */ 601int 602get_via_localfs(void) 603{ 604 605 /* Get device, filesystem, and filepath */ 606 process_menu (MENU_localfssource, NULL); 607 608 /* Mount it */ 609 if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2", 610 localfs_fs, localfs_dev)) 611 return SET_RETRY; 612 613 mnt2_mounted = 1; 614 615 snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s/%s", 616 "/mnt2", localfs_dir, set_dir_bin); 617 snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s/%s", 618 "/mnt2", localfs_dir, set_dir_src); 619 620 return SET_OK; 621} 622 623/* 624 * Get from an already-mounted pathname. 625 */ 626 627int 628get_via_localdir(void) 629{ 630 631 /* Get filepath */ 632 process_menu(MENU_localdirsource, NULL); 633 634 /* 635 * We have to have an absolute path ('cos pax runs in a 636 * different directory), make it so. 637 */ 638 snprintf(ext_dir_bin, sizeof ext_dir_bin, "/%s/%s", localfs_dir, set_dir_bin); 639 snprintf(ext_dir_src, sizeof ext_dir_src, "/%s/%s", localfs_dir, set_dir_src); 640 641 return SET_OK; 642} 643 644 645/* 646 * Support for custom distribution fetches / unpacks. 647 */ 648 649unsigned int 650set_X11_selected(void) 651{ 652 int i; 653 654 for (i = SET_X11_FIRST; ++i < SET_X11_LAST;) 655 if (set_status[i] & SET_SELECTED) 656 return 1; 657 return 0; 658} 659 660unsigned int 661get_kernel_set(void) 662{ 663 int i; 664 665 for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;) 666 if (set_status[i] & SET_SELECTED) 667 return i; 668 return SET_NONE; 669} 670 671void 672set_kernel_set(unsigned int kernel_set) 673{ 674 int i; 675 676 /* only one kernel set is allowed */ 677 for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;) 678 set_status[i] &= ~SET_SELECTED; 679 set_status[kernel_set] |= SET_SELECTED; 680} 681 682static int 683set_toggle(menudesc *menu, void *arg) 684{ 685 distinfo **distp = arg; 686 int set = distp[menu->cursel]->set; 687 688 if (set > SET_KERNEL_FIRST && set < SET_KERNEL_LAST && 689 !(set_status[set] & SET_SELECTED)) 690 set_kernel_set(set); 691 else 692 set_status[set] ^= SET_SELECTED; 693 return 0; 694} 695 696static int 697set_all_none(menudesc *menu, void *arg, int set, int clr) 698{ 699 distinfo **distp = arg; 700 distinfo *dist = *distp; 701 int nested; 702 703 for (nested = 0; dist->set != SET_GROUP_END || nested--; dist++) { 704 if (dist->set == SET_GROUP) { 705 nested++; 706 continue; 707 } 708 set_status[dist->set] = (set_status[dist->set] & ~clr) | set; 709 } 710 return 0; 711} 712 713static int 714set_all(menudesc *menu, void *arg) 715{ 716 return set_all_none(menu, arg, SET_SELECTED, 0); 717} 718 719static int 720set_none(menudesc *menu, void *arg) 721{ 722 return set_all_none(menu, arg, 0, SET_SELECTED); 723} 724 725static void 726set_label(menudesc *menu, int opt, void *arg) 727{ 728 distinfo **distp = arg; 729 distinfo *dist = distp[opt]; 730 const char *selected; 731 const char *desc; 732 int nested; 733 734 desc = dist->desc; 735 736 if (dist->set != SET_GROUP) 737 selected = set_status[dist->set] & SET_SELECTED ? msg_yes : msg_no; 738 else { 739 /* sub menu - display None/Some/All */ 740 nested = 0; 741 selected = "unknown"; 742 while ((++dist)->set != SET_GROUP_END || nested--) { 743 if (dist->set == SET_GROUP) { 744 nested++; 745 continue; 746 } 747 if (!(set_status[dist->set] & SET_VALID)) 748 continue; 749 if (set_status[dist->set] & SET_SELECTED) { 750 if (selected == msg_none) { 751 selected = msg_some; 752 break; 753 } 754 selected = msg_all; 755 } else { 756 if (selected == msg_all) { 757 selected = msg_some; 758 break; 759 } 760 selected = msg_none; 761 } 762 } 763 } 764 765 wprintw(menu->mw, msg_cur_distsets_row, msg_string(desc), selected); 766} 767 768static int set_sublist(menudesc *menu, void *arg); 769 770static int 771initialise_set_menu(distinfo *dist, menu_ent *me, distinfo **de, int all_none) 772{ 773 int set; 774 int sets; 775 int nested; 776 777 for (sets = 0; ; dist++) { 778 set = dist->set; 779 if (set == SET_LAST || set == SET_GROUP_END) 780 break; 781 if (!(set_status[set] & SET_VALID)) 782 continue; 783 *de = dist; 784 me->opt_menu = OPT_NOMENU; 785 me->opt_flags = 0; 786 me->opt_name = NULL; 787 if (set != SET_GROUP) 788 me->opt_action = set_toggle; 789 else { 790 /* Collapse sublist */ 791 nested = 0; 792 while ((++dist)->set != SET_GROUP_END || nested--) { 793 if (dist->set == SET_GROUP) 794 nested++; 795 } 796 me->opt_action = set_sublist; 797 } 798 sets++; 799 de++; 800 me++; 801 } 802 803 if (all_none) { 804 me->opt_menu = OPT_NOMENU; 805 me->opt_flags = 0; 806 me->opt_name = MSG_select_all; 807 me->opt_action = set_all; 808 me++; 809 me->opt_menu = OPT_NOMENU; 810 me->opt_flags = 0; 811 me->opt_name = MSG_select_none; 812 me->opt_action = set_none; 813 sets += 2; 814 } 815 816 return sets; 817} 818 819static int 820set_sublist(menudesc *menu, void *arg) 821{ 822 distinfo *de[SET_LAST]; 823 menu_ent me[SET_LAST]; 824 distinfo **dist = arg; 825 int menu_no; 826 int sets; 827 828 sets = initialise_set_menu(dist[menu->cursel] + 1, me, de, 1); 829 830 menu_no = new_menu(NULL, me, sets, 20, 10, 0, select_menu_width, 831 MC_SUBMENU | MC_SCROLL | MC_DFLTEXIT, 832 NULL, set_label, NULL, NULL, 833 MSG_install_selected_sets); 834 835 process_menu(menu_no, de); 836 free_menu(menu_no); 837 838 return 0; 839} 840 841void 842customise_sets(void) 843{ 844 distinfo *de[SET_LAST]; 845 menu_ent me[SET_LAST]; 846 int sets; 847 int menu_no; 848 849 msg_display(MSG_cur_distsets); 850 msg_table_add(MSG_cur_distsets_header); 851 852 sets = initialise_set_menu(dist_list, me, de, 0); 853 854 menu_no = new_menu(NULL, me, sets, 0, 5, 0, select_menu_width, 855 MC_SCROLL | MC_NOBOX | MC_DFLTEXIT | MC_NOCLEAR, 856 NULL, set_label, NULL, NULL, 857 MSG_install_selected_sets); 858 859 process_menu(menu_no, de); 860 free_menu(menu_no); 861} 862 863/* 864 * Extract_file **REQUIRES** an absolute path in ext_dir. Any code 865 * that sets up xfer_dir for use by extract_file needs to put in the 866 * full path name to the directory. 867 */ 868 869int 870extract_file(distinfo *dist, int update) 871{ 872 char path[STRSIZE]; 873 char *owd; 874 int rval; 875 876 /* If we might need to tidy up, ensure directory exists */ 877 if (fetch_fn != NULL) 878 make_target_dir(xfer_dir); 879 880 (void)snprintf(path, sizeof path, "%s/%s%s", 881 ext_dir_for_set(dist->name), dist->name, dist_postfix); 882 883 owd = getcwd(NULL, 0); 884 885 /* Do we need to fetch the file now? */ 886 if (fetch_fn != NULL) { 887 rval = fetch_fn(dist->name); 888 if (rval != SET_OK) 889 return rval; 890 } 891 892 /* check tarfile exists */ 893 if (!file_exists_p(path)) { 894 895#ifdef SUPPORT_8_3_SOURCE_FILESYSTEM 896 /* 897 * Update path to use dist->name truncated to the first eight 898 * characters and check again 899 */ 900 (void)snprintf(path, sizeof path, "%s/%.8s%.4s", /* 4 as includes '.' */ 901 ext_dir_for_set(dist->name), dist->name, dist_postfix); 902 if (!file_exists_p(path)) { 903#endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */ 904 905 tarstats.nnotfound++; 906 907 msg_display(MSG_notarfile, path); 908 process_menu(MENU_ok, NULL); 909 return SET_RETRY; 910 } 911#ifdef SUPPORT_8_3_SOURCE_FILESYSTEM 912 } 913#endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */ 914 915 tarstats.nfound++; 916 /* cd to the target root. */ 917 if (update && (dist->set == SET_ETC || dist->set == SET_X11_ETC)) { 918 make_target_dir("/.sysinst"); 919 target_chdir_or_die("/.sysinst"); 920 } else if (dist->set == SET_PKGSRC) 921 target_chdir_or_die("/usr"); 922 else 923 target_chdir_or_die("/"); 924 925 /* 926 * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0 927 * but is a file in 5.1 and beyond, so on upgrades we need to 928 * delete it before extracting the xbase set. 929 */ 930 if (update && dist->set == SET_X11_BASE) 931 run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc"); 932 933 /* now extract set files into "./". */ 934 rval = run_program(RUN_DISPLAY | RUN_PROGRESS, 935 "progress -zf %s tar --chroot -xhepf -", path); 936 937 chdir(owd); 938 free(owd); 939 940 /* Check rval for errors and give warning. */ 941 if (rval != 0) { 942 tarstats.nerror++; 943 msg_display(MSG_tarerror, path); 944 process_menu(MENU_ok, NULL); 945 return SET_RETRY; 946 } 947 948 if (fetch_fn != NULL && clean_xfer_dir) { 949 run_program(0, "rm %s", path); 950 /* Plausibly we should unlink an empty xfer_dir as well */ 951 } 952 953 set_status[dist->set] |= SET_INSTALLED; 954 tarstats.nsuccess++; 955 return SET_OK; 956} 957 958static void 959skip_set(distinfo *dist, int skip_type) 960{ 961 int nested; 962 int set; 963 964 nested = 0; 965 while ((++dist)->set != SET_GROUP_END || nested--) { 966 set = dist->set; 967 if (set == SET_GROUP) { 968 nested++; 969 continue; 970 } 971 if (set == SET_LAST) 972 break; 973 if (set_status[set] == (SET_SELECTED | SET_VALID)) 974 set_status[set] |= SET_SKIPPED; 975 tarstats.nskipped++; 976 } 977} 978 979/* 980 * Get and unpack the distribution. 981 * Show success_msg if installation completes. 982 * Otherwise show failure_msg and wait for the user to ack it before continuing. 983 * success_msg and failure_msg must both be 0-adic messages. 984 */ 985int 986get_and_unpack_sets(int update, msg setupdone_msg, msg success_msg, msg failure_msg) 987{ 988 distinfo *dist; 989 int status; 990 int set; 991 992 /* Ensure mountpoint for distribution files exists in current root. */ 993 (void)mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); 994 if (script) 995 (void)fprintf(script, "mkdir -m 755 /mnt2\n"); 996 997 /* reset failure/success counters */ 998 memset(&tarstats, 0, sizeof(tarstats)); 999 1000 /* Find out which files to "get" if we get files. */ 1001 1002 /* Accurately count selected sets */ 1003 for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) { 1004 if ((set_status[set] & (SET_VALID | SET_SELECTED)) 1005 == (SET_VALID | SET_SELECTED)) 1006 tarstats.nselected++; 1007 } 1008 1009 status = SET_RETRY; 1010 for (dist = dist_list; ; dist++) { 1011 set = dist->set; 1012 if (set == SET_LAST) 1013 break; 1014 if (dist->name == NULL) 1015 continue; 1016 if (set_status[set] != (SET_VALID | SET_SELECTED)) 1017 continue; 1018 1019 if (status != SET_OK) { 1020 /* This might force a redraw.... */ 1021 clearok(curscr, 1); 1022 touchwin(stdscr); 1023 wrefresh(stdscr); 1024 /* Sort out the location of the set files */ 1025 do { 1026 umount_mnt2(); 1027 msg_display(MSG_distmedium, tarstats.nselected, 1028 tarstats.nsuccess + tarstats.nskipped, 1029 dist->name); 1030 fetch_fn = NULL; 1031 process_menu(MENU_distmedium, &status); 1032 } while (status == SET_RETRY); 1033 1034 if (status == SET_SKIP) { 1035 set_status[set] |= SET_SKIPPED; 1036 tarstats.nskipped++; 1037 continue; 1038 } 1039 if (status == SET_SKIP_GROUP) { 1040 skip_set(dist, status); 1041 continue; 1042 } 1043 if (status != SET_OK) { 1044 msg_display(failure_msg); 1045 process_menu(MENU_ok, NULL); 1046 return 1; 1047 } 1048 } 1049 1050 /* Try to extract this set */ 1051 status = extract_file(dist, update); 1052 if (status == SET_RETRY) 1053 dist--; 1054 } 1055 1056 if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) { 1057 msg_display(MSG_endtarok); 1058 /* Give user a chance to see the success message */ 1059 sleep(1); 1060 } else { 1061 /* We encountered errors. Let the user know. */ 1062 msg_display(MSG_endtar, 1063 tarstats.nselected, tarstats.nnotfound, tarstats.nskipped, 1064 tarstats.nfound, tarstats.nsuccess, tarstats.nerror); 1065 process_menu(MENU_ok, NULL); 1066 msg_clear(); 1067 } 1068 1069 /* 1070 * postinstall needs to be run after extracting all sets, because 1071 * otherwise /var/db/obsolete will only have current information 1072 * from the base, comp, and etc sets. 1073 */ 1074 if (update && (set_status[SET_ETC] & SET_INSTALLED)) { 1075 int oldsendmail; 1076 oldsendmail = run_program(RUN_DISPLAY | RUN_CHROOT | 1077 RUN_ERROR_OK | RUN_PROGRESS, 1078 "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf"); 1079 if (oldsendmail == 1) { 1080 msg_display(MSG_oldsendmail); 1081 process_menu(MENU_yesno, NULL); 1082 if (yesno) { 1083 run_program(RUN_DISPLAY | RUN_CHROOT, 1084 "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf"); 1085 } 1086 } 1087 run_program(RUN_DISPLAY | RUN_CHROOT, 1088 "/usr/sbin/postinstall -s /.sysinst -d / fix"); 1089 } 1090 1091 /* Configure the system */ 1092 if (set_status[SET_BASE] & SET_INSTALLED) 1093 run_makedev(); 1094 1095 if (!update) { 1096 /* Save keybard type */ 1097 save_kb_encoding(); 1098 1099 /* Other configuration. */ 1100 mnt_net_config(); 1101 } 1102 1103 /* Mounted dist dir? */ 1104 umount_mnt2(); 1105 1106 /* Install/Upgrade complete ... reboot or exit to script */ 1107 msg_display(success_msg); 1108 process_menu(MENU_ok, NULL); 1109 return 0; 1110} 1111 1112void 1113umount_mnt2(void) 1114{ 1115 if (!mnt2_mounted) 1116 return; 1117 run_program(RUN_SILENT, "/sbin/umount /mnt2"); 1118 mnt2_mounted = 0; 1119} 1120 1121 1122/* 1123 * Do a quick sanity check that the target can reboot. 1124 * return 1 if everything OK, 0 if there is a problem. 1125 * Uses a table of files we expect to find after a base install/upgrade. 1126 */ 1127 1128/* test flag and pathname to check for after unpacking. */ 1129struct check_table { unsigned int mode; const char *path;} checks[] = { 1130 { S_IFREG, "/netbsd" }, 1131 { S_IFDIR, "/etc" }, 1132 { S_IFREG, "/etc/fstab" }, 1133 { S_IFREG, "/sbin/init" }, 1134 { S_IFREG, "/bin/sh" }, 1135 { S_IFREG, "/etc/rc" }, 1136 { S_IFREG, "/etc/rc.subr" }, 1137 { S_IFREG, "/etc/rc.conf" }, 1138 { S_IFDIR, "/dev" }, 1139 { S_IFCHR, "/dev/console" }, 1140/* XXX check for rootdev in target /dev? */ 1141 { S_IFREG, "/etc/fstab" }, 1142 { S_IFREG, "/sbin/fsck" }, 1143 { S_IFREG, "/sbin/fsck_ffs" }, 1144 { S_IFREG, "/sbin/mount" }, 1145 { S_IFREG, "/sbin/mount_ffs" }, 1146 { S_IFREG, "/sbin/mount_nfs" }, 1147#if defined(DEBUG) || defined(DEBUG_CHECK) 1148 { S_IFREG, "/foo/bar" }, /* bad entry to exercise warning */ 1149#endif 1150 { 0, 0 } 1151 1152}; 1153 1154/* 1155 * Check target for a single file. 1156 */ 1157static int 1158check_for(unsigned int mode, const char *pathname) 1159{ 1160 int found; 1161 1162 found = (target_test(mode, pathname) == 0); 1163 if (found == 0) 1164 msg_display(MSG_rootmissing, pathname); 1165 return found; 1166} 1167 1168/* 1169 * Check that all the files in check_table are present in the 1170 * target root. Warn if not found. 1171 */ 1172int 1173sanity_check(void) 1174{ 1175 int target_ok = 1; 1176 struct check_table *p; 1177 1178 for (p = checks; p->path; p++) { 1179 target_ok = target_ok && check_for(p->mode, p->path); 1180 } 1181 if (target_ok) 1182 return 0; 1183 1184 /* Uh, oh. Something's missing. */ 1185 msg_display(MSG_badroot); 1186 process_menu(MENU_ok, NULL); 1187 return 1; 1188} 1189 1190/* 1191 * Some globals to pass things back from callbacks 1192 */ 1193static char zoneinfo_dir[STRSIZE]; 1194static int zonerootlen; 1195static char *tz_selected; /* timezonename (relative to share/zoneinfo */ 1196const char *tz_default; /* UTC, or whatever /etc/localtime points to */ 1197static char tz_env[STRSIZE]; 1198static int save_cursel, save_topline; 1199 1200/* 1201 * Callback from timezone menu 1202 */ 1203static int 1204set_tz_select(menudesc *m, void *arg) 1205{ 1206 time_t t; 1207 char *new; 1208 1209 if (m && strcmp(tz_selected, m->opts[m->cursel].opt_name) != 0) { 1210 /* Change the displayed timezone */ 1211 new = strdup(m->opts[m->cursel].opt_name); 1212 if (new == NULL) 1213 return 0; 1214 free(tz_selected); 1215 tz_selected = new; 1216 snprintf(tz_env, sizeof tz_env, "%.*s%s", 1217 zonerootlen, zoneinfo_dir, tz_selected); 1218 setenv("TZ", tz_env, 1); 1219 } 1220 if (m) 1221 /* Warp curser to 'Exit' line on menu */ 1222 m->cursel = -1; 1223 1224 /* Update displayed time */ 1225 t = time(NULL); 1226 msg_display(MSG_choose_timezone, 1227 tz_default, tz_selected, ctime(&t), localtime(&t)->tm_zone); 1228 return 0; 1229} 1230 1231static int 1232set_tz_back(menudesc *m, void *arg) 1233{ 1234 1235 zoneinfo_dir[zonerootlen] = 0; 1236 m->cursel = save_cursel; 1237 m->topline = save_topline; 1238 return 0; 1239} 1240 1241static int 1242set_tz_dir(menudesc *m, void *arg) 1243{ 1244 1245 strlcpy(zoneinfo_dir + zonerootlen, m->opts[m->cursel].opt_name, 1246 sizeof zoneinfo_dir - zonerootlen); 1247 save_cursel = m->cursel; 1248 save_topline = m->topline; 1249 m->cursel = 0; 1250 m->topline = 0; 1251 return 0; 1252} 1253 1254/* 1255 * Alarm-handler to update example-display 1256 */ 1257static void 1258/*ARGSUSED*/ 1259timezone_sig(int sig) 1260{ 1261 1262 set_tz_select(NULL, NULL); 1263 alarm(60); 1264} 1265 1266static int 1267tz_sort(const void *a, const void *b) 1268{ 1269 return strcmp(((const menu_ent *)a)->opt_name, ((const menu_ent *)b)->opt_name); 1270} 1271 1272static void 1273tzm_set_names(menudesc *m, void *arg) 1274{ 1275 DIR *dir; 1276 struct dirent *dp; 1277 static int nfiles; 1278 static int maxfiles = 32; 1279 static menu_ent *tz_menu; 1280 static char **tz_names; 1281 void *p; 1282 int maxfname; 1283 char *fp; 1284 struct stat sb; 1285 1286 if (tz_menu == NULL) 1287 tz_menu = malloc(maxfiles * sizeof *tz_menu); 1288 if (tz_names == NULL) 1289 tz_names = malloc(maxfiles * sizeof *tz_names); 1290 if (tz_menu == NULL || tz_names == NULL) 1291 return; /* error - skip timezone setting */ 1292 while (nfiles > 0) 1293 free(tz_names[--nfiles]); 1294 1295 dir = opendir(zoneinfo_dir); 1296 fp = strchr(zoneinfo_dir, 0); 1297 if (fp != zoneinfo_dir + zonerootlen) { 1298 tz_names[0] = 0; 1299 tz_menu[0].opt_name = msg_string(MSG_tz_back); 1300 tz_menu[0].opt_menu = OPT_NOMENU; 1301 tz_menu[0].opt_flags = 0; 1302 tz_menu[0].opt_action = set_tz_back; 1303 nfiles = 1; 1304 } 1305 maxfname = zoneinfo_dir + sizeof zoneinfo_dir - fp - 1; 1306 if (dir != NULL) { 1307 while ((dp = readdir(dir)) != NULL) { 1308 if (dp->d_namlen > maxfname || dp->d_name[0] == '.') 1309 continue; 1310 strlcpy(fp, dp->d_name, maxfname); 1311 if (stat(zoneinfo_dir, &sb) == -1) 1312 continue; 1313 if (nfiles >= maxfiles) { 1314 p = realloc(tz_menu, 2 * maxfiles * sizeof *tz_menu); 1315 if (p == NULL) 1316 break; 1317 tz_menu = p; 1318 p = realloc(tz_names, 2 * maxfiles * sizeof *tz_names); 1319 if (p == NULL) 1320 break; 1321 tz_names = p; 1322 maxfiles *= 2; 1323 } 1324 if (S_ISREG(sb.st_mode)) 1325 tz_menu[nfiles].opt_action = set_tz_select; 1326 else if (S_ISDIR(sb.st_mode)) { 1327 tz_menu[nfiles].opt_action = set_tz_dir; 1328 strlcat(fp, "/", 1329 sizeof(zoneinfo_dir) - (fp - zoneinfo_dir)); 1330 } else 1331 continue; 1332 tz_names[nfiles] = strdup(zoneinfo_dir + zonerootlen); 1333 tz_menu[nfiles].opt_name = tz_names[nfiles]; 1334 tz_menu[nfiles].opt_menu = OPT_NOMENU; 1335 tz_menu[nfiles].opt_flags = 0; 1336 nfiles++; 1337 } 1338 closedir(dir); 1339 } 1340 *fp = 0; 1341 1342 m->opts = tz_menu; 1343 m->numopts = nfiles; 1344 qsort(tz_menu, nfiles, sizeof *tz_menu, tz_sort); 1345} 1346 1347void 1348get_tz_default(void) 1349{ 1350 char localtime_link[STRSIZE]; 1351 static char localtime_target[STRSIZE]; 1352 int rc; 1353 1354 strlcpy(localtime_link, target_expand("/etc/localtime"), 1355 sizeof localtime_link); 1356 1357 /* Add sanity check that /mnt/usr/share/zoneinfo contains 1358 * something useful 1359 */ 1360 1361 rc = readlink(localtime_link, localtime_target, 1362 sizeof(localtime_target) - 1); 1363 if (rc < 0) { 1364 /* error, default to UTC */ 1365 tz_default = "UTC"; 1366 } else { 1367 localtime_target[rc] = '\0'; 1368 tz_default = strchr(strstr(localtime_target, "zoneinfo"), '/') + 1; 1369 } 1370} 1371 1372/* 1373 * Choose from the files in usr/share/zoneinfo and set etc/localtime 1374 */ 1375int 1376set_timezone(void) 1377{ 1378 char localtime_link[STRSIZE]; 1379 char localtime_target[STRSIZE]; 1380 time_t t; 1381 int menu_no; 1382 1383 strlcpy(zoneinfo_dir, target_expand("/usr/share/zoneinfo/"), 1384 sizeof zoneinfo_dir - 1); 1385 zonerootlen = strlen(zoneinfo_dir); 1386 1387 get_tz_default(); 1388 1389 tz_selected = strdup(tz_default); 1390 snprintf(tz_env, sizeof(tz_env), "%s%s", zoneinfo_dir, tz_selected); 1391 setenv("TZ", tz_env, 1); 1392 t = time(NULL); 1393 msg_display(MSG_choose_timezone, 1394 tz_default, tz_selected, ctime(&t), localtime(&t)->tm_zone); 1395 1396 signal(SIGALRM, timezone_sig); 1397 alarm(60); 1398 1399 menu_no = new_menu(NULL, NULL, 14, 23, 9, 1400 12, 32, MC_ALWAYS_SCROLL | MC_NOSHORTCUT, 1401 tzm_set_names, NULL, NULL, 1402 "\nPlease consult the install documents.", NULL); 1403 if (menu_no < 0) 1404 goto done; /* error - skip timezone setting */ 1405 1406 process_menu(menu_no, NULL); 1407 1408 free_menu(menu_no); 1409 1410 signal(SIGALRM, SIG_IGN); 1411 1412 snprintf(localtime_target, sizeof(localtime_target), 1413 "/usr/share/zoneinfo/%s", tz_selected); 1414 strlcpy(localtime_link, target_expand("/etc/localtime"), 1415 sizeof localtime_link); 1416 unlink(localtime_link); 1417 symlink(localtime_target, localtime_link); 1418 1419done: 1420 return 1; 1421} 1422 1423void 1424scripting_vfprintf(FILE *f, const char *fmt, va_list ap) 1425{ 1426 1427 if (f) 1428 (void)vfprintf(f, fmt, ap); 1429 if (script) 1430 (void)vfprintf(script, fmt, ap); 1431} 1432 1433void 1434scripting_fprintf(FILE *f, const char *fmt, ...) 1435{ 1436 va_list ap; 1437 1438 va_start(ap, fmt); 1439 scripting_vfprintf(f, fmt, ap); 1440 va_end(ap); 1441} 1442 1443void 1444add_rc_conf(const char *fmt, ...) 1445{ 1446 FILE *f; 1447 va_list ap; 1448 1449 va_start(ap, fmt); 1450 f = target_fopen("/etc/rc.conf", "a"); 1451 if (f != 0) { 1452 scripting_fprintf(NULL, "cat <<EOF >>%s/etc/rc.conf\n", 1453 target_prefix()); 1454 scripting_vfprintf(f, fmt, ap); 1455 fclose(f); 1456 scripting_fprintf(NULL, "EOF\n"); 1457 } 1458 va_end(ap); 1459} 1460 1461int 1462del_rc_conf(const char *value) 1463{ 1464 FILE *fp, *nfp; 1465 char buf[4096]; /* Ridiculously high, but should be enough in any way */ 1466 char *rcconf, *tempname, *bakname; 1467 char *cp; 1468 int done = 0; 1469 int fd; 1470 int retval = 0; 1471 1472 /* The paths might seem strange, but using /tmp would require copy instead 1473 * of rename operations. */ 1474 if (asprintf(&rcconf, "%s", target_expand("/etc/rc.conf")) < 0 1475 || asprintf(&tempname, "%s", target_expand("/etc/rc.conf.tmp.XXXXXX")) < 0 1476 || asprintf(&bakname, "%s", target_expand("/etc/rc.conf.bak.XXXXXX")) < 0) { 1477 if (rcconf) 1478 free(rcconf); 1479 if (tempname) 1480 free(tempname); 1481 msg_display(MSG_rcconf_delete_failed, value); 1482 process_menu(MENU_ok, NULL); 1483 return -1; 1484 } 1485 1486 if ((fd = mkstemp(bakname)) < 0) { 1487 msg_display(MSG_rcconf_delete_failed, value); 1488 process_menu(MENU_ok, NULL); 1489 return -1; 1490 } 1491 close(fd); 1492 1493 if (!(fp = fopen(rcconf, "r+")) || (fd = mkstemp(tempname)) < 0) { 1494 if (fp) 1495 fclose(fp); 1496 msg_display(MSG_rcconf_delete_failed, value); 1497 process_menu(MENU_ok, NULL); 1498 return -1; 1499 } 1500 1501 nfp = fdopen(fd, "w"); 1502 if (!nfp) { 1503 fclose(fp); 1504 close(fd); 1505 msg_display(MSG_rcconf_delete_failed, value); 1506 process_menu(MENU_ok, NULL); 1507 return -1; 1508 } 1509 1510 while (fgets(buf, sizeof buf, fp) != NULL) { 1511 1512 cp = buf + strspn(buf, " \t"); /* Skip initial spaces */ 1513 if (strncmp(cp, value, strlen(value)) == 0) { 1514 cp += strlen(value); 1515 if (*cp != '=') 1516 scripting_fprintf(nfp, "%s", buf); 1517 else 1518 done = 1; 1519 } else { 1520 scripting_fprintf(nfp, "%s", buf); 1521 } 1522 } 1523 fclose(fp); 1524 fclose(nfp); 1525 1526 if (done) { 1527 if (rename(rcconf, bakname)) { 1528 msg_display(MSG_rcconf_backup_failed); 1529 process_menu(MENU_noyes, NULL); 1530 if (!yesno) { 1531 retval = -1; 1532 goto done; 1533 } 1534 } 1535 1536 if (rename(tempname, rcconf)) { 1537 if (rename(bakname, rcconf)) { 1538 msg_display(MSG_rcconf_restore_failed); 1539 process_menu(MENU_ok, NULL); 1540 } else { 1541 msg_display(MSG_rcconf_delete_failed, value); 1542 process_menu(MENU_ok, NULL); 1543 } 1544 } else { 1545 (void)unlink(bakname); 1546 } 1547 } 1548 1549done: 1550 (void)unlink(tempname); 1551 free(rcconf); 1552 free(tempname); 1553 free(bakname); 1554 return retval; 1555} 1556 1557void 1558add_sysctl_conf(const char *fmt, ...) 1559{ 1560 FILE *f; 1561 va_list ap; 1562 1563 va_start(ap, fmt); 1564 f = target_fopen("/etc/sysctl.conf", "a"); 1565 if (f != 0) { 1566 scripting_fprintf(NULL, "cat <<EOF >>%s/etc/sysctl.conf\n", 1567 target_prefix()); 1568 scripting_vfprintf(f, fmt, ap); 1569 fclose(f); 1570 scripting_fprintf(NULL, "EOF\n"); 1571 } 1572 va_end(ap); 1573} 1574 1575void 1576enable_rc_conf(void) 1577{ 1578 1579 replace("/etc/rc.conf", "s/^rc_configured=NO/rc_configured=YES/"); 1580} 1581 1582int 1583check_lfs_progs(void) 1584{ 1585 1586#ifndef NO_LFS 1587 return (access("/sbin/fsck_lfs", X_OK) == 0 && 1588 access("/sbin/mount_lfs", X_OK) == 0 && 1589 access("/sbin/newfs_lfs", X_OK) == 0); 1590#else 1591 return 0; 1592#endif 1593} 1594 1595int 1596set_is_source(const char *set_name) { 1597 int len = strlen(set_name); 1598 return len >= 3 && memcmp(set_name + len - 3, "src", 3) == 0; 1599} 1600 1601const char * 1602set_dir_for_set(const char *set_name) { 1603 if (strcmp(set_name, "pkgsrc") == 0) 1604 return pkgsrc_dir; 1605 return set_is_source(set_name) ? set_dir_src : set_dir_bin; 1606} 1607 1608const char * 1609ext_dir_for_set(const char *set_name) { 1610 if (strcmp(set_name, "pkgsrc") == 0) 1611 return ext_dir_pkgsrc; 1612 return set_is_source(set_name) ? ext_dir_src : ext_dir_bin; 1613} 1614 1615