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