Expand PMF_FN_* macros.
[netbsd-mini2440.git] / distrib / utils / sysinst / disks.c
blob2e5501393e2ae8b32ebad0dcd5f88bb224d5865f
1 /* $NetBSD: disks.c,v 1.109 2009/10/18 12:09:48 ahoka Exp $ */
3 /*
4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved.
7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
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:
19 * This product includes software developed for the NetBSD Project by
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.
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
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
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)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
39 /* disks.c -- routines to deal with finding disks and labeling disks. */
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <util.h>
49 #include <sys/param.h>
50 #include <sys/swap.h>
51 #include <ufs/ufs/dinode.h>
52 #include <ufs/ffs/fs.h>
53 #define FSTYPENAMES
54 #define MOUNTNAMES
55 #define static
56 #include <sys/disklabel.h>
57 #undef static
59 #include <dev/scsipi/scsipi_all.h>
60 #include <sys/scsiio.h>
62 #include <dev/ata/atareg.h>
63 #include <sys/ataio.h>
65 #include "defs.h"
66 #include "md.h"
67 #include "msg_defs.h"
68 #include "menu_defs.h"
69 #include "txtwalk.h"
71 /* Disk descriptions */
72 #define MAX_DISKS 15
73 struct disk_desc {
74 char dd_name[SSTRSIZE];
75 char dd_descr[70];
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;
84 /* Local prototypes */
85 static int foundffs(struct data *, size_t);
86 #ifdef USE_SYSVBFS
87 static int foundsysvbfs(struct data *, size_t);
88 #endif
89 static int fsck_preen(const char *, int, const char *);
90 static void fixsb(const char *, const char *, char);
92 #ifndef DISK_NAMES
93 #define DISK_NAMES "wd", "sd", "ld", "raid"
94 #endif
96 static const char *disk_names[] = { DISK_NAMES, "vnd", NULL };
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.
103 static void
104 ata_extract_string(char *buf, size_t bufmax,
105 uint8_t *bytes, unsigned numbytes,
106 int needswap)
108 unsigned i;
109 size_t j;
110 unsigned char ch1, ch2;
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;
118 if (j < bufmax-1) {
119 buf[j++] = ch1;
121 if (!needswap && j < bufmax-1) {
122 buf[j++] = ch2;
125 while (j > 0 && buf[j-1] == ' ') {
126 j--;
128 buf[j] = '\0';
132 * from src/sbin/scsictl/scsi_subr.c
134 #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
136 static void
137 scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen)
139 u_char *dst = (u_char *)sdst;
140 const u_char *src = (const u_char *)ssrc;
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;
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;
171 ++src, --slen;
174 *dst++ = 0;
178 static int
179 get_descr_scsi(struct disk_desc *dd, int fd)
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;
191 memset(&inqbuf, 0, sizeof(inqbuf));
192 memset(&cmd, 0, sizeof(cmd));
193 memset(&req, 0, sizeof(req));
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;
205 error = ioctl(fd, SCIOCCOMMAND, &req);
206 if (error == -1 || req.retsts != SCCMD_OK)
207 return 0;
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));
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);
220 snprintf(dd->dd_descr, sizeof(dd->dd_descr),
221 "%s (%s, %s %s)",
222 dd->dd_name, size, vendor, product);
224 return 1;
227 static int
228 get_descr_ata(struct disk_desc *dd, int fd)
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;
240 memset(&inbuf, 0, sizeof(inbuf));
241 memset(&req, 0, sizeof(req));
243 req.flags = ATACMD_READ;
244 req.command = WDCC_IDENTIFY;
245 req.databuf = (void *)&inbuf;
246 req.datalen = sizeof(inbuf);
247 req.timeout = 1000;
249 error = ioctl(fd, ATAIOCCOMMAND, &req);
250 if (error == -1 || req.retsts != ATACMD_OK)
251 return 0;
253 #if BYTE_ORDER == LITTLE_ENDIAN
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
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;
267 #endif
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);
275 snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)",
276 dd->dd_name, size, model);
278 return 1;
281 static void
282 get_descr(struct disk_desc *dd)
284 char diskpath[MAXPATHLEN];
285 int fd = -1;
287 fd = opendisk(dd->dd_name, O_RDONLY, diskpath, sizeof(diskpath), 0);
288 if (fd < 0)
289 goto done;
291 dd->dd_descr[0] = '\0';
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;
300 done:
301 if (fd >= 0)
302 close(fd);
303 if (strlen(dd->dd_descr) == 0)
304 strcpy(dd->dd_descr, dd->dd_name);
307 static int
308 get_disks(struct disk_desc *dd)
310 const char **xd;
311 char *cp;
312 struct disklabel l;
313 int i;
314 int numdisks;
316 /* initialize */
317 numdisks = 0;
319 for (xd = disk_names; *xd != NULL; xd++) {
320 for (i = 0; i < MAX_DISKS; i++) {
321 strlcpy(dd->dd_name, *xd, sizeof dd->dd_name - 2);
322 cp = strchr(dd->dd_name, ':');
323 if (cp != NULL)
324 dd->dd_no_mbr = !strcmp(cp, ":no_mbr");
325 else {
326 dd->dd_no_mbr = 0;
327 cp = strchr(dd->dd_name, 0);
330 snprintf(cp, 2 + 1, "%d", i);
331 if (!get_geom(dd->dd_name, &l)) {
332 if (errno == ENOENT)
333 break;
334 continue;
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;
341 get_descr(dd);
342 dd++;
343 numdisks++;
344 if (numdisks >= MAX_DISKS)
345 return numdisks;
348 return numdisks;
351 static int
352 set_dsk_select(menudesc *m, void *arg)
354 *(int *)arg = m->cursel;
355 return 1;
359 find_disks(const char *doingwhat)
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;
369 /* Find disks. */
370 numdisks = get_disks(disks);
372 /* need a redraw here, kernel messages hose everything */
373 touchwin(stdscr);
374 refresh();
375 /* Kill typeahead, it won't be what the user had in mind */
376 fpurge(stdin);
378 if (numdisks == 0) {
379 /* No disks found! */
380 msg_display(MSG_nodisk);
381 process_menu(MENU_ok, NULL);
382 /*endwin();*/
383 return -1;
386 if (numdisks == 1) {
387 /* One disk found! */
388 msg_display(MSG_onedisk, disks[0].dd_descr, doingwhat);
389 process_menu(MENU_ok, NULL);
390 } else {
391 /* Multiple disks found! */
392 for (i = 0; i < numdisks; i++) {
393 dsk_menu[i].opt_name = disks[i].dd_descr;
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;
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);
409 disk = disks + selected_disk;
410 strlcpy(diskdev, disk->dd_name, sizeof diskdev);
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);
415 sectorsize = disk->dd_secsize;
416 dlcyl = disk->dd_cyl;
417 dlhead = disk->dd_head;
418 dlsec = disk->dd_sec;
419 dlsize = disk->dd_totsec;
420 no_mbr = disk->dd_no_mbr;
421 if (dlsize == 0)
422 dlsize = disk->dd_cyl * disk->dd_head * disk->dd_sec;
423 if (dlsize > UINT32_MAX) {
424 msg_display(MSG_toobigdisklabel);
425 process_menu(MENU_ok, NULL);
426 return -1;
428 dlcylsize = dlhead * dlsec;
430 /* Get existing/default label */
431 memset(&oldlabel, 0, sizeof oldlabel);
432 incorelabel(diskdev, oldlabel);
434 /* Set 'target' label to current label in case we don't change it */
435 memcpy(&bsdlabel, &oldlabel, sizeof bsdlabel);
437 return numdisks;
440 void
441 fmt_fspart(menudesc *m, int ptn, void *arg)
443 unsigned int poffset, psize, pend;
444 const char *desc;
445 static const char *Yes, *No;
446 partinfo *p = bsdlabel + ptn;
448 if (Yes == NULL) {
449 Yes = msg_string(MSG_Yes);
450 No = msg_string(MSG_No);
453 poffset = p->pi_offset / sizemult;
454 psize = p->pi_size / sizemult;
455 if (psize == 0)
456 pend = 0;
457 else
458 pend = (p->pi_offset + p->pi_size) / sizemult - 1;
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];
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 {
475 if (ptn == PART_C)
476 desc = msg_string(MSG_NetBSD_partition_cant_change);
479 wprintw(m->mw, msg_string(MSG_fspart_row),
480 poffset, pend, psize, desc,
481 p->pi_flags & PIF_NEWFS ? Yes : "",
482 p->pi_flags & PIF_MOUNT ? Yes : "",
483 p->pi_mount);
487 * Label a disk using an MD-specific string DISKLABEL_CMD for
488 * to invoke disklabel.
489 * if MD code does not define DISKLABEL_CMD, this is a no-op.
491 * i386 port uses "/sbin/disklabel -w -r", just like i386
492 * miniroot scripts, though this may leave a bogus incore label.
494 * Sun ports should use DISKLABEL_CMD "/sbin/disklabel -w"
495 * to get incore to ondisk inode translation for the Sun proms.
498 write_disklabel (void)
501 #ifdef DISKLABEL_CMD
502 /* disklabel the disk */
503 return run_program(RUN_DISPLAY, "%s -f /tmp/disktab %s '%s'",
504 DISKLABEL_CMD, diskdev, bsddiskname);
505 #else
506 return 0;
507 #endif
511 static int
512 ptn_sort(const void *a, const void *b)
514 return strcmp(bsdlabel[*(const int *)a].pi_mount,
515 bsdlabel[*(const int *)b].pi_mount);
519 make_filesystems(void)
521 unsigned int i;
522 int ptn;
523 int ptn_order[nelem(bsdlabel)];
524 int error = 0;
525 unsigned int maxpart = getmaxpartitions();
526 char *newfs;
527 const char *mnt_opts;
528 const char *fsname;
529 partinfo *lbl;
531 if (maxpart > nelem(bsdlabel))
532 maxpart = nelem(bsdlabel);
534 /* Making new file systems and mounting them */
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);
541 for (i = 0; i < maxpart; i++) {
543 * newfs and mount. For now, process only BSD filesystems.
544 * but if this is the mounted-on root, has no mount
545 * point defined, or is marked preserve, don't touch it!
547 ptn = ptn_order[i];
548 lbl = bsdlabel + ptn;
550 if (is_active_rootpart(diskdev, ptn))
551 continue;
553 if (*lbl->pi_mount == 0)
554 /* No mount point */
555 continue;
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;
567 case FS_BSDFFS:
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);
573 if (lbl->pi_flags & PIF_LOG)
574 mnt_opts = "-tffs -o log";
575 else
576 mnt_opts = "-tffs -o async";
577 fsname = "ffs";
578 break;
579 case FS_BSDLFS:
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:
586 #ifdef USE_NEWFS_MSDOS
587 asprintf(&newfs, "/sbin/newfs_msdos");
588 #endif
589 mnt_opts = "-tmsdos";
590 fsname = "msdos";
591 break;
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
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
607 if (lbl->pi_flags & PIF_NEWFS && newfs != NULL) {
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;
623 } else
624 #endif
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);
631 free(newfs);
632 if (error != 0)
633 return error;
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;
647 return 0;
651 make_fstab(void)
653 FILE *f;
654 int i, swap_dev = -1;
655 const char *dump_dev;
657 /* Create the fstab. */
658 make_target_dir("/etc");
659 f = target_fopen("/etc/fstab", "w");
660 if (logging)
661 (void)fprintf(logfp,
662 "Creating %s/etc/fstab.\n", target_prefix());
663 scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
665 if (f == NULL) {
666 #ifndef DEBUG
667 msg_display(MSG_createfstab);
668 if (logging)
669 (void)fprintf(logfp, "Failed to make /etc/fstab!\n");
670 process_menu(MENU_ok, NULL);
671 return 1;
672 #else
673 f = stdout;
674 #endif
677 scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/"
678 "fstab/ for more examples.\n", target_prefix());
679 for (i = 0; i < getmaxpartitions(); i++) {
680 const char *s = "";
681 const char *mp = bsdlabel[i].pi_mount;
682 const char *fstype = "ffs";
683 int fsck_pass = 0, dump_freq = 0;
685 if (!*mp) {
687 * No mount point specified, comment out line and
688 * use /mnt as a placeholder for the mount point.
690 s = "# ";
691 mp = "/mnt";
694 switch (bsdlabel[i].pi_fstype) {
695 case FS_UNUSED:
696 continue;
697 case FS_BSDLFS:
698 /* If there is no LFS, just comment it out. */
699 if (!check_lfs_progs())
700 s = "# ";
701 fstype = "lfs";
702 /* FALLTHROUGH */
703 case FS_BSDFFS:
704 fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
705 dump_freq = 1;
706 break;
707 case FS_MSDOS:
708 fstype = "msdos";
709 break;
710 case FS_SWAP:
711 if (swap_dev == -1) {
712 swap_dev = i;
713 dump_dev = ",dp";
714 } else {
715 dump_dev ="";
717 scripting_fprintf(f, "/dev/%s%c\t\tnone\tswap\tsw%s\t\t 0 0\n",
718 diskdev, 'a' + i, dump_dev);
719 continue;
720 #ifdef USE_SYSVBFS
721 case FS_SYSVBFS:
722 fstype = "sysvbfs";
723 make_target_dir("/stand");
724 break;
725 #endif
726 default:
727 fstype = "???";
728 s = "# ";
729 break;
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 = "# ";
735 scripting_fprintf(f,
736 "%s/dev/%s%c\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
737 s, diskdev, 'a' + i, mp, fstype,
738 bsdlabel[i].pi_flags & PIF_LOG ? ",log" : "",
739 bsdlabel[i].pi_flags & PIF_MOUNT ? "" : ",noauto",
740 bsdlabel[i].pi_flags & PIF_ASYNC ? ",async" : "",
741 bsdlabel[i].pi_flags & PIF_NOATIME ? ",noatime" : "",
742 bsdlabel[i].pi_flags & PIF_NODEV ? ",nodev" : "",
743 bsdlabel[i].pi_flags & PIF_NODEVMTIME ? ",nodevmtime" : "",
744 bsdlabel[i].pi_flags & PIF_NOEXEC ? ",noexec" : "",
745 bsdlabel[i].pi_flags & PIF_NOSUID ? ",nosuid" : "",
746 dump_freq, fsck_pass);
749 if (tmp_ramdisk_size != 0) {
750 #ifdef HAVE_TMPFS
751 scripting_fprintf(f, "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,-s=%d\n",
752 tmp_ramdisk_size * 512);
753 #else
754 if (swap_dev != -1)
755 scripting_fprintf(f, "/dev/%s%c\t\t/tmp\tmfs\trw,-s=%d\n",
756 diskdev, 'a' + swap_dev, tmp_ramdisk_size);
757 else
758 scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%d\n",
759 tmp_ramdisk_size);
760 #endif
763 /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
764 scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
765 scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
766 scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
767 scripting_fprintf(f, "/dev/cd0a\t\t/cdrom\tcd9660\tro,noauto\n");
768 make_target_dir("/kern");
769 make_target_dir("/proc");
770 make_target_dir("/dev/pts");
771 make_target_dir("/cdrom");
773 scripting_fprintf(NULL, "EOF\n");
775 #ifndef DEBUG
776 fclose(f);
777 fflush(NULL);
778 #endif
779 return 0;
784 static int
785 /*ARGSUSED*/
786 foundffs(struct data *list, size_t num)
788 int error;
790 if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 ||
791 strstr(list[2].u.s_val, "noauto") != NULL)
792 return 0;
794 error = fsck_preen(list[0].u.s_val, ' '-'a', "ffs");
795 if (error != 0)
796 return error;
798 error = target_mount("", list[0].u.s_val, ' '-'a', list[1].u.s_val);
799 if (error != 0)
800 return error;
801 return 0;
804 #ifdef USE_SYSVBFS
805 static int
806 /*ARGSUSED*/
807 foundsysvbfs(struct data *list, size_t num)
809 int error;
811 if (num < 2 || strcmp(list[1].u.s_val, "/") == 0 ||
812 strstr(list[2].u.s_val, "noauto") != NULL)
813 return 0;
815 error = target_mount("", list[0].u.s_val, ' '-'a', list[1].u.s_val);
816 if (error != 0)
817 return error;
818 return 0;
820 #endif
823 * Do an fsck. On failure, inform the user by showing a warning
824 * message and doing menu_ok() before proceeding.
825 * Returns 0 on success, or nonzero return code from fsck() on failure.
827 static int
828 fsck_preen(const char *disk, int ptn, const char *fsname)
830 char *prog;
831 int error;
833 ptn += 'a';
834 if (fsname == NULL)
835 return 0;
836 /* first check fsck program exists, if not assue ok */
837 asprintf(&prog, "/sbin/fsck_%s", fsname);
838 if (prog == NULL)
839 return 0;
840 if (access(prog, X_OK) != 0)
841 return 0;
842 if (!strcmp(fsname,"ffs"))
843 fixsb(prog, disk, ptn);
844 error = run_program(0, "%s -p -q /dev/r%s%c", prog, disk, ptn);
845 free(prog);
846 if (error != 0) {
847 msg_display(MSG_badfs, disk, ptn, error);
848 process_menu(MENU_ok, NULL);
849 /* XXX at this point maybe we should run a full fsck? */
851 return error;
854 /* This performs the same function as the etc/rc.d/fixsb script
855 * which attempts to correct problems with ffs1 filesystems
856 * which may have been introduced by booting a netbsd-current kernel
857 * from between April of 2003 and January 2004. For more information
858 * This script was developed as a response to NetBSD pr install/25138
859 * Additional prs regarding the original issue include:
860 * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926
862 static void
863 fixsb(const char *prog, const char *disk, char ptn)
865 int fd;
866 int rval;
867 union {
868 struct fs fs;
869 char buf[SBLOCKSIZE];
870 } sblk;
871 struct fs *fs = &sblk.fs;
873 snprintf(sblk.buf, sizeof(sblk.buf), "/dev/r%s%c",
874 disk, ptn == ' ' ? 0 : ptn);
875 fd = open(sblk.buf, O_RDONLY);
876 if (fd == -1)
877 return;
879 /* Read ffsv1 main superblock */
880 rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1);
881 close(fd);
882 if (rval != sizeof sblk.buf)
883 return;
885 if (fs->fs_magic != FS_UFS1_MAGIC &&
886 fs->fs_magic != FS_UFS1_MAGIC_SWAPPED)
887 /* Not FFSv1 */
888 return;
889 if (fs->fs_old_flags & FS_FLAGS_UPDATED)
890 /* properly updated fslevel 4 */
891 return;
892 if (fs->fs_bsize != fs->fs_maxbsize)
893 /* not messed up */
894 return;
897 * OK we have a munged fs, first 'upgrade' to fslevel 4,
898 * We specify -b16 in order to stop fsck bleating that the
899 * sb doesn't match the first alternate.
901 run_program(RUN_DISPLAY | RUN_PROGRESS,
902 "%s -p -b 16 -c 4 /dev/r%s%c", prog, disk, ptn);
903 /* Then downgrade to fslevel 3 */
904 run_program(RUN_DISPLAY | RUN_PROGRESS,
905 "%s -p -c 3 /dev/r%s%c", prog, disk, ptn);
909 * fsck and mount the root partition.
911 static int
912 mount_root(void)
914 int error;
916 error = fsck_preen(diskdev, rootpart, "ffs");
917 if (error != 0)
918 return error;
920 /* Mount /dev/<diskdev>a on target's "".
921 * If we pass "" as mount-on, Prefixing will DTRT.
922 * for now, use no options.
923 * XXX consider -o remount in case target root is
924 * current root, still readonly from single-user?
926 return target_mount("", diskdev, rootpart, "");
929 /* Get information on the file systems mounted from the root filesystem.
930 * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD
931 * inodes. Fsck them. Mount them.
935 mount_disks(void)
937 char *fstab;
938 int fstabsize;
939 int error;
941 static struct lookfor fstabbuf[] = {
942 {"/dev/", "/dev/%s %s ffs %s", "c", NULL, 0, 0, foundffs},
943 {"/dev/", "/dev/%s %s ufs %s", "c", NULL, 0, 0, foundffs},
944 #ifdef USE_SYSVBFS
945 {"/dev/", "/dev/%s %s sysvbfs %s", "c", NULL, 0, 0,
946 foundsysvbfs},
947 #endif
949 static size_t numfstabbuf = sizeof(fstabbuf) / sizeof(struct lookfor);
951 /* First the root device. */
952 if (target_already_root())
953 /* avoid needing to call target_already_root() again */
954 targetroot_mnt[0] = 0;
955 else {
956 error = mount_root();
957 if (error != 0 && error != EBUSY)
958 return 0;
961 /* Check the target /etc/fstab exists before trying to parse it. */
962 if (target_dir_exists_p("/etc") == 0 ||
963 target_file_exists_p("/etc/fstab") == 0) {
964 msg_display(MSG_noetcfstab, diskdev);
965 process_menu(MENU_ok, NULL);
966 return 0;
970 /* Get fstab entries from the target-root /etc/fstab. */
971 fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab");
972 if (fstabsize < 0) {
973 /* error ! */
974 msg_display(MSG_badetcfstab, diskdev);
975 process_menu(MENU_ok, NULL);
976 return 0;
978 error = walk(fstab, (size_t)fstabsize, fstabbuf, numfstabbuf);
979 free(fstab);
981 return error;
985 set_swap(const char *disk, partinfo *pp)
987 int i;
988 char *cp;
989 int rval;
991 if (pp == NULL)
992 pp = oldlabel;
994 for (i = 0; i < MAXPARTITIONS; i++) {
995 if (pp[i].pi_fstype != FS_SWAP)
996 continue;
997 asprintf(&cp, "/dev/%s%c", disk, 'a' + i);
998 rval = swapctl(SWAP_ON, cp, 0);
999 free(cp);
1000 if (rval != 0)
1001 return -1;
1004 return 0;
1008 check_swap(const char *disk, int remove_swap)
1010 struct swapent *swap;
1011 char *cp;
1012 int nswap;
1013 int l;
1014 int rval = 0;
1016 nswap = swapctl(SWAP_NSWAP, 0, 0);
1017 if (nswap <= 0)
1018 return 0;
1020 swap = malloc(nswap * sizeof *swap);
1021 if (swap == NULL)
1022 return -1;
1024 nswap = swapctl(SWAP_STATS, swap, nswap);
1025 if (nswap < 0)
1026 goto bad_swap;
1028 l = strlen(disk);
1029 while (--nswap >= 0) {
1030 /* Should we check the se_dev or se_path? */
1031 cp = swap[nswap].se_path;
1032 if (memcmp(cp, "/dev/", 5) != 0)
1033 continue;
1034 if (memcmp(cp + 5, disk, l) != 0)
1035 continue;
1036 if (!isalpha(*(unsigned char *)(cp + 5 + l)))
1037 continue;
1038 if (cp[5 + l + 1] != 0)
1039 continue;
1040 /* ok path looks like it is for this device */
1041 if (!remove_swap) {
1042 /* count active swap areas */
1043 rval++;
1044 continue;
1046 if (swapctl(SWAP_OFF, cp, 0) == -1)
1047 rval = -1;
1050 done:
1051 free(swap);
1052 return rval;
1054 bad_swap:
1055 rval = -1;
1056 goto done;
1059 #ifdef HAVE_BOOTXX_xFS
1060 char *
1061 bootxx_name(void)
1063 int fstype;
1064 const char *bootxxname;
1065 char *bootxx;
1067 /* check we have boot code for the root partition type */
1068 fstype = bsdlabel[rootpart].pi_fstype;
1069 switch (fstype) {
1070 #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2)
1071 case FS_BSDFFS:
1072 if (bsdlabel[rootpart].pi_flags & PIF_FFSv2) {
1073 #ifdef BOOTXX_FFSV2
1074 bootxxname = BOOTXX_FFSV2;
1075 #else
1076 bootxxname = NULL;
1077 #endif
1078 } else {
1079 #ifdef BOOTXX_FFSV1
1080 bootxxname = BOOTXX_FFSV1;
1081 #else
1082 bootxxname = NULL;
1083 #endif
1085 break;
1086 #endif
1087 #ifdef BOOTXX_LFS
1088 case FS_BSDLFS:
1089 bootxxname = BOOTXX_LFS;
1090 break;
1091 #endif
1092 default:
1093 bootxxname = NULL;
1094 break;
1097 if (bootxxname == NULL)
1098 return NULL;
1100 asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname);
1101 return bootxx;
1103 #endif