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