Annotation of src/distrib/utils/sysinst/disks.c, Revision 1.108
1.108 ! martin 1: /* $NetBSD: disks.c,v 1.107 2009/10/01 10:41:03 jmcneill 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.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
1.27 cgd 19: * This product includes software developed for the NetBSD Project by
1.1 phil 20: * Piermont Information Systems Inc.
21: * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22: * or promote products derived from this software without specific prior
23: * written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1.51 dsl 28: * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1.1 phil 31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1.51 dsl 34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1.1 phil 35: * THE POSSIBILITY OF SUCH DAMAGE.
36: *
37: */
38:
39: /* disks.c -- routines to deal with finding disks and labeling disks. */
40:
41:
1.11 jonathan 42: #include <errno.h>
1.1 phil 43: #include <stdio.h>
44: #include <stdlib.h>
1.3 phil 45: #include <unistd.h>
46: #include <fcntl.h>
1.9 jonathan 47: #include <util.h>
1.3 phil 48:
49: #include <sys/param.h>
1.58 dsl 50: #include <sys/swap.h>
1.3 phil 51: #include <ufs/ufs/dinode.h>
52: #include <ufs/ffs/fs.h>
1.48 christos 53: #define FSTYPENAMES
1.74 dsl 54: #define MOUNTNAMES
1.49 christos 55: #define static
1.48 christos 56: #include <sys/disklabel.h>
1.49 christos 57: #undef static
1.3 phil 58:
1.106 jmcneill 59: #include <dev/scsipi/scsipi_all.h>
60: #include <sys/scsiio.h>
61:
62: #include <dev/ata/atareg.h>
63: #include <sys/ataio.h>
64:
1.1 phil 65: #include "defs.h"
1.6 phil 66: #include "md.h"
1.1 phil 67: #include "msg_defs.h"
68: #include "menu_defs.h"
69: #include "txtwalk.h"
70:
1.64 dsl 71: /* Disk descriptions */
72: #define MAX_DISKS 15
73: struct disk_desc {
1.85 dsl 74: char dd_name[SSTRSIZE];
1.106 jmcneill 75: char dd_descr[70];
1.85 dsl 76: uint dd_no_mbr;
77: uint dd_cyl;
78: uint dd_head;
79: uint dd_sec;
80: uint dd_secsize;
81: uint dd_totsec;
1.64 dsl 82: };
1.8 jonathan 83:
1.2 phil 84: /* Local prototypes */
1.74 dsl 85: static int foundffs(struct data *, size_t);
1.91 tsutsui 86: #ifdef USE_SYSVBFS
87: static int foundsysvbfs(struct data *, size_t);
88: #endif
1.74 dsl 89: static int fsck_preen(const char *, int, const char *);
1.82 dbj 90: static void fixsb(const char *, const char *, char);
1.11 jonathan 91:
1.52 dsl 92: #ifndef DISK_NAMES
1.88 tron 93: #define DISK_NAMES "wd", "sd", "ld", "raid"
1.52 dsl 94: #endif
95:
1.65 dsl 96: static const char *disk_names[] = { DISK_NAMES, "vnd", NULL };
1.8 jonathan 97:
1.106 jmcneill 98: /* from src/sbin/atactl/atactl.c
99: * extract_string: copy a block of bytes out of ataparams and make
100: * a proper string out of it, truncating trailing spaces and preserving
101: * strict typing. And also, not doing unaligned accesses.
102: */
103: static void
104: ata_extract_string(char *buf, size_t bufmax,
105: uint8_t *bytes, unsigned numbytes,
106: int needswap)
107: {
108: unsigned i;
109: size_t j;
110: unsigned char ch1, ch2;
111:
112: for (i = 0, j = 0; i < numbytes; i += 2) {
113: ch1 = bytes[i];
114: ch2 = bytes[i+1];
115: if (needswap && j < bufmax-1) {
116: buf[j++] = ch2;
117: }
118: if (j < bufmax-1) {
119: buf[j++] = ch1;
120: }
121: if (!needswap && j < bufmax-1) {
122: buf[j++] = ch2;
123: }
124: }
125: while (j > 0 && buf[j-1] == ' ') {
126: j--;
127: }
128: buf[j] = '\0';
129: }
130:
131: /*
132: * from src/sbin/scsictl/scsi_subr.c
133: */
134: #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
135:
136: static void
137: scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen)
138: {
139: u_char *dst = (u_char *)sdst;
140: const u_char *src = (const u_char *)ssrc;
141:
142: /* Trim leading and trailing blanks and NULs. */
143: while (slen > 0 && STRVIS_ISWHITE(src[0]))
144: ++src, --slen;
145: while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
146: --slen;
147:
148: while (slen > 0) {
149: if (*src < 0x20 || *src >= 0x80) {
150: /* non-printable characters */
151: dlen -= 4;
152: if (dlen < 1)
153: break;
154: *dst++ = '\\';
155: *dst++ = ((*src & 0300) >> 6) + '0';
156: *dst++ = ((*src & 0070) >> 3) + '0';
157: *dst++ = ((*src & 0007) >> 0) + '0';
158: } else if (*src == '\\') {
159: /* quote characters */
160: dlen -= 2;
161: if (dlen < 1)
162: break;
163: *dst++ = '\\';
164: *dst++ = '\\';
165: } else {
166: /* normal characters */
167: if (--dlen < 1)
168: break;
169: *dst++ = *src;
170: }
171: ++src, --slen;
172: }
173:
174: *dst++ = 0;
175: }
176:
177:
178: static int
179: get_descr_scsi(struct disk_desc *dd, int fd)
180: {
181: struct scsipi_inquiry_data inqbuf;
182: struct scsipi_inquiry cmd;
183: scsireq_t req;
184: /* x4 in case every character is escaped, +1 for NUL. */
185: char vendor[(sizeof(inqbuf.vendor) * 4) + 1],
186: product[(sizeof(inqbuf.product) * 4) + 1],
187: revision[(sizeof(inqbuf.revision) * 4) + 1];
188: char size[5];
189: int error;
190:
191: memset(&inqbuf, 0, sizeof(inqbuf));
192: memset(&cmd, 0, sizeof(cmd));
193: memset(&req, 0, sizeof(req));
194:
195: cmd.opcode = INQUIRY;
196: cmd.length = sizeof(inqbuf);
197: memcpy(req.cmd, &cmd, sizeof(cmd));
198: req.cmdlen = sizeof(cmd);
199: req.databuf = &inqbuf;
200: req.datalen = sizeof(inqbuf);
201: req.timeout = 10000;
202: req.flags = SCCMD_READ;
203: req.senselen = SENSEBUFLEN;
204:
205: error = ioctl(fd, SCIOCCOMMAND, &req);
206: if (error == -1 || req.retsts != SCCMD_OK)
207: return 0;
208:
209: scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor,
210: sizeof(inqbuf.vendor));
211: scsi_strvis(product, sizeof(product), inqbuf.product,
212: sizeof(inqbuf.product));
213: scsi_strvis(revision, sizeof(revision), inqbuf.revision,
214: sizeof(inqbuf.revision));
215:
216: humanize_number(size, sizeof(size),
217: (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
218: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
219:
220: snprintf(dd->dd_descr, sizeof(dd->dd_descr),
221: "%s (%s, %s %s)",
222: dd->dd_name, size, vendor, product);
223:
224: return 1;
225: }
226:
227: static int
228: get_descr_ata(struct disk_desc *dd, int fd)
229: {
230: struct atareq req;
231: static union {
232: unsigned char inbuf[DEV_BSIZE];
233: struct ataparams inqbuf;
234: } inbuf;
235: struct ataparams *inqbuf = &inbuf.inqbuf;
236: char model[sizeof(inqbuf->atap_model)+1];
237: char size[5];
238: int error, needswap = 0;
239:
240: memset(&inbuf, 0, sizeof(inbuf));
241: memset(&req, 0, sizeof(req));
242:
243: req.flags = ATACMD_READ;
244: req.command = WDCC_IDENTIFY;
245: req.databuf = (void *)&inbuf;
246: req.datalen = sizeof(inbuf);
247: req.timeout = 1000;
248:
249: error = ioctl(fd, ATAIOCCOMMAND, &req);
250: if (error == -1 || req.retsts != ATACMD_OK)
251: return 0;
252:
253: #if BYTE_ORDER == LITTLE_ENDIAN
254: /*
255: * On little endian machines, we need to shuffle the string
256: * byte order. However, we don't have to do this for NEC or
257: * Mitsumi ATAPI devices
258: */
259:
260: if (!((inqbuf->atap_config & WDC_CFG_ATAPI_MASK) == WDC_CFG_ATAPI &&
261: ((inqbuf->atap_model[0] == 'N' &&
262: inqbuf->atap_model[1] == 'E') ||
263: (inqbuf->atap_model[0] == 'F' &&
264: inqbuf->atap_model[1] == 'X')))) {
265: needswap = 1;
266: }
267: #endif
268:
269: ata_extract_string(model, sizeof(model),
270: inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap);
271: humanize_number(size, sizeof(size),
272: (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
273: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
274:
275: snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)",
276: dd->dd_name, size, model);
277:
278: return 1;
279: }
280:
281: static void
282: get_descr(struct disk_desc *dd)
283: {
284: char diskpath[MAXPATHLEN];
285: int fd = -1;
286:
287: fd = opendisk(dd->dd_name, O_RDONLY, diskpath, sizeof(diskpath), 0);
288: if (fd < 0)
289: goto done;
290:
1.107 jmcneill 291: dd->dd_descr[0] = '\0';
292:
1.106 jmcneill 293: /* try ATA */
294: if (get_descr_ata(dd, fd))
295: goto done;
296: /* try SCSI */
297: if (get_descr_scsi(dd, fd))
298: goto done;
299:
300: done:
301: if (fd >= 0)
302: close(fd);
303: if (strlen(dd->dd_descr) == 0)
304: strcpy(dd->dd_descr, dd->dd_name);
305: }
306:
1.64 dsl 307: static int
308: get_disks(struct disk_desc *dd)
1.4 phil 309: {
1.65 dsl 310: const char **xd;
1.85 dsl 311: char *cp;
1.4 phil 312: struct disklabel l;
313: int i;
1.64 dsl 314: int numdisks;
1.4 phil 315:
1.51 dsl 316: /* initialize */
317: numdisks = 0;
318:
319: for (xd = disk_names; *xd != NULL; xd++) {
320: for (i = 0; i < MAX_DISKS; i++) {
1.85 dsl 321: strlcpy(dd->dd_name, *xd, sizeof dd->dd_name - 2);
322: cp = strchr(dd->dd_name, ':');
323: if (cp != NULL)
1.92 dsl 324: dd->dd_no_mbr = !strcmp(cp, ":no_mbr");
1.86 cube 325: else {
326: dd->dd_no_mbr = 0;
1.85 dsl 327: cp = strchr(dd->dd_name, 0);
1.86 cube 328: }
1.85 dsl 329:
330: snprintf(cp, 2 + 1, "%d", i);
331: if (!get_geom(dd->dd_name, &l)) {
1.52 dsl 332: if (errno == ENOENT)
333: break;
1.51 dsl 334: continue;
1.52 dsl 335: }
1.51 dsl 336: dd->dd_cyl = l.d_ncylinders;
337: dd->dd_head = l.d_ntracks;
338: dd->dd_sec = l.d_nsectors;
339: dd->dd_secsize = l.d_secsize;
340: dd->dd_totsec = l.d_secperunit;
1.106 jmcneill 341: get_descr(dd);
1.51 dsl 342: dd++;
343: numdisks++;
344: if (numdisks >= MAX_DISKS)
1.64 dsl 345: return numdisks;
1.4 phil 346: }
1.3 phil 347: }
1.64 dsl 348: return numdisks;
1.3 phil 349: }
1.51 dsl 350:
1.64 dsl 351: static int
1.66 dsl 352: set_dsk_select(menudesc *m, void *arg)
1.64 dsl 353: {
354: *(int *)arg = m->cursel;
355: return 1;
356: }
1.3 phil 357:
1.38 mrg 358: int
1.61 dsl 359: find_disks(const char *doingwhat)
1.1 phil 360: {
1.64 dsl 361: struct disk_desc disks[MAX_DISKS];
362: menu_ent dsk_menu[nelem(disks)];
363: struct disk_desc *disk;
364: int i;
365: int numdisks;
366: int selected_disk = 0;
367: int menu_no;
1.1 phil 368:
1.4 phil 369: /* Find disks. */
1.64 dsl 370: numdisks = get_disks(disks);
1.1 phil 371:
1.20 garbled 372: /* need a redraw here, kernel messages hose everything */
373: touchwin(stdscr);
374: refresh();
1.94 dsl 375: /* Kill typeahead, it won't be what the user had in mind */
376: fpurge(stdin);
1.20 garbled 377:
1.1 phil 378: if (numdisks == 0) {
379: /* No disks found! */
1.23 fvdl 380: msg_display(MSG_nodisk);
1.53 dsl 381: process_menu(MENU_ok, NULL);
1.20 garbled 382: /*endwin();*/
1.1 phil 383: return -1;
1.51 dsl 384: }
385:
386: if (numdisks == 1) {
1.1 phil 387: /* One disk found! */
1.106 jmcneill 388: msg_display(MSG_onedisk, disks[0].dd_descr, doingwhat);
1.53 dsl 389: process_menu(MENU_ok, NULL);
1.1 phil 390: } else {
391: /* Multiple disks found! */
1.64 dsl 392: for (i = 0; i < numdisks; i++) {
1.106 jmcneill 393: dsk_menu[i].opt_name = disks[i].dd_descr;
1.64 dsl 394: dsk_menu[i].opt_menu = OPT_NOMENU;
395: dsk_menu[i].opt_flags = OPT_EXIT;
396: dsk_menu[i].opt_action = set_dsk_select;
397: }
398: menu_no = new_menu(MSG_Available_disks,
399: dsk_menu, numdisks, -1, 4, 0, 0,
400: MC_SCROLL | MC_NOEXITOPT,
401: NULL, NULL, NULL, NULL, NULL);
402: if (menu_no == -1)
403: return -1;
404: msg_display(MSG_ask_disk);
405: process_menu(menu_no, &selected_disk);
406: free_menu(menu_no);
1.1 phil 407: }
1.51 dsl 408:
1.64 dsl 409: disk = disks + selected_disk;
410: strlcpy(diskdev, disk->dd_name, sizeof diskdev);
1.3 phil 411:
1.92 dsl 412: /* Use as a default disk if the user has the sets on a local disk */
413: strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev);
414:
1.22 fvdl 415: sectorsize = disk->dd_secsize;
1.23 fvdl 416: dlcyl = disk->dd_cyl;
417: dlhead = disk->dd_head;
418: dlsec = disk->dd_sec;
419: dlsize = disk->dd_totsec;
1.85 dsl 420: no_mbr = disk->dd_no_mbr;
1.64 dsl 421: if (dlsize == 0)
422: dlsize = disk->dd_cyl * disk->dd_head * disk->dd_sec;
1.105 sborrill 423: if (dlsize > UINT32_MAX) {
424: msg_display(MSG_toobigdisklabel);
425: process_menu(MENU_ok, NULL);
426: return -1;
427: }
1.23 fvdl 428: dlcylsize = dlhead * dlsec;
1.1 phil 429:
1.62 dsl 430: /* Get existing/default label */
1.76 dsl 431: memset(&oldlabel, 0, sizeof oldlabel);
1.62 dsl 432: incorelabel(diskdev, oldlabel);
433:
1.75 dsl 434: /* Set 'target' label to current label in case we don't change it */
435: memcpy(&bsdlabel, &oldlabel, sizeof bsdlabel);
436:
1.1 phil 437: return numdisks;
438: }
439:
1.57 dsl 440: void
1.62 dsl 441: fmt_fspart(menudesc *m, int ptn, void *arg)
1.57 dsl 442: {
1.105 sborrill 443: unsigned int poffset, psize, pend;
1.57 dsl 444: const char *desc;
1.62 dsl 445: static const char *Yes, *No;
1.74 dsl 446: partinfo *p = bsdlabel + ptn;
1.62 dsl 447:
448: if (Yes == NULL) {
449: Yes = msg_string(MSG_Yes);
450: No = msg_string(MSG_No);
451: }
1.57 dsl 452:
1.74 dsl 453: poffset = p->pi_offset / sizemult;
454: psize = p->pi_size / sizemult;
1.57 dsl 455: if (psize == 0)
456: pend = 0;
457: else
1.74 dsl 458: pend = (p->pi_offset + p->pi_size) / sizemult - 1;
459:
460: if (p->pi_fstype == FS_BSDFFS)
461: if (p->pi_flags & PIF_FFSv2)
462: desc = "FFSv2";
463: else
464: desc = "FFSv1";
465: else
466: desc = fstypenames[p->pi_fstype];
1.57 dsl 467:
468: #ifdef PART_BOOT
469: if (ptn == PART_BOOT)
470: desc = msg_string(MSG_Boot_partition_cant_change);
471: #endif
472: if (ptn == getrawpartition())
473: desc = msg_string(MSG_Whole_disk_cant_change);
474: else {
1.74 dsl 475: if (ptn == PART_C)
1.57 dsl 476: desc = msg_string(MSG_NetBSD_partition_cant_change);
477: }
478:
1.62 dsl 479: wprintw(m->mw, msg_string(MSG_fspart_row),
480: poffset, pend, psize, desc,
1.74 dsl 481: p->pi_flags & PIF_NEWFS ? Yes : "",
482: p->pi_flags & PIF_MOUNT ? Yes : "",
483: p->pi_mount);
1.1 phil 484: }
485:
1.13 jonathan 486: /*
487: * Label a disk using an MD-specific string DISKLABEL_CMD for
1.60 dsl 488: * to invoke disklabel.
1.13 jonathan 489: * if MD code does not define DISKLABEL_CMD, this is a no-op.
490: *
1.60 dsl 491: * i386 port uses "/sbin/disklabel -w -r", just like i386
1.13 jonathan 492: * miniroot scripts, though this may leave a bogus incore label.
493: *
1.60 dsl 494: * Sun ports should use DISKLABEL_CMD "/sbin/disklabel -w"
495: * to get incore to ondisk inode translation for the Sun proms.
1.13 jonathan 496: */
1.38 mrg 497: int
498: write_disklabel (void)
1.1 phil 499: {
1.13 jonathan 500:
501: #ifdef DISKLABEL_CMD
1.1 phil 502: /* disklabel the disk */
1.74 dsl 503: return run_program(RUN_DISPLAY, "%s -f /tmp/disktab %s '%s'",
1.73 dsl 504: DISKLABEL_CMD, diskdev, bsddiskname);
1.48 christos 505: #else
506: return 0;
1.13 jonathan 507: #endif
1.1 phil 508: }
509:
1.62 dsl 510:
511: static int
512: ptn_sort(const void *a, const void *b)
513: {
1.65 dsl 514: return strcmp(bsdlabel[*(const int *)a].pi_mount,
515: bsdlabel[*(const int *)b].pi_mount);
1.62 dsl 516: }
517:
1.38 mrg 518: int
519: make_filesystems(void)
1.1 phil 520: {
521: int i;
1.62 dsl 522: int ptn;
523: int ptn_order[nelem(bsdlabel)];
1.74 dsl 524: int error = 0;
1.62 dsl 525: int maxpart = getmaxpartitions();
1.74 dsl 526: char *newfs;
527: const char *mnt_opts;
528: const char *fsname;
529: partinfo *lbl;
1.62 dsl 530:
531: if (maxpart > nelem(bsdlabel))
532: maxpart = nelem(bsdlabel);
533:
534: /* Making new file systems and mounting them */
535:
536: /* sort to ensure /usr/local is mounted after /usr (etc) */
537: for (i = 0; i < maxpart; i++)
538: ptn_order[i] = i;
539: qsort(ptn_order, maxpart, sizeof ptn_order[0], ptn_sort);
1.1 phil 540:
1.62 dsl 541: for (i = 0; i < maxpart; i++) {
1.9 jonathan 542: /*
1.51 dsl 543: * newfs and mount. For now, process only BSD filesystems.
1.40 mrg 544: * but if this is the mounted-on root, has no mount
1.51 dsl 545: * point defined, or is marked preserve, don't touch it!
1.9 jonathan 546: */
1.62 dsl 547: ptn = ptn_order[i];
1.74 dsl 548: lbl = bsdlabel + ptn;
549:
1.72 dsl 550: if (is_active_rootpart(diskdev, ptn))
551: continue;
1.1 phil 552:
1.74 dsl 553: if (*lbl->pi_mount == 0)
554: /* No mount point */
555: continue;
1.57 dsl 556:
1.74 dsl 557: newfs = NULL;
558: mnt_opts = NULL;
559: fsname = NULL;
560: switch (lbl->pi_fstype) {
561: case FS_APPLEUFS:
562: asprintf(&newfs, "/sbin/newfs %s%.0d",
563: lbl->pi_isize != 0 ? "-i" : "", lbl->pi_isize);
564: mnt_opts = "-tffs -o async";
565: fsname = "ffs";
566: break;
1.57 dsl 567: case FS_BSDFFS:
1.93 dsl 568: asprintf(&newfs,
569: "/sbin/newfs -V2 -O %d -b %d -f %d%s%.0d",
570: lbl->pi_flags & PIF_FFSv2 ? 2 : 1,
571: lbl->pi_fsize * lbl->pi_frag, lbl->pi_fsize,
572: lbl->pi_isize != 0 ? " -i " : "", lbl->pi_isize);
1.100 simonb 573: if (lbl->pi_flags & PIF_LOG)
574: mnt_opts = "-tffs -o log";
575: else
576: mnt_opts = "-tffs -o async";
1.74 dsl 577: fsname = "ffs";
1.57 dsl 578: break;
579: case FS_BSDLFS:
1.74 dsl 580: asprintf(&newfs, "/sbin/newfs_lfs -b %d",
581: lbl->pi_fsize * lbl->pi_frag);
582: mnt_opts = "-tlfs";
583: fsname = "lfs";
584: break;
585: case FS_MSDOS:
1.98 tsutsui 586: #ifdef USE_NEWFS_MSDOS
587: asprintf(&newfs, "/sbin/newfs_msdos");
588: #endif
1.74 dsl 589: mnt_opts = "-tmsdos";
590: fsname = "msdos";
1.57 dsl 591: break;
1.91 tsutsui 592: #ifdef USE_SYSVBFS
593: case FS_SYSVBFS:
594: asprintf(&newfs, "/sbin/newfs_sysvbfs");
595: mnt_opts = "-tsysvbfs";
596: fsname = "sysvbfs";
597: break;
598: #endif
1.99 tsutsui 599: #ifdef USE_EXT2FS
600: case FS_EX2FS:
601: asprintf(&newfs, "/sbin/newfs_ext2fs");
602: mnt_opts = "-text2fs";
603: fsname = "ext2fs";
604: break;
605: #endif
1.57 dsl 606: }
1.74 dsl 607: if (lbl->pi_flags & PIF_NEWFS && newfs != NULL) {
1.98 tsutsui 608: #ifdef USE_NEWFS_MSDOS
609: if (lbl->pi_fstype == FS_MSDOS) {
610: /* newfs only if mount fails */
611: if (run_program(RUN_SILENT | RUN_ERROR_OK,
612: "mount -rt msdos /dev/%s%c /mnt2",
613: diskdev, 'a' + ptn) != 0)
614: error = run_program(
615: RUN_DISPLAY | RUN_PROGRESS,
616: "%s /dev/r%s%c",
617: newfs, diskdev, 'a' + ptn);
618: else {
619: run_program(RUN_SILENT | RUN_ERROR_OK,
620: "umount /mnt2");
621: error = 0;
622: }
623: } else
624: #endif
1.74 dsl 625: error = run_program(RUN_DISPLAY | RUN_PROGRESS,
626: "%s /dev/r%s%c", newfs, diskdev, 'a' + ptn);
627: } else {
628: /* We'd better check it isn't dirty */
629: error = fsck_preen(diskdev, ptn, fsname);
630: }
631: free(newfs);
632: if (error != 0)
633: return error;
634:
635: if (lbl->pi_flags & PIF_MOUNT && mnt_opts != NULL) {
636: make_target_dir(lbl->pi_mount);
637: error = target_mount(mnt_opts, diskdev, ptn,
638: lbl->pi_mount);
639: if (error) {
640: msg_display(MSG_mountfail,
641: diskdev, 'a' + ptn, lbl->pi_mount);
642: process_menu(MENU_ok, NULL);
643: return error;
644: }
1.25 bouyer 645: }
1.9 jonathan 646: }
1.74 dsl 647: return 0;
1.1 phil 648: }
649:
1.38 mrg 650: int
651: make_fstab(void)
1.1 phil 652: {
653: FILE *f;
1.48 christos 654: int i, swap_dev = -1;
1.108 ! martin 655: const char *dump_dev;
1.1 phil 656:
657: /* Create the fstab. */
1.8 jonathan 658: make_target_dir("/etc");
1.23 fvdl 659: f = target_fopen("/etc/fstab", "w");
1.20 garbled 660: if (logging)
1.47 fvdl 661: (void)fprintf(logfp,
662: "Creating %s/etc/fstab.\n", target_prefix());
1.40 mrg 663: scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
1.20 garbled 664:
1.1 phil 665: if (f == NULL) {
666: #ifndef DEBUG
1.24 bouyer 667: msg_display(MSG_createfstab);
1.20 garbled 668: if (logging)
1.47 fvdl 669: (void)fprintf(logfp, "Failed to make /etc/fstab!\n");
1.53 dsl 670: process_menu(MENU_ok, NULL);
1.25 bouyer 671: return 1;
1.1 phil 672: #else
673: f = stdout;
1.51 dsl 674: #endif
1.1 phil 675: }
1.40 mrg 676:
1.90 christos 677: scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/"
678: "fstab/ for more examples.\n", target_prefix());
1.57 dsl 679: for (i = 0; i < getmaxpartitions(); i++) {
680: const char *s = "";
681: const char *mp = bsdlabel[i].pi_mount;
682: const char *fstype = "ffs";
1.69 dsl 683: int fsck_pass = 0, dump_freq = 0;
1.57 dsl 684:
685: if (!*mp) {
686: /*
687: * No mount point specified, comment out line and
688: * use /mnt as a placeholder for the mount point.
689: */
690: s = "# ";
691: mp = "/mnt";
692: }
693:
694: switch (bsdlabel[i].pi_fstype) {
1.69 dsl 695: case FS_UNUSED:
696: continue;
1.57 dsl 697: case FS_BSDLFS:
1.40 mrg 698: /* If there is no LFS, just comment it out. */
1.95 dsl 699: if (!check_lfs_progs())
1.57 dsl 700: s = "# ";
701: fstype = "lfs";
702: /* FALLTHROUGH */
703: case FS_BSDFFS:
1.74 dsl 704: fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
1.69 dsl 705: dump_freq = 1;
1.57 dsl 706: break;
707: case FS_MSDOS:
1.69 dsl 708: fstype = "msdos";
1.57 dsl 709: break;
710: case FS_SWAP:
1.108 ! martin 711: if (swap_dev == -1) {
1.48 christos 712: swap_dev = i;
1.108 ! martin 713: dump_dev = ",dp";
! 714: } else {
! 715: dump_dev ="";
! 716: }
! 717: scripting_fprintf(f, "/dev/%s%c\t\tnone\tswap\tsw%s\t\t 0 0\n",
! 718: diskdev, 'a' + i, dump_dev);
1.69 dsl 719: continue;
1.91 tsutsui 720: #ifdef USE_SYSVBFS
721: case FS_SYSVBFS:
722: fstype = "sysvbfs";
723: make_target_dir("/stand");
724: break;
725: #endif
1.69 dsl 726: default:
727: fstype = "???";
728: s = "# ";
1.57 dsl 729: break;
1.20 garbled 730: }
1.89 dsl 731: /* The code that remounts root rw doesn't check the partition */
732: if (strcmp(mp, "/") == 0 && !(bsdlabel[i].pi_flags & PIF_MOUNT))
733: s = "# ";
734:
1.100 simonb 735: scripting_fprintf(f,
1.101 ad 736: "%s/dev/%s%c\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
1.69 dsl 737: s, diskdev, 'a' + i, mp, fstype,
1.100 simonb 738: bsdlabel[i].pi_flags & PIF_LOG ? ",log" : "",
1.69 dsl 739: bsdlabel[i].pi_flags & PIF_MOUNT ? "" : ",noauto",
740: bsdlabel[i].pi_flags & PIF_ASYNC ? ",async" : "",
741: bsdlabel[i].pi_flags & PIF_NOATIME ? ",noatime" : "",
1.71 dsl 742: bsdlabel[i].pi_flags & PIF_NODEV ? ",nodev" : "",
1.69 dsl 743: bsdlabel[i].pi_flags & PIF_NODEVMTIME ? ",nodevmtime" : "",
1.71 dsl 744: bsdlabel[i].pi_flags & PIF_NOEXEC ? ",noexec" : "",
745: bsdlabel[i].pi_flags & PIF_NOSUID ? ",nosuid" : "",
1.69 dsl 746: dump_freq, fsck_pass);
1.57 dsl 747: }
748:
1.56 dsl 749: if (tmp_mfs_size != 0) {
1.48 christos 750: if (swap_dev != -1)
1.90 christos 751: scripting_fprintf(f, "/dev/%s%c\t\t/tmp\tmfs\trw,-s=%d\n",
1.56 dsl 752: diskdev, 'a' + swap_dev, tmp_mfs_size);
1.40 mrg 753: else
1.90 christos 754: scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%d\n",
1.68 skrll 755: tmp_mfs_size);
1.20 garbled 756: }
1.57 dsl 757:
1.96 xtraeme 758: /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
1.103 ad 759: scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
1.96 xtraeme 760: scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
1.102 ad 761: scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
1.97 hubertf 762: scripting_fprintf(f, "/dev/cd0a\t\t/cdrom\tcd9660\tro,noauto\n");
1.57 dsl 763: make_target_dir("/kern");
1.69 dsl 764: make_target_dir("/proc");
1.96 xtraeme 765: make_target_dir("/dev/pts");
1.97 hubertf 766: make_target_dir("/cdrom");
1.57 dsl 767:
1.40 mrg 768: scripting_fprintf(NULL, "EOF\n");
769:
1.1 phil 770: #ifndef DEBUG
771: fclose(f);
1.20 garbled 772: fflush(NULL);
1.1 phil 773: #endif
1.24 bouyer 774: return 0;
1.1 phil 775: }
1.14 jonathan 776:
1.40 mrg 777:
1.1 phil 778:
1.74 dsl 779: static int
1.48 christos 780: /*ARGSUSED*/
781: foundffs(struct data *list, size_t num)
1.3 phil 782: {
1.74 dsl 783: int error;
1.3 phil 784:
1.74 dsl 785: if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 ||
786: strstr(list[2].u.s_val, "noauto") != NULL)
787: return 0;
1.3 phil 788:
1.74 dsl 789: error = fsck_preen(list[0].u.s_val, ' '-'a', "ffs");
790: if (error != 0)
791: return error;
1.2 phil 792:
1.74 dsl 793: error = target_mount("", list[0].u.s_val, ' '-'a', list[1].u.s_val);
794: if (error != 0)
795: return error;
796: return 0;
1.2 phil 797: }
798:
1.91 tsutsui 799: #ifdef USE_SYSVBFS
800: static int
801: /*ARGSUSED*/
802: foundsysvbfs(struct data *list, size_t num)
803: {
804: int error;
805:
806: if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 ||
807: strstr(list[2].u.s_val, "noauto") != NULL)
808: return 0;
809:
810: error = target_mount("", list[0].u.s_val, ' '-'a', list[1].u.s_val);
811: if (error != 0)
812: return error;
813: return 0;
814: }
815: #endif
816:
1.11 jonathan 817: /*
1.81 dsl 818: * Do an fsck. On failure, inform the user by showing a warning
1.11 jonathan 819: * message and doing menu_ok() before proceeding.
1.74 dsl 820: * Returns 0 on success, or nonzero return code from fsck() on failure.
1.11 jonathan 821: */
1.74 dsl 822: static int
823: fsck_preen(const char *disk, int ptn, const char *fsname)
1.10 jonathan 824: {
1.74 dsl 825: char *prog;
1.40 mrg 826: int error;
1.74 dsl 827:
828: ptn += 'a';
829: if (fsname == NULL)
830: return 0;
831: /* first check fsck program exists, if not assue ok */
832: asprintf(&prog, "/sbin/fsck_%s", fsname);
833: if (prog == NULL)
834: return 0;
835: if (access(prog, X_OK) != 0)
836: return 0;
1.77 dbj 837: if (!strcmp(fsname,"ffs"))
1.82 dbj 838: fixsb(prog, disk, ptn);
1.74 dsl 839: error = run_program(0, "%s -p -q /dev/r%s%c", prog, disk, ptn);
840: free(prog);
841: if (error != 0) {
842: msg_display(MSG_badfs, disk, ptn, error);
1.53 dsl 843: process_menu(MENU_ok, NULL);
1.81 dsl 844: /* XXX at this point maybe we should run a full fsck? */
1.3 phil 845: }
1.11 jonathan 846: return error;
847: }
848:
1.82 dbj 849: /* This performs the same function as the etc/rc.d/fixsb script
850: * which attempts to correct problems with ffs1 filesystems
851: * which may have been introduced by booting a netbsd-current kernel
852: * from between April of 2003 and January 2004. For more information
853: * This script was developed as a response to NetBSD pr install/25138
854: * Additional prs regarding the original issue include:
855: * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926
1.81 dsl 856: */
1.77 dbj 857: static void
1.82 dbj 858: fixsb(const char *prog, const char *disk, char ptn)
1.77 dbj 859: {
860: int fd;
1.78 dbj 861: int rval;
1.82 dbj 862: union {
863: struct fs fs;
864: char buf[SBLOCKSIZE];
865: } sblk;
866: struct fs *fs = &sblk.fs;
867:
1.84 dsl 868: snprintf(sblk.buf, sizeof(sblk.buf), "/dev/r%s%c",
869: disk, ptn == ' ' ? 0 : ptn);
1.82 dbj 870: fd = open(sblk.buf, O_RDONLY);
1.77 dbj 871: if (fd == -1)
872: return;
1.81 dsl 873:
874: /* Read ffsv1 main superblock */
1.82 dbj 875: rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1);
1.77 dbj 876: close(fd);
1.82 dbj 877: if (rval != sizeof sblk.buf)
1.77 dbj 878: return;
879:
880: if (fs->fs_magic != FS_UFS1_MAGIC &&
881: fs->fs_magic != FS_UFS1_MAGIC_SWAPPED)
1.81 dsl 882: /* Not FFSv1 */
1.77 dbj 883: return;
884: if (fs->fs_old_flags & FS_FLAGS_UPDATED)
1.81 dsl 885: /* properly updated fslevel 4 */
1.77 dbj 886: return;
887: if (fs->fs_bsize != fs->fs_maxbsize)
1.81 dsl 888: /* not messed up */
1.77 dbj 889: return;
890:
1.81 dsl 891: /*
892: * OK we have a munged fs, first 'upgrade' to fslevel 4,
893: * We specify -b16 in order to stop fsck bleating that the
894: * sb doesn't match the first alternate.
895: */
1.82 dbj 896: run_program(RUN_DISPLAY | RUN_PROGRESS,
1.83 dbj 897: "%s -p -b 16 -c 4 /dev/r%s%c", prog, disk, ptn);
1.81 dsl 898: /* Then downgrade to fslevel 3 */
1.82 dbj 899: run_program(RUN_DISPLAY | RUN_PROGRESS,
900: "%s -p -c 3 /dev/r%s%c", prog, disk, ptn);
1.77 dbj 901: }
902:
1.11 jonathan 903: /*
904: * fsck and mount the root partition.
905: */
1.92 dsl 906: static int
1.74 dsl 907: mount_root(void)
1.11 jonathan 908: {
1.60 dsl 909: int error;
1.11 jonathan 910:
1.74 dsl 911: error = fsck_preen(diskdev, rootpart, "ffs");
1.11 jonathan 912: if (error != 0)
913: return error;
914:
1.60 dsl 915: /* Mount /dev/<diskdev>a on target's "".
1.51 dsl 916: * If we pass "" as mount-on, Prefixing will DTRT.
1.11 jonathan 917: * for now, use no options.
918: * XXX consider -o remount in case target root is
1.60 dsl 919: * current root, still readonly from single-user?
1.11 jonathan 920: */
1.74 dsl 921: return target_mount("", diskdev, rootpart, "");
922: }
1.11 jonathan 923:
1.74 dsl 924: /* Get information on the file systems mounted from the root filesystem.
925: * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD
926: * inodes. Fsck them. Mount them.
927: */
1.10 jonathan 928:
929: int
1.74 dsl 930: mount_disks(void)
1.59 dsl 931: {
932: char *fstab;
1.10 jonathan 933: int fstabsize;
1.11 jonathan 934: int error;
1.10 jonathan 935:
1.74 dsl 936: static struct lookfor fstabbuf[] = {
937: {"/dev/", "/dev/%s %s ffs %s", "c", NULL, 0, 0, foundffs},
938: {"/dev/", "/dev/%s %s ufs %s", "c", NULL, 0, 0, foundffs},
1.91 tsutsui 939: #ifdef USE_SYSVBFS
940: {"/dev/", "/dev/%s %s sysvbfs %s", "c", NULL, 0, 0,
941: foundsysvbfs},
942: #endif
1.74 dsl 943: };
944: static size_t numfstabbuf = sizeof(fstabbuf) / sizeof(struct lookfor);
945:
1.10 jonathan 946: /* First the root device. */
1.92 dsl 947: if (target_already_root())
948: /* avoid needing to call target_already_root() again */
949: targetroot_mnt[0] = 0;
950: else {
1.74 dsl 951: error = mount_root();
1.51 dsl 952: if (error != 0 && error != EBUSY)
1.10 jonathan 953: return 0;
1.2 phil 954: }
955:
1.11 jonathan 956: /* Check the target /etc/fstab exists before trying to parse it. */
1.51 dsl 957: if (target_dir_exists_p("/etc") == 0 ||
1.16 jonathan 958: target_file_exists_p("/etc/fstab") == 0) {
1.11 jonathan 959: msg_display(MSG_noetcfstab, diskdev);
1.53 dsl 960: process_menu(MENU_ok, NULL);
1.11 jonathan 961: return 0;
962: }
963:
964:
1.10 jonathan 965: /* Get fstab entries from the target-root /etc/fstab. */
1.23 fvdl 966: fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab");
1.2 phil 967: if (fstabsize < 0) {
968: /* error ! */
1.11 jonathan 969: msg_display(MSG_badetcfstab, diskdev);
1.53 dsl 970: process_menu(MENU_ok, NULL);
1.2 phil 971: return 0;
972: }
1.74 dsl 973: error = walk(fstab, (size_t)fstabsize, fstabbuf, numfstabbuf);
1.2 phil 974: free(fstab);
975:
1.74 dsl 976: return error;
1.32 fvdl 977: }
978:
979: int
1.65 dsl 980: set_swap(const char *disk, partinfo *pp)
1.32 fvdl 981: {
1.62 dsl 982: int i;
1.58 dsl 983: char *cp;
984: int rval;
1.32 fvdl 985:
1.62 dsl 986: if (pp == NULL)
987: pp = oldlabel;
1.32 fvdl 988:
1.62 dsl 989: for (i = 0; i < MAXPARTITIONS; i++) {
1.58 dsl 990: if (pp[i].pi_fstype != FS_SWAP)
991: continue;
1.65 dsl 992: asprintf(&cp, "/dev/%s%c", disk, 'a' + i);
1.58 dsl 993: rval = swapctl(SWAP_ON, cp, 0);
994: free(cp);
995: if (rval != 0)
996: return -1;
997: }
998:
999: return 0;
1000: }
1001:
1002: int
1.65 dsl 1003: check_swap(const char *disk, int remove_swap)
1.58 dsl 1004: {
1005: struct swapent *swap;
1006: char *cp;
1007: int nswap;
1008: int l;
1009: int rval = 0;
1010:
1011: nswap = swapctl(SWAP_NSWAP, 0, 0);
1012: if (nswap <= 0)
1013: return 0;
1014:
1015: swap = malloc(nswap * sizeof *swap);
1016: if (swap == NULL)
1017: return -1;
1018:
1019: nswap = swapctl(SWAP_STATS, swap, nswap);
1020: if (nswap < 0)
1021: goto bad_swap;
1022:
1.65 dsl 1023: l = strlen(disk);
1.58 dsl 1024: while (--nswap >= 0) {
1025: /* Should we check the se_dev or se_path? */
1026: cp = swap[nswap].se_path;
1027: if (memcmp(cp, "/dev/", 5) != 0)
1028: continue;
1.65 dsl 1029: if (memcmp(cp + 5, disk, l) != 0)
1.58 dsl 1030: continue;
1031: if (!isalpha(*(unsigned char *)(cp + 5 + l)))
1032: continue;
1033: if (cp[5 + l + 1] != 0)
1034: continue;
1035: /* ok path looks like it is for this device */
1.65 dsl 1036: if (!remove_swap) {
1.58 dsl 1037: /* count active swap areas */
1038: rval++;
1039: continue;
1.32 fvdl 1040: }
1.58 dsl 1041: if (swapctl(SWAP_OFF, cp, 0) == -1)
1042: rval = -1;
1.32 fvdl 1043: }
1044:
1.58 dsl 1045: done:
1046: free(swap);
1047: return rval;
1048:
1049: bad_swap:
1050: rval = -1;
1051: goto done;
1.1 phil 1052: }
1.104 tsutsui 1053:
1054: #ifdef HAVE_BOOTXX_xFS
1055: char *
1056: bootxx_name(void)
1057: {
1058: int fstype;
1059: const char *bootxxname;
1060: char *bootxx;
1061:
1062: /* check we have boot code for the root partition type */
1063: fstype = bsdlabel[rootpart].pi_fstype;
1064: switch (fstype) {
1065: #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2)
1066: case FS_BSDFFS:
1067: if (bsdlabel[rootpart].pi_flags & PIF_FFSv2) {
1068: #ifdef BOOTXX_FFSV2
1069: bootxxname = BOOTXX_FFSV2;
1070: #else
1071: bootxxname = NULL;
1072: #endif
1073: } else {
1074: #ifdef BOOTXX_FFSV1
1075: bootxxname = BOOTXX_FFSV1;
1076: #else
1077: bootxxname = NULL;
1078: #endif
1079: }
1080: break;
1081: #endif
1082: #ifdef BOOTXX_LFS
1083: case FS_BSDLFS:
1084: bootxxname = BOOTXX_LFS;
1085: break;
1086: #endif
1087: default:
1088: bootxxname = NULL;
1089: break;
1090: }
1091:
1092: if (bootxxname == NULL)
1093: return NULL;
1094:
1095: asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname);
1096: return bootxx;
1097: }
1098: #endif
CVSweb <webmaster@jp.NetBSD.org>