Annotation of src/usr.sbin/sysinst/disks.c, Revision 1.77
1.77 ! jmcneill 1: /* $NetBSD: disks.c,v 1.76 2021/08/21 11:55:26 andvar Exp $ */
1.1 dholland 2:
3: /*
4: * Copyright 1997 Piermont Information Systems Inc.
5: * All rights reserved.
6: *
7: * Written by Philip A. Nelson for Piermont Information Systems Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. The name of Piermont Information Systems Inc. may not be used to endorse
18: * or promote products derived from this software without specific prior
19: * written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
22: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
25: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31: * THE POSSIBILITY OF SUCH DAMAGE.
32: *
33: */
34:
35: /* disks.c -- routines to deal with finding disks and labeling disks. */
36:
37:
1.30 martin 38: #include <assert.h>
1.1 dholland 39: #include <errno.h>
1.17 martin 40: #include <inttypes.h>
1.1 dholland 41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <unistd.h>
44: #include <fcntl.h>
1.20 martin 45: #include <fnmatch.h>
1.1 dholland 46: #include <util.h>
1.2 martin 47: #include <uuid.h>
1.30 martin 48: #include <paths.h>
1.47 martin 49: #include <fstab.h>
1.1 dholland 50:
51: #include <sys/param.h>
52: #include <sys/sysctl.h>
53: #include <sys/swap.h>
1.30 martin 54: #include <sys/disklabel_gpt.h>
1.1 dholland 55: #include <ufs/ufs/dinode.h>
56: #include <ufs/ffs/fs.h>
57:
58: #include <dev/scsipi/scsipi_all.h>
59: #include <sys/scsiio.h>
60:
61: #include <dev/ata/atareg.h>
62: #include <sys/ataio.h>
63:
64: #include "defs.h"
65: #include "md.h"
66: #include "msg_defs.h"
67: #include "menu_defs.h"
68: #include "txtwalk.h"
69:
1.31 martin 70: /* #define DEBUG_VERBOSE 1 */
1.30 martin 71:
1.1 dholland 72: /* Disk descriptions */
73: struct disk_desc {
74: char dd_name[SSTRSIZE];
1.29 mrg 75: char dd_descr[256];
1.15 martin 76: bool dd_no_mbr, dd_no_part;
1.1 dholland 77: uint dd_cyl;
78: uint dd_head;
79: uint dd_sec;
80: uint dd_secsize;
1.30 martin 81: daddr_t dd_totsec;
1.2 martin 82: };
83:
1.47 martin 84: #define NAME_PREFIX "NAME="
85: static const char name_prefix[] = NAME_PREFIX;
86:
87: /* things we could have as /sbin/newfs_* and /sbin/fsck_* */
88: static const char *extern_fs_with_chk[] = {
89: "ext2fs", "lfs", "msdos", "v7fs"
90: };
91:
92: /* things we could have as /sbin/newfs_* but not /sbin/fsck_* */
93: static const char *extern_fs_newfs_only[] = {
94: "sysvbfs", "udf"
95: };
1.45 martin 96:
1.1 dholland 97: /* Local prototypes */
1.47 martin 98: static int found_fs(struct data *, size_t, const struct lookfor*);
99: static int found_fs_nocheck(struct data *, size_t, const struct lookfor*);
1.30 martin 100: static int fsck_preen(const char *, const char *, bool silent);
101: static void fixsb(const char *, const char *);
1.1 dholland 102:
103:
104: static bool tmpfs_on_var_shm(void);
105:
106: const char *
1.30 martin 107: getfslabelname(uint f, uint f_version)
1.1 dholland 108: {
1.30 martin 109: if (f == FS_TMPFS)
110: return "tmpfs";
111: else if (f == FS_MFS)
112: return "mfs";
113: else if (f == FS_BSDFFS && f_version > 0)
114: return f_version == 2 ?
115: msg_string(MSG_fs_type_ffsv2) : msg_string(MSG_fs_type_ffs);
1.58 martin 116: else if (f == FS_EX2FS && f_version == 1)
117: return msg_string(MSG_fs_type_ext2old);
1.30 martin 118: else if (f >= __arraycount(fstypenames) || fstypenames[f] == NULL)
1.1 dholland 119: return "invalid";
120: return fstypenames[f];
121: }
122:
123: /*
124: * Decide wether we want to mount a tmpfs on /var/shm: we do this always
125: * when the machine has more than 16 MB of user memory. On smaller machines,
126: * shm_open() and friends will not perform well anyway.
127: */
128: static bool
129: tmpfs_on_var_shm()
130: {
131: uint64_t ram;
132: size_t len;
133:
134: len = sizeof(ram);
135: if (sysctlbyname("hw.usermem64", &ram, &len, NULL, 0))
136: return false;
137:
1.28 martin 138: return ram > 16 * MEG;
1.1 dholland 139: }
140:
141: /* from src/sbin/atactl/atactl.c
142: * extract_string: copy a block of bytes out of ataparams and make
143: * a proper string out of it, truncating trailing spaces and preserving
144: * strict typing. And also, not doing unaligned accesses.
145: */
146: static void
147: ata_extract_string(char *buf, size_t bufmax,
148: uint8_t *bytes, unsigned numbytes,
149: int needswap)
150: {
151: unsigned i;
152: size_t j;
153: unsigned char ch1, ch2;
154:
155: for (i = 0, j = 0; i < numbytes; i += 2) {
156: ch1 = bytes[i];
157: ch2 = bytes[i+1];
158: if (needswap && j < bufmax-1) {
159: buf[j++] = ch2;
160: }
161: if (j < bufmax-1) {
162: buf[j++] = ch1;
163: }
164: if (!needswap && j < bufmax-1) {
165: buf[j++] = ch2;
166: }
167: }
168: while (j > 0 && buf[j-1] == ' ') {
169: j--;
170: }
171: buf[j] = '\0';
172: }
173:
174: /*
175: * from src/sbin/scsictl/scsi_subr.c
176: */
177: #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
178:
179: static void
180: scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen)
181: {
182: u_char *dst = (u_char *)sdst;
183: const u_char *src = (const u_char *)ssrc;
184:
185: /* Trim leading and trailing blanks and NULs. */
186: while (slen > 0 && STRVIS_ISWHITE(src[0]))
187: ++src, --slen;
188: while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
189: --slen;
190:
191: while (slen > 0) {
192: if (*src < 0x20 || *src >= 0x80) {
193: /* non-printable characters */
194: dlen -= 4;
195: if (dlen < 1)
196: break;
197: *dst++ = '\\';
198: *dst++ = ((*src & 0300) >> 6) + '0';
199: *dst++ = ((*src & 0070) >> 3) + '0';
200: *dst++ = ((*src & 0007) >> 0) + '0';
201: } else if (*src == '\\') {
202: /* quote characters */
203: dlen -= 2;
204: if (dlen < 1)
205: break;
206: *dst++ = '\\';
207: *dst++ = '\\';
208: } else {
209: /* normal characters */
210: if (--dlen < 1)
211: break;
212: *dst++ = *src;
213: }
214: ++src, --slen;
215: }
216:
217: *dst++ = 0;
218: }
219:
220:
221: static int
1.35 christos 222: get_descr_scsi(struct disk_desc *dd)
1.1 dholland 223: {
224: struct scsipi_inquiry_data inqbuf;
225: struct scsipi_inquiry cmd;
226: scsireq_t req;
227: /* x4 in case every character is escaped, +1 for NUL. */
228: char vendor[(sizeof(inqbuf.vendor) * 4) + 1],
229: product[(sizeof(inqbuf.product) * 4) + 1],
230: revision[(sizeof(inqbuf.revision) * 4) + 1];
231: char size[5];
232:
233: memset(&inqbuf, 0, sizeof(inqbuf));
234: memset(&cmd, 0, sizeof(cmd));
235: memset(&req, 0, sizeof(req));
236:
237: cmd.opcode = INQUIRY;
238: cmd.length = sizeof(inqbuf);
239: memcpy(req.cmd, &cmd, sizeof(cmd));
240: req.cmdlen = sizeof(cmd);
241: req.databuf = &inqbuf;
242: req.datalen = sizeof(inqbuf);
243: req.timeout = 10000;
244: req.flags = SCCMD_READ;
245: req.senselen = SENSEBUFLEN;
246:
1.35 christos 247: if (!disk_ioctl(dd->dd_name, SCIOCCOMMAND, &req)
248: || req.retsts != SCCMD_OK)
1.1 dholland 249: return 0;
250:
251: scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor,
252: sizeof(inqbuf.vendor));
253: scsi_strvis(product, sizeof(product), inqbuf.product,
254: sizeof(inqbuf.product));
255: scsi_strvis(revision, sizeof(revision), inqbuf.revision,
256: sizeof(inqbuf.revision));
257:
258: humanize_number(size, sizeof(size),
259: (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
260: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
261:
262: snprintf(dd->dd_descr, sizeof(dd->dd_descr),
263: "%s (%s, %s %s)",
264: dd->dd_name, size, vendor, product);
265:
266: return 1;
267: }
268:
269: static int
1.35 christos 270: get_descr_ata(struct disk_desc *dd)
1.1 dholland 271: {
272: struct atareq req;
273: static union {
274: unsigned char inbuf[DEV_BSIZE];
275: struct ataparams inqbuf;
276: } inbuf;
277: struct ataparams *inqbuf = &inbuf.inqbuf;
278: char model[sizeof(inqbuf->atap_model)+1];
279: char size[5];
1.35 christos 280: int needswap = 0;
1.1 dholland 281:
282: memset(&inbuf, 0, sizeof(inbuf));
283: memset(&req, 0, sizeof(req));
284:
285: req.flags = ATACMD_READ;
286: req.command = WDCC_IDENTIFY;
287: req.databuf = (void *)&inbuf;
288: req.datalen = sizeof(inbuf);
289: req.timeout = 1000;
290:
1.35 christos 291: if (!disk_ioctl(dd->dd_name, ATAIOCCOMMAND, &req)
292: || req.retsts != ATACMD_OK)
1.1 dholland 293: return 0;
294:
295: #if BYTE_ORDER == LITTLE_ENDIAN
296: /*
297: * On little endian machines, we need to shuffle the string
298: * byte order. However, we don't have to do this for NEC or
299: * Mitsumi ATAPI devices
300: */
301:
302: if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC &&
303: (inqbuf->atap_config & WDC_CFG_ATAPI) &&
304: ((inqbuf->atap_model[0] == 'N' &&
1.10 isaki 305: inqbuf->atap_model[1] == 'E') ||
1.1 dholland 306: (inqbuf->atap_model[0] == 'F' &&
1.10 isaki 307: inqbuf->atap_model[1] == 'X')))) {
1.1 dholland 308: needswap = 1;
309: }
310: #endif
311:
312: ata_extract_string(model, sizeof(model),
313: inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap);
314: humanize_number(size, sizeof(size),
315: (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
316: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
317:
318: snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)",
319: dd->dd_name, size, model);
320:
321: return 1;
322: }
323:
324: static void
325: get_descr(struct disk_desc *dd)
326: {
1.35 christos 327: char size[5];
1.1 dholland 328: dd->dd_descr[0] = '\0';
329:
330: /* try ATA */
1.35 christos 331: if (get_descr_ata(dd))
1.77 ! jmcneill 332: return;
1.1 dholland 333: /* try SCSI */
1.35 christos 334: if (get_descr_scsi(dd))
1.77 ! jmcneill 335: return;
1.30 martin 336:
337: /* XXX: identify for ld @ NVME or microSD */
338:
1.2 martin 339: /* XXX: get description from raid, cgd, vnd... */
1.77 ! jmcneill 340:
1.30 martin 341: /* punt, just give some generic info */
342: humanize_number(size, sizeof(size),
343: (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
344: "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
345:
346: snprintf(dd->dd_descr, sizeof(dd->dd_descr),
347: "%s (%s)", dd->dd_name, size);
1.1 dholland 348: }
349:
1.21 martin 350: /*
351: * State for helper callback for get_default_cdrom
352: */
353: struct default_cdrom_data {
354: char *device;
355: size_t max_len;
356: bool found;
357: };
358:
359: /*
360: * Helper function for get_default_cdrom, gets passed a device
361: * name and a void pointer to default_cdrom_data.
362: */
363: static bool
364: get_default_cdrom_helper(void *state, const char *dev)
365: {
366: struct default_cdrom_data *data = state;
367:
1.25 martin 368: if (!is_cdrom_device(dev, false))
1.22 martin 369: return true;
370:
1.21 martin 371: strlcpy(data->device, dev, data->max_len);
1.22 martin 372: strlcat(data->device, "a", data->max_len); /* default to partition a */
1.21 martin 373: data->found = true;
374:
375: return false; /* one is enough, stop iteration */
376: }
377:
378: /*
379: * Set the argument to the name of the first CD devices actually
380: * available, leave it unmodified otherwise.
381: * Return true if a device has been found.
1.1 dholland 382: */
1.18 martin 383: bool
384: get_default_cdrom(char *cd, size_t max_len)
1.1 dholland 385: {
1.21 martin 386: struct default_cdrom_data state;
387:
388: state.device = cd;
389: state.max_len = max_len;
390: state.found = false;
391:
392: if (enumerate_disks(&state, get_default_cdrom_helper))
393: return state.found;
394:
395: return false;
1.1 dholland 396: }
397:
1.30 martin 398: static bool
1.15 martin 399: get_wedge_descr(struct disk_desc *dd)
400: {
401: struct dkwedge_info dkw;
402:
1.35 christos 403: if (!get_wedge_info(dd->dd_name, &dkw))
1.30 martin 404: return false;
1.15 martin 405:
1.35 christos 406: snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s@%s)",
407: dkw.dkw_wname, dkw.dkw_devname, dkw.dkw_parent);
408: return true;
1.15 martin 409: }
410:
411: static bool
412: get_name_and_parent(const char *dev, char *name, char *parent)
413: {
414: struct dkwedge_info dkw;
415:
1.35 christos 416: if (!get_wedge_info(dev, &dkw))
1.15 martin 417: return false;
1.35 christos 418: strcpy(name, (const char *)dkw.dkw_wname);
419: strcpy(parent, dkw.dkw_parent);
420: return true;
1.15 martin 421: }
422:
423: static bool
424: find_swap_part_on(const char *dev, char *swap_name)
425: {
1.35 christos 426: struct dkwedge_list dkwl;
1.15 martin 427: struct dkwedge_info *dkw;
428: u_int i;
429: bool res = false;
430:
1.35 christos 431: if (!get_wedge_list(dev, &dkwl))
1.15 martin 432: return false;
433:
1.35 christos 434: dkw = dkwl.dkwl_buf;
1.15 martin 435: for (i = 0; i < dkwl.dkwl_nwedges; i++) {
436: res = strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) == 0;
437: if (res) {
438: strcpy(swap_name, (const char*)dkw[i].dkw_wname);
439: break;
440: }
441: }
1.35 christos 442: free(dkwl.dkwl_buf);
1.15 martin 443:
444: return res;
445: }
446:
447: static bool
448: is_ffs_wedge(const char *dev)
449: {
450: struct dkwedge_info dkw;
451:
1.35 christos 452: if (!get_wedge_info(dev, &dkw))
1.15 martin 453: return false;
454:
1.35 christos 455: return strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) == 0;
1.15 martin 456: }
457:
1.18 martin 458: /*
459: * Does this device match an entry in our default CDROM device list?
1.25 martin 460: * If looking for install targets, we also flag floopy devices.
1.18 martin 461: */
1.22 martin 462: bool
1.25 martin 463: is_cdrom_device(const char *dev, bool as_target)
1.18 martin 464: {
1.25 martin 465: static const char *target_devices[] = {
1.24 martin 466: #ifdef CD_NAMES
467: CD_NAMES
468: #endif
469: #if defined(CD_NAMES) && defined(FLOPPY_NAMES)
470: ,
471: #endif
472: #ifdef FLOPPY_NAMES
473: FLOPPY_NAMES
474: #endif
475: #if defined(CD_NAMES) || defined(FLOPPY_NAMES)
476: ,
477: #endif
478: 0
479: };
1.25 martin 480: static const char *src_devices[] = {
481: #ifdef CD_NAMES
482: CD_NAMES ,
483: #endif
484: 0
485: };
1.18 martin 486:
1.25 martin 487: for (const char **dev_pat = as_target ? target_devices : src_devices;
488: *dev_pat; dev_pat++)
1.20 martin 489: if (fnmatch(*dev_pat, dev, 0) == 0)
490: return true;
1.18 martin 491:
492: return false;
493: }
494:
1.27 martin 495: /* does this device match any entry in the driver list? */
496: static bool
497: dev_in_list(const char *dev, const char **list)
498: {
499:
500: for ( ; *list; list++) {
501:
502: size_t len = strlen(*list);
503:
504: /* start of name matches? */
505: if (strncmp(dev, *list, len) == 0) {
506: char *endp;
507: int e;
508:
509: /* remainder of name is a decimal number? */
510: strtou(dev+len, &endp, 10, 0, INT_MAX, &e);
511: if (endp && *endp == 0 && e == 0)
512: return true;
513: }
514: }
515:
516: return false;
517: }
518:
519: bool
520: is_bootable_device(const char *dev)
521: {
522: static const char *non_bootable_devs[] = {
523: "raid", /* bootcode lives outside of raid */
524: "xbd", /* xen virtual device, can not boot from that */
525: NULL
526: };
527:
528: return !dev_in_list(dev, non_bootable_devs);
529: }
530:
531: bool
532: is_partitionable_device(const char *dev)
533: {
534: static const char *non_partitionable_devs[] = {
1.42 msaitoh 535: "dk", /* this is already a partitioned slice */
1.27 martin 536: NULL
537: };
538:
539: return !dev_in_list(dev, non_partitionable_devs);
540: }
541:
1.18 martin 542: /*
543: * Multi-purpose helper function:
1.21 martin 544: * iterate all known disks, invoke a callback for each.
545: * Stop iteration when the callback returns false.
1.76 andvar 546: * Return true when iteration actually happened, false on error.
1.18 martin 547: */
1.22 martin 548: bool
1.21 martin 549: enumerate_disks(void *state, bool (*func)(void *state, const char *dev))
1.1 dholland 550: {
1.17 martin 551: static const int mib[] = { CTL_HW, HW_DISKNAMES };
552: static const unsigned int miblen = __arraycount(mib);
553: const char *xd;
1.21 martin 554: char *disk_names;
1.17 martin 555: size_t len;
1.1 dholland 556:
1.21 martin 557: if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1)
558: return false;
1.1 dholland 559:
1.17 martin 560: disk_names = malloc(len);
561: if (disk_names == NULL)
1.21 martin 562: return false;
1.17 martin 563:
564: if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) {
565: free(disk_names);
1.21 martin 566: return false;
1.17 martin 567: }
1.1 dholland 568:
1.17 martin 569: for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) {
1.21 martin 570: if (!(*func)(state, xd))
571: break;
572: }
573: free(disk_names);
574:
575: return true;
576: }
577:
578: /*
579: * Helper state for get_disks
580: */
581: struct get_disks_state {
582: int numdisks;
583: struct disk_desc *dd;
584: bool with_non_partitionable;
585: };
586:
587: /*
588: * Helper function for get_disks enumartion
589: */
590: static bool
591: get_disks_helper(void *arg, const char *dev)
592: {
593: struct get_disks_state *state = arg;
1.30 martin 594: struct disk_geom geo;
1.18 martin 595:
1.21 martin 596: /* is this a CD device? */
1.25 martin 597: if (is_cdrom_device(dev, true))
1.21 martin 598: return true;
599:
1.27 martin 600: memset(state->dd, 0, sizeof(*state->dd));
1.21 martin 601: strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2);
1.27 martin 602: state->dd->dd_no_mbr = !is_bootable_device(dev);
603: state->dd->dd_no_part = !is_partitionable_device(dev);
1.21 martin 604:
605: if (state->dd->dd_no_part && !state->with_non_partitionable)
606: return true;
1.1 dholland 607:
1.30 martin 608: if (!get_disk_geom(state->dd->dd_name, &geo)) {
1.21 martin 609: if (errno == ENOENT)
610: return true;
611: if (errno != ENOTTY || !state->dd->dd_no_part)
612: /*
613: * Allow plain partitions,
614: * like already existing wedges
615: * (like dk0) if marked as
616: * non-partitioning device.
617: * For all other cases, continue
618: * with the next disk.
619: */
620: return true;
621: if (!is_ffs_wedge(state->dd->dd_name))
622: return true;
623: }
1.1 dholland 624:
1.21 martin 625: /*
626: * Exclude a disk mounted as root partition,
627: * in case of install-image on a USB memstick.
628: */
1.23 martin 629: if (is_active_rootpart(state->dd->dd_name,
630: state->dd->dd_no_part ? -1 : 0))
1.21 martin 631: return true;
1.17 martin 632:
1.30 martin 633: state->dd->dd_cyl = geo.dg_ncylinders;
634: state->dd->dd_head = geo.dg_ntracks;
635: state->dd->dd_sec = geo.dg_nsectors;
636: state->dd->dd_secsize = geo.dg_secsize;
637: state->dd->dd_totsec = geo.dg_secperunit;
638:
639: if (!state->dd->dd_no_part || !get_wedge_descr(state->dd))
1.21 martin 640: get_descr(state->dd);
641: state->dd++;
642: state->numdisks++;
643: if (state->numdisks == MAX_DISKS)
644: return false;
645:
646: return true;
647: }
648:
649: /*
650: * Get all disk devices that are not CDs.
651: * Optionally leave out those that can not be partitioned further.
652: */
653: static int
654: get_disks(struct disk_desc *dd, bool with_non_partitionable)
655: {
656: struct get_disks_state state;
657:
658: /* initialize */
659: state.numdisks = 0;
660: state.dd = dd;
661: state.with_non_partitionable = with_non_partitionable;
662:
663: if (enumerate_disks(&state, get_disks_helper))
664: return state.numdisks;
665:
666: return 0;
1.1 dholland 667: }
668:
1.30 martin 669: #ifdef DEBUG_VERBOSE
670: static void
671: dump_parts(const struct disk_partitions *parts)
672: {
673: fprintf(stderr, "%s partitions on %s:\n",
674: MSG_XLAT(parts->pscheme->short_name), parts->disk);
675:
676: for (size_t p = 0; p < parts->num_part; p++) {
677: struct disk_part_info info;
678:
679: if (parts->pscheme->get_part_info(
680: parts, p, &info)) {
681: fprintf(stderr, " #%zu: start: %" PRIu64 " "
682: "size: %" PRIu64 ", flags: %x\n",
683: p, info.start, info.size,
684: info.flags);
685: if (info.nat_type)
686: fprintf(stderr, "\ttype: %s\n",
687: info.nat_type->description);
688: } else {
689: fprintf(stderr, "failed to get info "
690: "for partition #%zu\n", p);
691: }
692: }
1.72 rillig 693: fprintf(stderr, "%" PRIu64 " sectors free, disk size %" PRIu64
1.30 martin 694: " sectors, %zu partitions used\n", parts->free_space,
695: parts->disk_size, parts->num_part);
696: }
697: #endif
698:
699: static bool
700: delete_scheme(struct pm_devs *p)
701: {
702:
703: if (!ask_noyes(MSG_removepartswarn))
704: return false;
705:
706: p->parts->pscheme->free(p->parts);
707: p->parts = NULL;
708: return true;
709: }
710:
711:
712: static void
1.72 rillig 713: convert_copy(struct disk_partitions *old_parts,
1.30 martin 714: struct disk_partitions *new_parts)
715: {
716: struct disk_part_info oinfo, ninfo;
717: part_id i;
718:
719: for (i = 0; i < old_parts->num_part; i++) {
720: if (!old_parts->pscheme->get_part_info(old_parts, i, &oinfo))
721: continue;
722:
723: if (oinfo.flags & PTI_PSCHEME_INTERNAL)
724: continue;
725:
726: if (oinfo.flags & PTI_SEC_CONTAINER) {
727: if (old_parts->pscheme->secondary_partitions) {
728: struct disk_partitions *sec_part =
729: old_parts->pscheme->
730: secondary_partitions(
1.32 martin 731: old_parts, oinfo.start, false);
1.30 martin 732: if (sec_part)
733: convert_copy(sec_part, new_parts);
734: }
735: continue;
736: }
737:
738: if (!new_parts->pscheme->adapt_foreign_part_info(new_parts,
1.55 martin 739: &ninfo, old_parts->pscheme, &oinfo))
1.30 martin 740: continue;
741: new_parts->pscheme->add_partition(new_parts, &ninfo, NULL);
742: }
743: }
744:
745: bool
746: convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg)
747: {
748: struct disk_partitions *old_parts, *new_parts;
749: const struct disk_partitioning_scheme *new_scheme;
750:
751: *err_msg = NULL;
752:
753: old_parts = p->parts;
754: new_scheme = select_part_scheme(p, old_parts->pscheme,
755: false, MSG_select_other_partscheme);
756:
1.73 martin 757: if (new_scheme == NULL) {
758: if (err_msg)
759: *err_msg = INTERNAL_ERROR;
1.30 martin 760: return false;
1.73 martin 761: }
1.30 martin 762:
763: new_parts = new_scheme->create_new_for_disk(p->diskdev,
1.62 martin 764: 0, p->dlsize, is_boot_drive, NULL);
1.73 martin 765: if (new_parts == NULL) {
766: if (err_msg)
767: *err_msg = MSG_out_of_memory;
1.30 martin 768: return false;
1.73 martin 769: }
1.30 martin 770:
771: convert_copy(old_parts, new_parts);
772:
1.73 martin 773: if (new_parts->num_part == 0 && old_parts->num_part != 0) {
1.30 martin 774: /* need to cleanup */
775: new_parts->pscheme->free(new_parts);
776: return false;
777: }
778:
779: old_parts->pscheme->free(old_parts);
780: p->parts = new_parts;
781: return true;
782: }
783:
1.40 martin 784: static struct pm_devs *
785: dummy_whole_system_pm(void)
786: {
787: static struct pm_devs whole_system = {
788: .diskdev = "/",
789: .no_mbr = true,
790: .no_part = true,
791: .cur_system = true,
792: };
793: static bool init = false;
794:
795: if (!init) {
796: strlcpy(whole_system.diskdev_descr,
797: msg_string(MSG_running_system),
798: sizeof whole_system.diskdev_descr);
799: }
800:
801: return &whole_system;
802: }
803:
1.1 dholland 804: int
1.40 martin 805: find_disks(const char *doingwhat, bool allow_cur_system)
1.1 dholland 806: {
807: struct disk_desc disks[MAX_DISKS];
1.40 martin 808: /* need two more menu entries: current system + extended partitioning */
809: menu_ent dsk_menu[__arraycount(disks) + 2];
1.1 dholland 810: struct disk_desc *disk;
1.15 martin 811: int i = 0, skipped = 0;
812: int already_found, numdisks, selected_disk = -1;
1.1 dholland 813: int menu_no;
1.30 martin 814: struct pm_devs *pm_i, *pm_last = NULL;
815:
816: memset(dsk_menu, 0, sizeof(dsk_menu));
1.1 dholland 817:
818: /* Find disks. */
1.21 martin 819: numdisks = get_disks(disks, partman_go <= 0);
1.1 dholland 820:
821: /* need a redraw here, kernel messages hose everything */
822: touchwin(stdscr);
823: refresh();
824: /* Kill typeahead, it won't be what the user had in mind */
825: fpurge(stdin);
826:
1.10 isaki 827: /*
828: * partman_go: <0 - we want to see menu with extended partitioning
829: * ==0 - we want to see simple select disk menu
830: * >0 - we do not want to see any menus, just detect
831: * all disks
832: */
1.2 martin 833: if (partman_go <= 0) {
1.40 martin 834: if (numdisks == 0 && !allow_cur_system) {
1.2 martin 835: /* No disks found! */
1.30 martin 836: hit_enter_to_continue(MSG_nodisk, NULL);
1.2 martin 837: /*endwin();*/
838: return -1;
839: } else {
1.40 martin 840: /* One or more disks found or current system allowed */
841: i = 0;
842: if (allow_cur_system) {
843: dsk_menu[i].opt_name = MSG_running_system;
844: dsk_menu[i].opt_flags = OPT_EXIT;
845: dsk_menu[i].opt_action = set_menu_select;
846: i++;
847: }
1.43 martin 848: for (; i < numdisks+allow_cur_system; i++) {
1.15 martin 849: dsk_menu[i].opt_name =
1.40 martin 850: disks[i-allow_cur_system].dd_descr;
1.2 martin 851: dsk_menu[i].opt_flags = OPT_EXIT;
852: dsk_menu[i].opt_action = set_menu_select;
853: }
854: if (partman_go < 0) {
855: dsk_menu[i].opt_name = MSG_partman;
856: dsk_menu[i].opt_flags = OPT_EXIT;
857: dsk_menu[i].opt_action = set_menu_select;
1.40 martin 858: i++;
1.2 martin 859: }
860: menu_no = new_menu(MSG_Available_disks,
1.40 martin 861: dsk_menu, i, -1,
1.15 martin 862: 4, 0, 0, MC_SCROLL,
1.57 martin 863: NULL, NULL, NULL, NULL, MSG_exit_menu_generic);
1.2 martin 864: if (menu_no == -1)
865: return -1;
1.33 christos 866: msg_fmt_display(MSG_ask_disk, "%s", doingwhat);
1.2 martin 867: process_menu(menu_no, &selected_disk);
868: free_menu(menu_no);
1.40 martin 869: if (allow_cur_system) {
870: if (selected_disk == 0) {
871: pm = dummy_whole_system_pm();
872: return 1;
873: } else {
874: selected_disk--;
875: }
876: }
1.2 martin 877: }
878: if (partman_go < 0 && selected_disk == numdisks) {
879: partman_go = 1;
1.10 isaki 880: return -2;
1.2 martin 881: } else
882: partman_go = 0;
883: if (selected_disk < 0 || selected_disk >= numdisks)
1.10 isaki 884: return -1;
1.2 martin 885: }
886:
887: /* Fill pm struct with device(s) info */
888: for (i = 0; i < numdisks; i++) {
889: if (! partman_go)
890: disk = disks + selected_disk;
891: else {
892: disk = disks + i;
893: already_found = 0;
894: SLIST_FOREACH(pm_i, &pm_head, l) {
895: pm_last = pm_i;
1.44 martin 896: if (strcmp(pm_i->diskdev, disk->dd_name) == 0) {
897: already_found = 1;
1.2 martin 898: break;
899: }
900: }
1.44 martin 901: if (pm_i != NULL && already_found) {
902: /*
903: * We already added this device, but
904: * partitions might have changed
905: */
906: if (!pm_i->found) {
907: pm_i->found = true;
908: if (pm_i->parts == NULL) {
909: pm_i->parts =
910: partitions_read_disk(
911: pm_i->diskdev,
1.54 martin 912: disk->dd_totsec,
1.62 martin 913: disk->dd_secsize,
1.54 martin 914: disk->dd_no_mbr);
1.44 martin 915: }
916: }
1.2 martin 917: continue;
1.44 martin 918: }
1.1 dholland 919: }
1.2 martin 920: pm = pm_new;
921: pm->found = 1;
1.30 martin 922: pm->ptstart = 0;
923: pm->ptsize = 0;
1.2 martin 924: strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev);
925: strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr);
926: /* Use as a default disk if the user has the sets on a local disk */
927: strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev);
928:
1.30 martin 929: /*
930: * Init disk size and geometry
931: */
932: pm->sectorsize = disk->dd_secsize;
933: pm->dlcyl = disk->dd_cyl;
934: pm->dlhead = disk->dd_head;
935: pm->dlsec = disk->dd_sec;
936: pm->dlsize = disk->dd_totsec;
937: if (pm->dlsize == 0)
1.62 martin 938: pm->dlsize =
939: disk->dd_cyl * disk->dd_head * disk->dd_sec;
1.30 martin 940:
1.54 martin 941: pm->parts = partitions_read_disk(pm->diskdev,
1.62 martin 942: pm->dlsize, disk->dd_secsize, disk->dd_no_mbr);
1.30 martin 943:
944: again:
945:
946: #ifdef DEBUG_VERBOSE
947: if (pm->parts) {
948: fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr);
949: dump_parts(pm->parts);
950:
951: if (pm->parts->pscheme->secondary_partitions) {
952: const struct disk_partitions *sparts =
953: pm->parts->pscheme->secondary_partitions(
1.32 martin 954: pm->parts, pm->ptstart, false);
1.30 martin 955: if (sparts != NULL)
956: dump_parts(sparts);
957: }
958: }
959: #endif
960:
961: pm->no_mbr = disk->dd_no_mbr;
1.15 martin 962: pm->no_part = disk->dd_no_part;
963: if (!pm->no_part) {
964: pm->sectorsize = disk->dd_secsize;
965: pm->dlcyl = disk->dd_cyl;
966: pm->dlhead = disk->dd_head;
967: pm->dlsec = disk->dd_sec;
968: pm->dlsize = disk->dd_totsec;
969: if (pm->dlsize == 0)
1.62 martin 970: pm->dlsize =
971: disk->dd_cyl * disk->dd_head * disk->dd_sec;
1.30 martin 972:
973: if (pm->parts && pm->parts->pscheme->size_limit != 0
974: && pm->dlsize > pm->parts->pscheme->size_limit
975: && ! partman_go) {
976:
977: char size[5], limit[5];
978:
979: humanize_number(size, sizeof(size),
1.62 martin 980: (uint64_t)pm->dlsize * pm->sectorsize,
1.30 martin 981: "", HN_AUTOSCALE, HN_B | HN_NOSPACE
982: | HN_DECIMAL);
983:
984: humanize_number(limit, sizeof(limit),
985: (uint64_t)pm->parts->pscheme->size_limit
986: * 512U,
987: "", HN_AUTOSCALE, HN_B | HN_NOSPACE
988: | HN_DECIMAL);
989:
1.15 martin 990: if (logfp)
1.30 martin 991: fprintf(logfp,
992: "disk %s: is too big (%" PRIu64
993: " blocks, %s), will be truncated\n",
994: pm->diskdev, pm->dlsize,
995: size);
996:
997: msg_display_subst(MSG_toobigdisklabel, 5,
998: pm->diskdev,
999: msg_string(pm->parts->pscheme->name),
1000: msg_string(pm->parts->pscheme->short_name),
1001: size, limit);
1002:
1003: int sel = -1;
1004: const char *err = NULL;
1005: process_menu(MENU_convertscheme, &sel);
1006: if (sel == 1) {
1007: if (!delete_scheme(pm)) {
1008: return -1;
1009: }
1010: goto again;
1011: } else if (sel == 2) {
1012: if (!convert_scheme(pm,
1013: partman_go < 0, &err)) {
1014: if (err != NULL)
1015: err_msg_win(err);
1016: return -1;
1017: }
1018: goto again;
1019: } else if (sel == 3) {
1020: return -1;
1021: }
1022: pm->dlsize = pm->parts->pscheme->size_limit;
1.15 martin 1023: }
1024: } else {
1025: pm->sectorsize = 0;
1026: pm->dlcyl = 0;
1027: pm->dlhead = 0;
1028: pm->dlsec = 0;
1029: pm->dlsize = 0;
1030: pm->no_mbr = 1;
1.2 martin 1031: }
1032: pm->dlcylsize = pm->dlhead * pm->dlsec;
1033:
1034: if (partman_go) {
1035: pm_getrefdev(pm_new);
1036: if (SLIST_EMPTY(&pm_head) || pm_last == NULL)
1037: SLIST_INSERT_HEAD(&pm_head, pm_new, l);
1038: else
1039: SLIST_INSERT_AFTER(pm_last, pm_new, l);
1.30 martin 1040: pm_new = malloc(sizeof (struct pm_devs));
1.2 martin 1041: memset(pm_new, 0, sizeof *pm_new);
1042: } else
1.30 martin 1043: /* We are not in partman and do not want to process
1044: * all devices, exit */
1.2 martin 1045: break;
1.1 dholland 1046: }
1047:
1.15 martin 1048: return numdisks-skipped;
1.2 martin 1049: }
1050:
1.30 martin 1051: static int
1052: sort_part_usage_by_mount(const void *a, const void *b)
1.2 martin 1053: {
1.30 martin 1054: const struct part_usage_info *pa = a, *pb = b;
1.15 martin 1055:
1.30 martin 1056: /* sort all real partitions by mount point */
1057: if ((pa->instflags & PUIINST_MOUNT) &&
1058: (pb->instflags & PUIINST_MOUNT))
1059: return strcmp(pa->mount, pb->mount);
1.15 martin 1060:
1.30 martin 1061: /* real partitions go first */
1062: if (pa->instflags & PUIINST_MOUNT)
1063: return -1;
1064: if (pb->instflags & PUIINST_MOUNT)
1065: return 1;
1.8 martin 1066:
1.30 martin 1067: /* arbitrary order for all other partitions */
1068: if (pa->type == PT_swap)
1069: return -1;
1070: if (pb->type == PT_swap)
1071: return 1;
1072: if (pa->type < pb->type)
1073: return -1;
1074: if (pa->type > pb->type)
1075: return 1;
1076: if (pa->cur_part_id < pb->cur_part_id)
1077: return -1;
1078: if (pa->cur_part_id > pb->cur_part_id)
1079: return 1;
1080: return (uintptr_t)a < (uintptr_t)b ? -1 : 1;
1.1 dholland 1081: }
1082:
1083: int
1.30 martin 1084: make_filesystems(struct install_partition_desc *install)
1.1 dholland 1085: {
1.30 martin 1086: int error = 0, partno = -1;
1.71 martin 1087: char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX],
1088: opts[200], opt[30];
1.30 martin 1089: size_t i;
1090: struct part_usage_info *ptn;
1091: struct disk_partitions *parts;
1092: const char *mnt_opts = NULL, *fsname = NULL;
1.1 dholland 1093:
1.40 martin 1094: if (pm->cur_system)
1095: return 1;
1096:
1.15 martin 1097: if (pm->no_part) {
1098: /* check if this target device already has a ffs */
1.30 martin 1099: snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev);
1100: error = fsck_preen(rdev, "ffs", true);
1.15 martin 1101: if (error) {
1102: if (!ask_noyes(MSG_No_filesystem_newfs))
1103: return EINVAL;
1104: error = run_program(RUN_DISPLAY | RUN_PROGRESS,
1.30 martin 1105: "/sbin/newfs -V2 -O2 %s", rdev);
1.15 martin 1106: }
1107:
1.37 martin 1108: md_pre_mount(install, 0);
1.15 martin 1109:
1110: make_target_dir("/");
1.30 martin 1111:
1112: snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev);
1.15 martin 1113: error = target_mount_do("-o async", devdev, "/");
1114: if (error) {
1.30 martin 1115: msg_display_subst(MSG_mountfail, 2, devdev, "/");
1116: hit_enter_to_continue(NULL, NULL);
1.15 martin 1117: }
1.30 martin 1118:
1.15 martin 1119: return error;
1120: }
1121:
1.1 dholland 1122: /* Making new file systems and mounting them */
1123:
1124: /* sort to ensure /usr/local is mounted after /usr (etc) */
1.30 martin 1125: qsort(install->infos, install->num, sizeof(*install->infos),
1126: sort_part_usage_by_mount);
1.1 dholland 1127:
1.30 martin 1128: for (i = 0; i < install->num; i++) {
1.1 dholland 1129: /*
1.68 martin 1130: * Newfs all file systems marked as needing this.
1.38 martin 1131: * Mount the ones that have a mountpoint in the target.
1.1 dholland 1132: */
1.30 martin 1133: ptn = &install->infos[i];
1134: parts = ptn->parts;
1.50 martin 1135: newfs = NULL;
1136: fsname = NULL;
1.1 dholland 1137:
1.46 martin 1138: if (ptn->size == 0 || parts == NULL|| ptn->type == PT_swap)
1.72 rillig 1139: continue;
1.1 dholland 1140:
1.30 martin 1141: if (parts->pscheme->get_part_device(parts, ptn->cur_part_id,
1.59 martin 1142: devdev, sizeof devdev, &partno, parent_device_only, false,
1143: false) && is_active_rootpart(devdev, partno))
1.30 martin 1144: continue;
1145:
1146: parts->pscheme->get_part_device(parts, ptn->cur_part_id,
1.59 martin 1147: devdev, sizeof devdev, &partno, plain_name, true, true);
1.30 martin 1148:
1149: parts->pscheme->get_part_device(parts, ptn->cur_part_id,
1.59 martin 1150: rdev, sizeof rdev, &partno, raw_dev_name, true, true);
1.2 martin 1151:
1.71 martin 1152: opts[0] = 0;
1.30 martin 1153: switch (ptn->fs_type) {
1.1 dholland 1154: case FS_APPLEUFS:
1.71 martin 1155: if (ptn->fs_opt3 != 0)
1156: snprintf(opts, sizeof opts, "-i %u",
1157: ptn->fs_opt3);
1158: asprintf(&newfs, "/sbin/newfs %s", opts);
1.30 martin 1159: mnt_opts = "-tffs -o async";
1160: fsname = "ffs";
1.1 dholland 1161: break;
1162: case FS_BSDFFS:
1.71 martin 1163: if (ptn->fs_opt3 != 0)
1164: snprintf(opts, sizeof opts, "-i %u ",
1165: ptn->fs_opt3);
1166: if (ptn->fs_opt1 != 0) {
1167: snprintf(opt, sizeof opt, "-b %u ",
1168: ptn->fs_opt1);
1169: strcat(opts, opt);
1170: }
1171: if (ptn->fs_opt2 != 0) {
1172: snprintf(opt, sizeof opt, "-f %u ",
1173: ptn->fs_opt2);
1174: strcat(opts, opt);
1175: }
1.1 dholland 1176: asprintf(&newfs,
1.71 martin 1177: "/sbin/newfs -V2 -O %d %s",
1178: ptn->fs_version == 2 ? 2 : 1, opts);
1.30 martin 1179: if (ptn->mountflags & PUIMNT_LOG)
1180: mnt_opts = "-tffs -o log";
1.1 dholland 1181: else
1.30 martin 1182: mnt_opts = "-tffs -o async";
1183: fsname = "ffs";
1.1 dholland 1184: break;
1185: case FS_BSDLFS:
1.71 martin 1186: if (ptn->fs_opt1 != 0 && ptn->fs_opt2 != 0)
1187: snprintf(opts, sizeof opts, "-b %u",
1188: ptn->fs_opt1 * ptn->fs_opt2);
1189: asprintf(&newfs, "/sbin/newfs_lfs %s", opts);
1.30 martin 1190: mnt_opts = "-tlfs";
1191: fsname = "lfs";
1.1 dholland 1192: break;
1193: case FS_MSDOS:
1194: asprintf(&newfs, "/sbin/newfs_msdos");
1.30 martin 1195: mnt_opts = "-tmsdos";
1196: fsname = "msdos";
1.1 dholland 1197: break;
1198: case FS_SYSVBFS:
1199: asprintf(&newfs, "/sbin/newfs_sysvbfs");
1.30 martin 1200: mnt_opts = "-tsysvbfs";
1201: fsname = "sysvbfs";
1.1 dholland 1202: break;
1.50 martin 1203: case FS_V7:
1204: asprintf(&newfs, "/sbin/newfs_v7fs");
1205: mnt_opts = "-tv7fs";
1206: fsname = "v7fs";
1207: break;
1.1 dholland 1208: case FS_EX2FS:
1.58 martin 1209: asprintf(&newfs,
1210: ptn->fs_version == 1 ?
1211: "/sbin/newfs_ext2fs -O 0" :
1212: "/sbin/newfs_ext2fs");
1.30 martin 1213: mnt_opts = "-text2fs";
1214: fsname = "ext2fs";
1.1 dholland 1215: break;
1216: }
1.30 martin 1217: if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) {
1.70 martin 1218: error = run_program(RUN_DISPLAY | RUN_PROGRESS,
1.30 martin 1219: "%s %s", newfs, rdev);
1.50 martin 1220: } else if ((ptn->instflags & (PUIINST_MOUNT|PUIINST_BOOT))
1221: && fsname != NULL) {
1.1 dholland 1222: /* We'd better check it isn't dirty */
1.30 martin 1223: error = fsck_preen(devdev, fsname, false);
1.1 dholland 1224: }
1225: free(newfs);
1.30 martin 1226: if (error != 0)
1.1 dholland 1227: return error;
1228:
1.30 martin 1229: ptn->instflags &= ~PUIINST_NEWFS;
1.37 martin 1230: md_pre_mount(install, i);
1.1 dholland 1231:
1.30 martin 1232: if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) &&
1233: mnt_opts != NULL) {
1234: make_target_dir(ptn->mount);
1235: error = target_mount_do(mnt_opts, devdev,
1236: ptn->mount);
1.1 dholland 1237: if (error) {
1.72 rillig 1238: msg_display_subst(MSG_mountfail, 2, devdev,
1.30 martin 1239: ptn->mount);
1240: hit_enter_to_continue(NULL, NULL);
1.1 dholland 1241: return error;
1242: }
1243: }
1244: }
1245: return 0;
1246: }
1247:
1248: int
1.30 martin 1249: make_fstab(struct install_partition_desc *install)
1.1 dholland 1250: {
1251: FILE *f;
1.30 martin 1252: const char *dump_dev = NULL;
1253: const char *dev;
1254: char dev_buf[PATH_MAX], swap_dev[PATH_MAX];
1255:
1.40 martin 1256: if (pm->cur_system)
1257: return 1;
1258:
1.30 martin 1259: swap_dev[0] = 0;
1.1 dholland 1260:
1261: /* Create the fstab. */
1262: make_target_dir("/etc");
1263: f = target_fopen("/etc/fstab", "w");
1.2 martin 1264: scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
1265:
1.1 dholland 1266: if (logfp)
1267: (void)fprintf(logfp,
1.30 martin 1268: "Making %s/etc/fstab (%s).\n", target_prefix(),
1269: pm->diskdev);
1.10 isaki 1270:
1.1 dholland 1271: if (f == NULL) {
1272: msg_display(MSG_createfstab);
1273: if (logfp)
1274: (void)fprintf(logfp, "Failed to make /etc/fstab!\n");
1.30 martin 1275: hit_enter_to_continue(NULL, NULL);
1.2 martin 1276: #ifndef DEBUG
1.1 dholland 1277: return 1;
1278: #else
1279: f = stdout;
1280: #endif
1281: }
1282:
1.16 martin 1283: scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/"
1284: "fstab/ for more examples.\n");
1.15 martin 1285:
1286: if (pm->no_part) {
1287: /* single dk? target */
1288: char buf[200], parent[200], swap[200], *prompt;
1289: int res;
1290:
1291: if (!get_name_and_parent(pm->diskdev, buf, parent))
1292: goto done_with_disks;
1.47 martin 1293: scripting_fprintf(f, NAME_PREFIX "%s\t/\tffs\trw\t\t1 1\n",
1.15 martin 1294: buf);
1295: if (!find_swap_part_on(parent, swap))
1296: goto done_with_disks;
1.30 martin 1297: const char *args[] = { parent, swap };
1298: prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part),
1299: __arraycount(args), args);
1.15 martin 1300: res = ask_yesno(prompt);
1301: free(prompt);
1302: if (res)
1.47 martin 1303: scripting_fprintf(f, NAME_PREFIX "%s\tnone"
1.15 martin 1304: "\tswap\tsw,dp\t\t0 0\n", swap);
1305: goto done_with_disks;
1306: }
1307:
1.30 martin 1308: for (size_t i = 0; i < install->num; i++) {
1309:
1310: const struct part_usage_info *ptn = &install->infos[i];
1311:
1.53 martin 1312: if (ptn->size == 0)
1313: continue;
1314:
1.60 martin 1315: bool is_tmpfs = ptn->type == PT_root &&
1316: ptn->fs_type == FS_TMPFS &&
1317: (ptn->flags & PUIFLG_JUST_MOUNTPOINT);
1318:
1319: if (!is_tmpfs && ptn->type != PT_swap &&
1.30 martin 1320: (ptn->instflags & PUIINST_MOUNT) == 0)
1321: continue;
1322:
1323: const char *s = "";
1324: const char *mp = ptn->mount;
1325: const char *fstype = "ffs";
1326: int fsck_pass = 0, dump_freq = 0;
1327:
1328: if (ptn->parts->pscheme->get_part_device(ptn->parts,
1329: ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL,
1.59 martin 1330: logical_name, true, false))
1.30 martin 1331: dev = dev_buf;
1332: else
1333: dev = NULL;
1334:
1335: if (!*mp) {
1336: /*
1337: * No mount point specified, comment out line and
1338: * use /mnt as a placeholder for the mount point.
1339: */
1340: s = "# ";
1341: mp = "/mnt";
1342: }
1343:
1344: switch (ptn->fs_type) {
1345: case FS_UNUSED:
1346: continue;
1347: case FS_BSDLFS:
1348: /* If there is no LFS, just comment it out. */
1349: if (!check_lfs_progs())
1.1 dholland 1350: s = "# ";
1.30 martin 1351: fstype = "lfs";
1352: /* FALLTHROUGH */
1353: case FS_BSDFFS:
1354: fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
1355: dump_freq = 1;
1356: break;
1357: case FS_MSDOS:
1358: fstype = "msdos";
1359: break;
1360: case FS_SWAP:
1361: if (swap_dev[0] == 0) {
1.66 martin 1362: strlcpy(swap_dev, dev, sizeof swap_dev);
1.30 martin 1363: dump_dev = ",dp";
1364: } else {
1365: dump_dev = "";
1.1 dholland 1366: }
1.30 martin 1367: scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n",
1368: dev, dump_dev);
1369: continue;
1.60 martin 1370: #ifdef HAVE_TMPFS
1371: case FS_TMPFS:
1372: if (ptn->size < 0)
1373: scripting_fprintf(f,
1374: "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,"
1375: "-s=ram%%%" PRIu64 "\n", -ptn->size);
1376: else
1377: scripting_fprintf(f,
1378: "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,"
1379: "-s=%" PRIu64 "M\n", ptn->size);
1380: continue;
1381: #else
1382: case FS_MFS:
1383: if (swap_dev[0] != 0)
1384: scripting_fprintf(f,
1385: "%s\t\t/tmp\tmfs\trw,-s=%"
1386: PRIu64 "\n", swap_dev, ptn->size);
1387: else
1388: scripting_fprintf(f,
1389: "swap\t\t/tmp\tmfs\trw,-s=%"
1390: PRIu64 "\n", ptn->size);
1391: continue;
1392: #endif
1.30 martin 1393: case FS_SYSVBFS:
1394: fstype = "sysvbfs";
1395: make_target_dir("/stand");
1396: break;
1397: default:
1398: fstype = "???";
1399: s = "# ";
1400: break;
1.2 martin 1401: }
1.30 martin 1402: /* The code that remounts root rw doesn't check the partition */
1403: if (strcmp(mp, "/") == 0 &&
1404: (ptn->instflags & PUIINST_MOUNT) == 0)
1405: s = "# ";
1406:
1407: scripting_fprintf(f,
1408: "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
1409: s, dev, mp, fstype,
1410: ptn->mountflags & PUIMNT_LOG ? ",log" : "",
1.48 martin 1411: ptn->mountflags & PUIMNT_NOAUTO ? ",noauto" : "",
1.30 martin 1412: ptn->mountflags & PUIMNT_ASYNC ? ",async" : "",
1413: ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "",
1414: ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "",
1415: ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "",
1416: ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "",
1417: ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "",
1418: dump_freq, fsck_pass);
1.1 dholland 1419: }
1.30 martin 1420:
1.15 martin 1421: done_with_disks:
1.18 martin 1422: if (cdrom_dev[0] == 0)
1423: get_default_cdrom(cdrom_dev, sizeof(cdrom_dev));
1424:
1.1 dholland 1425: /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
1426: scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
1427: scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
1428: scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
1.69 martin 1429: if (cdrom_dev[0] != 0)
1430: scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n",
1431: cdrom_dev);
1.1 dholland 1432: scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n",
1433: tmpfs_on_var_shm() ? "" : "#");
1434: make_target_dir("/kern");
1435: make_target_dir("/proc");
1436: make_target_dir("/dev/pts");
1.69 martin 1437: if (cdrom_dev[0] != 0)
1438: make_target_dir("/cdrom");
1.1 dholland 1439: make_target_dir("/var/shm");
1440:
1441: scripting_fprintf(NULL, "EOF\n");
1442:
1443: fclose(f);
1444: fflush(NULL);
1445: return 0;
1446: }
1447:
1.47 martin 1448: static bool
1449: find_part_by_name(const char *name, struct disk_partitions **parts,
1450: part_id *pno)
1451: {
1452: struct pm_devs *i;
1453: struct disk_partitions *ps;
1454: part_id id;
1455: struct disk_desc disks[MAX_DISKS];
1456: int n, cnt;
1457:
1458: if (SLIST_EMPTY(&pm_head)) {
1459: /*
1460: * List has not been filled, only "pm" is valid - check
1461: * that first.
1462: */
1.65 martin 1463: if (pm->parts != NULL &&
1464: pm->parts->pscheme->find_by_name != NULL) {
1.47 martin 1465: id = pm->parts->pscheme->find_by_name(pm->parts, name);
1466: if (id != NO_PART) {
1467: *pno = id;
1468: *parts = pm->parts;
1469: return true;
1470: }
1471: }
1472: /*
1473: * Not that easy - check all other disks
1474: */
1475: cnt = get_disks(disks, false);
1476: for (n = 0; n < cnt; n++) {
1477: if (strcmp(disks[n].dd_name, pm->diskdev) == 0)
1478: continue;
1479: ps = partitions_read_disk(disks[n].dd_name,
1.62 martin 1480: disks[n].dd_totsec,
1481: disks[n].dd_secsize,
1482: disks[n].dd_no_mbr);
1.47 martin 1483: if (ps == NULL)
1484: continue;
1485: if (ps->pscheme->find_by_name == NULL)
1486: continue;
1487: id = ps->pscheme->find_by_name(ps, name);
1488: if (id != NO_PART) {
1489: *pno = id;
1490: *parts = ps;
1491: return true; /* XXX this leaks memory */
1492: }
1493: ps->pscheme->free(ps);
1494: }
1495: } else {
1496: SLIST_FOREACH(i, &pm_head, l) {
1497: if (i->parts == NULL)
1498: continue;
1499: if (i->parts->pscheme->find_by_name == NULL)
1500: continue;
1501: id = i->parts->pscheme->find_by_name(i->parts, name);
1502: if (id == NO_PART)
1503: continue;
1504: *pno = id;
1505: *parts = i->parts;
1506: return true;
1507: }
1508: }
1509:
1510: *pno = NO_PART;
1511: *parts = NULL;
1512: return false;
1513: }
1514:
1.1 dholland 1515: static int
1516: /*ARGSUSED*/
1.47 martin 1517: process_found_fs(struct data *list, size_t num, const struct lookfor *item,
1518: bool with_fsck)
1.1 dholland 1519: {
1520: int error;
1.47 martin 1521: char rdev[PATH_MAX], dev[PATH_MAX],
1522: options[STRSIZE], tmp[STRSIZE], *op, *last;
1523: const char *fsname = (const char*)item->var;
1524: part_id pno;
1525: struct disk_partitions *parts;
1.51 martin 1526: size_t len;
1527: bool first, is_root;
1.47 martin 1528:
1529: if (num < 2 || strstr(list[2].u.s_val, "noauto") != NULL)
1530: return 0;
1.1 dholland 1531:
1.51 martin 1532: is_root = strcmp(list[1].u.s_val, "/") == 0;
1533: if (is_root && target_mounted())
1.1 dholland 1534: return 0;
1535:
1.47 martin 1536: if (strcmp(item->head, name_prefix) == 0) {
1537: /* this fstab entry uses NAME= syntax */
1.64 martin 1538:
1539: /* unescape */
1540: char *src, *dst;
1541: for (src = list[0].u.s_val, dst =src; src[0] != 0; ) {
1542: if (src[0] == '\\' && src[1] != 0)
1543: src++;
1544: *dst++ = *src++;
1545: }
1546: *dst = 0;
1547:
1.47 martin 1548: if (!find_part_by_name(list[0].u.s_val,
1549: &parts, &pno) || parts == NULL || pno == NO_PART)
1550: return 0;
1551: parts->pscheme->get_part_device(parts, pno,
1.59 martin 1552: dev, sizeof(dev), NULL, plain_name, true, true);
1.47 martin 1553: parts->pscheme->get_part_device(parts, pno,
1.59 martin 1554: rdev, sizeof(rdev), NULL, raw_dev_name, true, true);
1.45 martin 1555: } else {
1.51 martin 1556: /* this fstab entry uses the plain device name */
1557: if (is_root) {
1558: /*
1559: * PR 54480: we can not use the current device name
1560: * as it might be different from the real environment.
1561: * This is an abuse of the functionality, but it used
1562: * to work before (and still does work if only a single
1563: * target disk is involved).
1564: * Use the device name from the current "pm" instead.
1565: */
1566: strcpy(rdev, "/dev/r");
1567: strlcat(rdev, pm->diskdev, sizeof(rdev));
1568: strcpy(dev, "/dev/");
1569: strlcat(dev, pm->diskdev, sizeof(dev));
1570: /* copy over the partition letter, if any */
1571: len = strlen(list[0].u.s_val);
1572: if (list[0].u.s_val[len-1] >= 'a' &&
1573: list[0].u.s_val[len-1] <=
1574: ('a' + getmaxpartitions())) {
1575: strlcat(rdev, &list[0].u.s_val[len-1],
1576: sizeof(rdev));
1577: strlcat(dev, &list[0].u.s_val[len-1],
1578: sizeof(dev));
1579: }
1580: } else {
1581: strcpy(rdev, "/dev/r");
1582: strlcat(rdev, list[0].u.s_val, sizeof(rdev));
1583: strcpy(dev, "/dev/");
1584: strlcat(dev, list[0].u.s_val, sizeof(dev));
1585: }
1.47 martin 1586: }
1587:
1588: if (with_fsck) {
1589: /* need the raw device for fsck_preen */
1590: error = fsck_preen(rdev, fsname, false);
1591: if (error != 0)
1592: return error;
1.45 martin 1593: }
1594:
1.47 martin 1595: /* add mount option for fs type */
1596: strcpy(options, "-t ");
1597: strlcat(options, fsname, sizeof(options));
1598:
1599: /* extract mount options from fstab */
1600: strlcpy(tmp, list[2].u.s_val, sizeof(tmp));
1601: for (first = true, op = strtok_r(tmp, ",", &last); op != NULL;
1602: op = strtok_r(NULL, ",", &last)) {
1603: if (strcmp(op, FSTAB_RW) == 0 ||
1604: strcmp(op, FSTAB_RQ) == 0 ||
1605: strcmp(op, FSTAB_RO) == 0 ||
1606: strcmp(op, FSTAB_SW) == 0 ||
1607: strcmp(op, FSTAB_DP) == 0 ||
1608: strcmp(op, FSTAB_XX) == 0)
1609: continue;
1610: if (first) {
1611: first = false;
1612: strlcat(options, " -o ", sizeof(options));
1613: } else {
1614: strlcat(options, ",", sizeof(options));
1615: }
1616: strlcat(options, op, sizeof(options));
1617: }
1.1 dholland 1618:
1.47 martin 1619: error = target_mount(options, dev, list[1].u.s_val);
1.1 dholland 1620: if (error != 0) {
1.33 christos 1621: msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val);
1.9 martin 1622: if (!ask_noyes(NULL))
1.1 dholland 1623: return error;
1624: }
1625: return 0;
1626: }
1627:
1628: static int
1629: /*ARGSUSED*/
1.47 martin 1630: found_fs(struct data *list, size_t num, const struct lookfor *item)
1.1 dholland 1631: {
1.47 martin 1632: return process_found_fs(list, num, item, true);
1633: }
1.1 dholland 1634:
1.47 martin 1635: static int
1636: /*ARGSUSED*/
1637: found_fs_nocheck(struct data *list, size_t num, const struct lookfor *item)
1638: {
1639: return process_found_fs(list, num, item, false);
1.1 dholland 1640: }
1641:
1642: /*
1643: * Do an fsck. On failure, inform the user by showing a warning
1644: * message and doing menu_ok() before proceeding.
1.30 martin 1645: * The device passed should be the full qualified path to raw disk
1646: * (e.g. /dev/rwd0a).
1.1 dholland 1647: * Returns 0 on success, or nonzero return code from fsck() on failure.
1648: */
1649: static int
1.30 martin 1650: fsck_preen(const char *disk, const char *fsname, bool silent)
1.1 dholland 1651: {
1.30 martin 1652: char *prog, err[12];
1.1 dholland 1653: int error;
1654:
1655: if (fsname == NULL)
1656: return 0;
1657: /* first, check if fsck program exists, if not, assume ok */
1658: asprintf(&prog, "/sbin/fsck_%s", fsname);
1659: if (prog == NULL)
1660: return 0;
1.12 martin 1661: if (access(prog, X_OK) != 0) {
1662: free(prog);
1.1 dholland 1663: return 0;
1.12 martin 1664: }
1.1 dholland 1665: if (!strcmp(fsname,"ffs"))
1.30 martin 1666: fixsb(prog, disk);
1667: error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk);
1.1 dholland 1668: free(prog);
1.15 martin 1669: if (error != 0 && !silent) {
1.30 martin 1670: sprintf(err, "%d", error);
1671: msg_display_subst(msg_string(MSG_badfs), 3,
1672: disk, fsname, err);
1.9 martin 1673: if (ask_noyes(NULL))
1.1 dholland 1674: error = 0;
1675: /* XXX at this point maybe we should run a full fsck? */
1676: }
1677: return error;
1678: }
1679:
1680: /* This performs the same function as the etc/rc.d/fixsb script
1681: * which attempts to correct problems with ffs1 filesystems
1682: * which may have been introduced by booting a netbsd-current kernel
1683: * from between April of 2003 and January 2004. For more information
1684: * This script was developed as a response to NetBSD pr install/25138
1685: * Additional prs regarding the original issue include:
1686: * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926
1687: */
1688: static void
1.30 martin 1689: fixsb(const char *prog, const char *disk)
1.1 dholland 1690: {
1691: int fd;
1692: int rval;
1693: union {
1694: struct fs fs;
1695: char buf[SBLOCKSIZE];
1696: } sblk;
1697: struct fs *fs = &sblk.fs;
1698:
1.30 martin 1699: fd = open(disk, O_RDONLY);
1.1 dholland 1700: if (fd == -1)
1701: return;
1702:
1703: /* Read ffsv1 main superblock */
1704: rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1);
1705: close(fd);
1706: if (rval != sizeof sblk.buf)
1707: return;
1708:
1709: if (fs->fs_magic != FS_UFS1_MAGIC &&
1710: fs->fs_magic != FS_UFS1_MAGIC_SWAPPED)
1711: /* Not FFSv1 */
1712: return;
1713: if (fs->fs_old_flags & FS_FLAGS_UPDATED)
1714: /* properly updated fslevel 4 */
1715: return;
1716: if (fs->fs_bsize != fs->fs_maxbsize)
1717: /* not messed up */
1718: return;
1719:
1720: /*
1721: * OK we have a munged fs, first 'upgrade' to fslevel 4,
1722: * We specify -b16 in order to stop fsck bleating that the
1723: * sb doesn't match the first alternate.
1724: */
1725: run_program(RUN_DISPLAY | RUN_PROGRESS,
1.30 martin 1726: "%s -p -b 16 -c 4 %s", prog, disk);
1.1 dholland 1727: /* Then downgrade to fslevel 3 */
1728: run_program(RUN_DISPLAY | RUN_PROGRESS,
1.30 martin 1729: "%s -p -c 3 %s", prog, disk);
1.1 dholland 1730: }
1731:
1732: /*
1733: * fsck and mount the root partition.
1.30 martin 1734: * devdev is the fully qualified block device name.
1.1 dholland 1735: */
1736: static int
1.47 martin 1737: mount_root(const char *devdev, bool first, bool writeable,
1738: struct install_partition_desc *install)
1.1 dholland 1739: {
1740: int error;
1741:
1.30 martin 1742: error = fsck_preen(devdev, "ffs", false);
1.1 dholland 1743: if (error != 0)
1744: return error;
1745:
1.47 martin 1746: if (first)
1747: md_pre_mount(install, 0);
1.1 dholland 1748:
1.30 martin 1749: /* Mount devdev on target's "".
1.1 dholland 1750: * If we pass "" as mount-on, Prefixing will DTRT.
1751: * for now, use no options.
1752: * XXX consider -o remount in case target root is
1753: * current root, still readonly from single-user?
1754: */
1.47 martin 1755: return target_mount(writeable? "" : "-r", devdev, "");
1.1 dholland 1756: }
1757:
1758: /* Get information on the file systems mounted from the root filesystem.
1759: * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD
1760: * inodes. Fsck them. Mount them.
1761: */
1762:
1763: int
1.30 martin 1764: mount_disks(struct install_partition_desc *install)
1.1 dholland 1765: {
1766: char *fstab;
1767: int fstabsize;
1768: int error;
1.30 martin 1769: char devdev[PATH_MAX];
1.47 martin 1770: size_t i, num_fs_types, num_entries;
1771: struct lookfor *fstabbuf, *l;
1.1 dholland 1772:
1.40 martin 1773: if (install->cur_system)
1774: return 0;
1775:
1.47 martin 1776: /*
1777: * Check what file system tools are available and create parsers
1778: * for the corresponding fstab(5) entries - all others will be
1779: * ignored.
1780: */
1781: num_fs_types = 1; /* ffs is implicit */
1782: for (i = 0; i < __arraycount(extern_fs_with_chk); i++) {
1783: sprintf(devdev, "/sbin/newfs_%s", extern_fs_with_chk[i]);
1784: if (file_exists_p(devdev))
1785: num_fs_types++;
1786: }
1787: for (i = 0; i < __arraycount(extern_fs_newfs_only); i++) {
1788: sprintf(devdev, "/sbin/newfs_%s", extern_fs_newfs_only[i]);
1789: if (file_exists_p(devdev))
1790: num_fs_types++;
1791: }
1792: num_entries = 2 * num_fs_types + 1; /* +1 for "ufs" special case */
1793: fstabbuf = calloc(num_entries, sizeof(*fstabbuf));
1794: if (fstabbuf == NULL)
1795: return -1;
1796: l = fstabbuf;
1797: l->head = "/dev/";
1798: l->fmt = strdup("/dev/%s %s ffs %s");
1799: l->todo = "c";
1800: l->var = __UNCONST("ffs");
1801: l->func = found_fs;
1802: l++;
1803: l->head = "/dev/";
1804: l->fmt = strdup("/dev/%s %s ufs %s");
1805: l->todo = "c";
1806: l->var = __UNCONST("ffs");
1807: l->func = found_fs;
1808: l++;
1809: l->head = NAME_PREFIX;
1810: l->fmt = strdup(NAME_PREFIX "%s %s ffs %s");
1811: l->todo = "c";
1812: l->var = __UNCONST("ffs");
1813: l->func = found_fs;
1814: l++;
1815: for (i = 0; i < __arraycount(extern_fs_with_chk); i++) {
1816: sprintf(devdev, "/sbin/newfs_%s", extern_fs_with_chk[i]);
1817: if (!file_exists_p(devdev))
1818: continue;
1819: sprintf(devdev, "/dev/%%s %%s %s %%s", extern_fs_with_chk[i]);
1820: l->head = "/dev/";
1821: l->fmt = strdup(devdev);
1822: l->todo = "c";
1823: l->var = __UNCONST(extern_fs_with_chk[i]);
1824: l->func = found_fs;
1825: l++;
1826: sprintf(devdev, NAME_PREFIX "%%s %%s %s %%s",
1827: extern_fs_with_chk[i]);
1828: l->head = NAME_PREFIX;
1829: l->fmt = strdup(devdev);
1830: l->todo = "c";
1831: l->var = __UNCONST(extern_fs_with_chk[i]);
1832: l->func = found_fs;
1833: l++;
1834: }
1835: for (i = 0; i < __arraycount(extern_fs_newfs_only); i++) {
1836: sprintf(devdev, "/sbin/newfs_%s", extern_fs_newfs_only[i]);
1837: if (!file_exists_p(devdev))
1838: continue;
1839: sprintf(devdev, "/dev/%%s %%s %s %%s", extern_fs_newfs_only[i]);
1840: l->head = "/dev/";
1841: l->fmt = strdup(devdev);
1842: l->todo = "c";
1843: l->var = __UNCONST(extern_fs_newfs_only[i]);
1844: l->func = found_fs_nocheck;
1845: l++;
1846: sprintf(devdev, NAME_PREFIX "%%s %%s %s %%s",
1847: extern_fs_newfs_only[i]);
1848: l->head = NAME_PREFIX;
1849: l->fmt = strdup(devdev);
1850: l->todo = "c";
1851: l->var = __UNCONST(extern_fs_newfs_only[i]);
1852: l->func = found_fs_nocheck;
1853: l++;
1854: }
1855: assert((size_t)(l - fstabbuf) == num_entries);
1.1 dholland 1856:
1857: /* First the root device. */
1.65 martin 1858: if (target_already_root()) {
1.1 dholland 1859: /* avoid needing to call target_already_root() again */
1860: targetroot_mnt[0] = 0;
1.65 martin 1861: } else if (pm->no_part) {
1862: snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev);
1863: error = mount_root(devdev, true, false, install);
1864: if (error != 0 && error != EBUSY)
1865: return -1;
1866: } else {
1.39 martin 1867: for (i = 0; i < install->num; i++) {
1868: if (is_root_part_mount(install->infos[i].mount))
1869: break;
1870: }
1871:
1872: if (i >= install->num) {
1873: hit_enter_to_continue(MSG_noroot, NULL);
1874: return -1;
1875: }
1876:
1877: if (!install->infos[i].parts->pscheme->get_part_device(
1878: install->infos[i].parts, install->infos[i].cur_part_id,
1.59 martin 1879: devdev, sizeof devdev, NULL, plain_name, true, true))
1.30 martin 1880: return -1;
1.47 martin 1881: error = mount_root(devdev, true, false, install);
1.1 dholland 1882: if (error != 0 && error != EBUSY)
1883: return -1;
1884: }
1885:
1886: /* Check the target /etc/fstab exists before trying to parse it. */
1887: if (target_dir_exists_p("/etc") == 0 ||
1888: target_file_exists_p("/etc/fstab") == 0) {
1.33 christos 1889: msg_fmt_display(MSG_noetcfstab, "%s", pm->diskdev);
1.30 martin 1890: hit_enter_to_continue(NULL, NULL);
1.1 dholland 1891: return -1;
1892: }
1893:
1894:
1895: /* Get fstab entries from the target-root /etc/fstab. */
1896: fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab");
1897: if (fstabsize < 0) {
1898: /* error ! */
1.33 christos 1899: msg_fmt_display(MSG_badetcfstab, "%s", pm->diskdev);
1.30 martin 1900: hit_enter_to_continue(NULL, NULL);
1.47 martin 1901: umount_root();
1.2 martin 1902: return -2;
1.1 dholland 1903: }
1.47 martin 1904: /*
1905: * We unmount the read-only root again, so we can mount it
1906: * with proper options from /etc/fstab
1907: */
1908: umount_root();
1909:
1910: /*
1911: * Now do all entries in /etc/fstab and mount them if required
1912: */
1913: error = walk(fstab, (size_t)fstabsize, fstabbuf, num_entries);
1.1 dholland 1914: free(fstab);
1.47 martin 1915: for (i = 0; i < num_entries; i++)
1916: free(__UNCONST(fstabbuf[i].fmt));
1917: free(fstabbuf);
1.1 dholland 1918:
1919: return error;
1920: }
1921:
1.67 martin 1922: static char swap_dev[PATH_MAX];
1923:
1.75 martin 1924: void
1.30 martin 1925: set_swap_if_low_ram(struct install_partition_desc *install)
1.10 isaki 1926: {
1.67 martin 1927: swap_dev[0] = 0;
1.61 martin 1928: if (get_ramsize() <= TINY_RAM_SIZE)
1.75 martin 1929: set_swap(install);
1.7 abs 1930: }
1931:
1.75 martin 1932: void
1.30 martin 1933: set_swap(struct install_partition_desc *install)
1.1 dholland 1934: {
1.30 martin 1935: size_t i;
1.1 dholland 1936: int rval;
1937:
1.67 martin 1938: swap_dev[0] = 0;
1.30 martin 1939: for (i = 0; i < install->num; i++) {
1940: if (install->infos[i].type == PT_swap)
1941: break;
1942: }
1943: if (i >= install->num)
1.75 martin 1944: return;
1.1 dholland 1945:
1.30 martin 1946: if (!install->infos[i].parts->pscheme->get_part_device(
1.67 martin 1947: install->infos[i].parts, install->infos[i].cur_part_id, swap_dev,
1948: sizeof swap_dev, NULL, plain_name, true, true))
1.75 martin 1949: return;
1.30 martin 1950:
1.67 martin 1951: rval = swapctl(SWAP_ON, swap_dev, 0);
1.75 martin 1952: if (rval != 0)
1.67 martin 1953: swap_dev[0] = 0;
1954: }
1.1 dholland 1955:
1.67 martin 1956: void
1957: clear_swap(void)
1958: {
1959:
1960: if (swap_dev[0] == 0)
1961: return;
1962: swapctl(SWAP_OFF, swap_dev, 0);
1963: swap_dev[0] = 0;
1.1 dholland 1964: }
1965:
1966: int
1967: check_swap(const char *disk, int remove_swap)
1968: {
1969: struct swapent *swap;
1970: char *cp;
1971: int nswap;
1972: int l;
1973: int rval = 0;
1974:
1975: nswap = swapctl(SWAP_NSWAP, 0, 0);
1976: if (nswap <= 0)
1977: return 0;
1978:
1979: swap = malloc(nswap * sizeof *swap);
1980: if (swap == NULL)
1981: return -1;
1982:
1983: nswap = swapctl(SWAP_STATS, swap, nswap);
1984: if (nswap < 0)
1985: goto bad_swap;
1986:
1987: l = strlen(disk);
1988: while (--nswap >= 0) {
1989: /* Should we check the se_dev or se_path? */
1990: cp = swap[nswap].se_path;
1991: if (memcmp(cp, "/dev/", 5) != 0)
1992: continue;
1993: if (memcmp(cp + 5, disk, l) != 0)
1994: continue;
1995: if (!isalpha(*(unsigned char *)(cp + 5 + l)))
1996: continue;
1997: if (cp[5 + l + 1] != 0)
1998: continue;
1999: /* ok path looks like it is for this device */
2000: if (!remove_swap) {
2001: /* count active swap areas */
2002: rval++;
2003: continue;
2004: }
2005: if (swapctl(SWAP_OFF, cp, 0) == -1)
2006: rval = -1;
2007: }
2008:
2009: done:
2010: free(swap);
2011: return rval;
2012:
2013: bad_swap:
2014: rval = -1;
2015: goto done;
2016: }
2017:
2018: #ifdef HAVE_BOOTXX_xFS
2019: char *
1.30 martin 2020: bootxx_name(struct install_partition_desc *install)
1.1 dholland 2021: {
1.52 martin 2022: size_t i;
2023: int fstype = -1;
1.1 dholland 2024: const char *bootxxname;
2025: char *bootxx;
2026:
1.52 martin 2027: /* find a partition to be mounted as / */
2028: for (i = 0; i < install->num; i++) {
2029: if ((install->infos[i].instflags & PUIINST_MOUNT)
2030: && strcmp(install->infos[i].mount, "/") == 0) {
2031: fstype = install->infos[i].fs_type;
2032: break;
2033: }
2034: }
2035: if (fstype < 0) {
2036: /* not found? take first root type partition instead */
2037: for (i = 0; i < install->num; i++) {
2038: if (install->infos[i].type == PT_root) {
2039: fstype = install->infos[i].fs_type;
2040: break;
2041: }
2042: }
2043: }
2044:
1.1 dholland 2045: /* check we have boot code for the root partition type */
2046: switch (fstype) {
2047: #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2)
2048: case FS_BSDFFS:
1.63 martin 2049: if (install->infos[i].fs_version == 2) {
1.1 dholland 2050: #ifdef BOOTXX_FFSV2
2051: bootxxname = BOOTXX_FFSV2;
2052: #else
2053: bootxxname = NULL;
2054: #endif
2055: } else {
2056: #ifdef BOOTXX_FFSV1
2057: bootxxname = BOOTXX_FFSV1;
2058: #else
2059: bootxxname = NULL;
2060: #endif
2061: }
2062: break;
2063: #endif
1.11 pgoyette 2064: #ifdef BOOTXX_LFSV2
1.1 dholland 2065: case FS_BSDLFS:
1.11 pgoyette 2066: bootxxname = BOOTXX_LFSV2;
1.1 dholland 2067: break;
2068: #endif
2069: default:
2070: bootxxname = NULL;
2071: break;
2072: }
2073:
2074: if (bootxxname == NULL)
2075: return NULL;
2076:
2077: asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname);
2078: return bootxx;
2079: }
2080: #endif
1.2 martin 2081:
2082: /* from dkctl.c */
2083: static int
2084: get_dkwedges_sort(const void *a, const void *b)
2085: {
2086: const struct dkwedge_info *dkwa = a, *dkwb = b;
2087: const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset;
2088: return (oa < ob) ? -1 : (oa > ob) ? 1 : 0;
2089: }
2090:
2091: int
2092: get_dkwedges(struct dkwedge_info **dkw, const char *diskdev)
2093: {
2094: struct dkwedge_list dkwl;
2095:
2096: *dkw = NULL;
1.35 christos 2097: if (!get_wedge_list(diskdev, &dkwl))
1.2 martin 2098: return -1;
2099:
1.35 christos 2100: if (dkwl.dkwl_nwedges > 0 && *dkw != NULL) {
2101: qsort(*dkw, dkwl.dkwl_nwedges, sizeof(**dkw),
2102: get_dkwedges_sort);
1.2 martin 2103: }
2104:
2105: return dkwl.dkwl_nwedges;
2106: }
1.55 martin 2107:
1.56 martin 2108: #ifndef NO_CLONES
1.55 martin 2109: /*
2110: * Helper structures used in the partition select menu
2111: */
2112: struct single_partition {
2113: struct disk_partitions *parts;
2114: part_id id;
2115: };
2116:
2117: struct sel_menu_data {
2118: struct single_partition *partitions;
2119: struct selected_partition result;
2120: };
2121:
2122: static int
2123: select_single_part(menudesc *m, void *arg)
2124: {
2125: struct sel_menu_data *data = arg;
2126:
2127: data->result.parts = data->partitions[m->cursel].parts;
2128: data->result.id = data->partitions[m->cursel].id;
2129:
2130: return 1;
2131: }
2132:
2133: static void
2134: display_single_part(menudesc *m, int opt, void *arg)
2135: {
2136: const struct sel_menu_data *data = arg;
2137: struct disk_part_info info;
2138: struct disk_partitions *parts = data->partitions[opt].parts;
2139: part_id id = data->partitions[opt].id;
2140: int l;
2141: const char *desc = NULL;
2142: char line[MENUSTRSIZE*2];
2143:
2144: if (!parts->pscheme->get_part_info(parts, id, &info))
2145: return;
2146:
2147: if (parts->pscheme->other_partition_identifier != NULL)
2148: desc = parts->pscheme->other_partition_identifier(
2149: parts, id);
2150:
2151: daddr_t start = info.start / sizemult;
2152: daddr_t size = info.size / sizemult;
2153: snprintf(line, sizeof line, "%s [%" PRIu64 " @ %" PRIu64 "]",
2154: parts->disk, size, start);
2155:
2156: if (info.nat_type != NULL) {
2157: strlcat(line, " ", sizeof line);
2158: strlcat(line, info.nat_type->description, sizeof line);
2159: }
2160:
2161: if (desc != NULL) {
2162: strlcat(line, ": ", sizeof line);
2163: strlcat(line, desc, sizeof line);
2164: }
2165:
2166: l = strlen(line);
2167: if (l >= (m->w))
2168: strcpy(line + (m->w-3), "...");
2169: wprintw(m->mw, "%s", line);
2170: }
2171:
2172: /*
2173: * is the given "test" partitions set used in the selected set?
2174: */
2175: static bool
2176: selection_has_parts(struct selected_partitions *sel,
2177: const struct disk_partitions *test)
2178: {
2179: size_t i;
2180:
2181: for (i = 0; i < sel->num_sel; i++) {
2182: if (sel->selection[i].parts == test)
2183: return true;
2184: }
2185: return false;
2186: }
2187:
2188: /*
2189: * is the given "test" partition in the selected set?
2190: */
2191: static bool
2192: selection_has_partition(struct selected_partitions *sel,
2193: const struct disk_partitions *test, part_id test_id)
2194: {
2195: size_t i;
2196:
2197: for (i = 0; i < sel->num_sel; i++) {
2198: if (sel->selection[i].parts == test &&
2199: sel->selection[i].id == test_id)
2200: return true;
2201: }
2202: return false;
2203: }
2204:
2205: /*
2206: * let the user select a partition, optionally skipping all partitions
2207: * on the "ignore" device
2208: */
2209: static bool
2210: add_select_partition(struct selected_partitions *res,
2211: struct disk_partitions **all_parts, size_t all_cnt)
2212: {
2213: struct disk_partitions *ps;
2214: struct disk_part_info info;
2215: part_id id;
2216: struct single_partition *partitions, *pp;
2217: struct menu_ent *part_menu_opts, *menup;
2218: size_t n, part_cnt;
2219: int sel_menu;
2220:
2221: /*
2222: * count how many items our menu will have
2223: */
2224: part_cnt = 0;
2225: for (n = 0; n < all_cnt; n++) {
2226: ps = all_parts[n];
2227: for (id = 0; id < ps->num_part; id++) {
2228: if (selection_has_partition(res, ps, id))
2229: continue;
2230: if (!ps->pscheme->get_part_info(ps, id, &info))
2231: continue;
2232: if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK|
2233: PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
2234: continue;
2235: part_cnt++;
2236: }
2237: }
2238:
2239: /*
2240: * create a menu from this and let the user
2241: * select one partition
2242: */
2243: part_menu_opts = NULL;
2244: partitions = calloc(part_cnt, sizeof *partitions);
2245: if (partitions == NULL)
2246: goto done;
2247: part_menu_opts = calloc(part_cnt, sizeof *part_menu_opts);
2248: if (part_menu_opts == NULL)
2249: goto done;
2250: pp = partitions;
2251: menup = part_menu_opts;
2252: for (n = 0; n < all_cnt; n++) {
2253: ps = all_parts[n];
2254: for (id = 0; id < ps->num_part; id++) {
2255: if (selection_has_partition(res, ps, id))
2256: continue;
2257: if (!ps->pscheme->get_part_info(ps, id, &info))
2258: continue;
2259: if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK|
2260: PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
2261: continue;
2262: pp->parts = ps;
2263: pp->id = id;
2264: pp++;
2265: menup->opt_action = select_single_part;
2266: menup++;
2267: }
2268: }
2269: sel_menu = new_menu(MSG_select_foreign_part, part_menu_opts, part_cnt,
2270: 3, 3, 0, 60,
2271: MC_SUBMENU | MC_SCROLL | MC_NOCLEAR,
2272: NULL, display_single_part, NULL,
1.57 martin 2273: NULL, MSG_exit_menu_generic);
1.55 martin 2274: if (sel_menu != -1) {
2275: struct selected_partition *newsels;
2276: struct sel_menu_data data;
2277:
2278: memset(&data, 0, sizeof data);
2279: data.partitions = partitions;
2280: process_menu(sel_menu, &data);
2281: free_menu(sel_menu);
2282:
2283: if (data.result.parts != NULL) {
2284: newsels = realloc(res->selection,
2285: sizeof(*res->selection)*(res->num_sel+1));
2286: if (newsels != NULL) {
2287: res->selection = newsels;
2288: newsels += res->num_sel++;
2289: newsels->parts = data.result.parts;
2290: newsels->id = data.result.id;
2291: }
2292: }
2293: }
2294:
2295: /*
2296: * Final cleanup
2297: */
2298: done:
2299: free(part_menu_opts);
2300: free(partitions);
2301:
2302: return res->num_sel > 0;
2303: }
2304:
2305: struct part_selection_and_all_parts {
2306: struct selected_partitions *selection;
2307: struct disk_partitions **all_parts;
2308: size_t all_cnt;
2309: char *title;
2310: bool cancelled;
2311: };
2312:
2313: static int
2314: toggle_clone_data(struct menudesc *m, void *arg)
2315: {
2316: struct part_selection_and_all_parts *sel = arg;
2317:
2318: sel->selection->with_data = !sel->selection->with_data;
2319: return 0;
2320: }
2321:
2322: static int
2323: add_another(struct menudesc *m, void *arg)
2324: {
2325: struct part_selection_and_all_parts *sel = arg;
2326:
2327: add_select_partition(sel->selection, sel->all_parts, sel->all_cnt);
2328: return 0;
2329: }
2330:
2331: static int
2332: cancel_clone(struct menudesc *m, void *arg)
1.72 rillig 2333: {
1.55 martin 2334: struct part_selection_and_all_parts *sel = arg;
2335:
2336: sel->cancelled = true;
2337: return 1;
2338: }
2339:
2340: static void
2341: update_sel_part_title(struct part_selection_and_all_parts *sel)
2342: {
2343: struct disk_part_info info;
2344: char *buf, line[MENUSTRSIZE];
2345: size_t buf_len, i;
2346:
2347: buf_len = MENUSTRSIZE * (1+sel->selection->num_sel);
2348: buf = malloc(buf_len);
2349: if (buf == NULL)
2350: return;
2351:
2352: strcpy(buf, msg_string(MSG_select_source_hdr));
2353: for (i = 0; i < sel->selection->num_sel; i++) {
2354: struct selected_partition *s =
2355: &sel->selection->selection[i];
2356: if (!s->parts->pscheme->get_part_info(s->parts, s->id, &info))
2357: continue;
2358: daddr_t start = info.start / sizemult;
2359: daddr_t size = info.size / sizemult;
2360: sprintf(line, "\n %s [%" PRIu64 " @ %" PRIu64 "] ",
2361: s->parts->disk, size, start);
2362: if (info.nat_type != NULL)
2363: strlcat(line, info.nat_type->description, sizeof(line));
2364: strlcat(buf, line, buf_len);
2365: }
2366: free(sel->title);
2367: sel->title = buf;
2368: }
2369:
2370: static void
2371: post_sel_part(struct menudesc *m, void *arg)
2372: {
2373: struct part_selection_and_all_parts *sel = arg;
2374:
2375: if (m->mw == NULL)
2376: return;
2377: update_sel_part_title(sel);
2378: m->title = sel->title;
2379: m->h = 0;
2380: resize_menu_height(m);
2381: }
2382:
2383: static void
2384: fmt_sel_part_line(struct menudesc *m, int i, void *arg)
2385: {
2386: struct part_selection_and_all_parts *sel = arg;
2387:
2388: wprintw(m->mw, "%s: %s", msg_string(MSG_clone_with_data),
2389: sel->selection->with_data ?
2390: msg_string(MSG_Yes) :
2391: msg_string(MSG_No));
2392: }
2393:
2394: bool
2395: select_partitions(struct selected_partitions *res,
2396: const struct disk_partitions *ignore)
2397: {
2398: struct disk_desc disks[MAX_DISKS];
2399: struct disk_partitions *ps;
2400: struct part_selection_and_all_parts data;
2401: struct pm_devs *i;
2402: size_t j;
2403: int cnt, n, m;
2404: static menu_ent men[] = {
2405: { .opt_name = MSG_select_source_add,
2406: .opt_action = add_another },
2407: { .opt_action = toggle_clone_data },
2408: { .opt_name = MSG_cancel, .opt_action = cancel_clone },
2409: };
2410:
2411: memset(res, 0, sizeof *res);
2412: memset(&data, 0, sizeof data);
2413: data.selection = res;
2414:
2415: /*
2416: * collect all available partition sets
2417: */
2418: data.all_cnt = 0;
2419: if (SLIST_EMPTY(&pm_head)) {
2420: cnt = get_disks(disks, false);
2421: if (cnt <= 0)
2422: return false;
2423:
2424: /*
2425: * allocate two slots for each disk (primary/secondary)
2426: */
2427: data.all_parts = calloc(2*cnt, sizeof *data.all_parts);
2428: if (data.all_parts == NULL)
2429: return false;
2430:
2431: for (n = 0; n < cnt; n++) {
2432: if (ignore != NULL &&
2433: strcmp(disks[n].dd_name, ignore->disk) == 0)
2434: continue;
2435:
2436: ps = partitions_read_disk(disks[n].dd_name,
1.62 martin 2437: disks[n].dd_totsec,
2438: disks[n].dd_secsize,
2439: disks[n].dd_no_mbr);
1.55 martin 2440: if (ps == NULL)
2441: continue;
2442: data.all_parts[data.all_cnt++] = ps;
2443: ps = get_inner_parts(ps);
2444: if (ps == NULL)
2445: continue;
2446: data.all_parts[data.all_cnt++] = ps;
2447: }
2448: if (data.all_cnt > 0)
2449: res->free_parts = true;
2450: } else {
2451: cnt = 0;
2452: SLIST_FOREACH(i, &pm_head, l)
2453: cnt++;
2454:
2455: data.all_parts = calloc(cnt, sizeof *data.all_parts);
2456: if (data.all_parts == NULL)
2457: return false;
2458:
2459: SLIST_FOREACH(i, &pm_head, l) {
2460: if (i->parts == NULL)
2461: continue;
2462: if (i->parts == ignore)
2463: continue;
2464: data.all_parts[data.all_cnt++] = i->parts;
2465: }
2466: }
2467:
2468: if (!add_select_partition(res, data.all_parts, data.all_cnt))
2469: goto fail;
2470:
2471: /* loop with menu */
2472: update_sel_part_title(&data);
2473: m = new_menu(data.title, men, __arraycount(men), 3, 2, 0, 65, MC_SCROLL,
1.57 martin 2474: post_sel_part, fmt_sel_part_line, NULL, NULL, MSG_clone_src_done);
1.55 martin 2475: process_menu(m, &data);
2476: free(data.title);
2477: if (res->num_sel == 0)
2478: goto fail;
2479:
2480: /* cleanup */
2481: if (res->free_parts) {
2482: for (j = 0; j < data.all_cnt; j++) {
2483: if (selection_has_parts(res, data.all_parts[j]))
2484: continue;
2485: if (data.all_parts[j]->parent != NULL)
2486: continue;
2487: data.all_parts[j]->pscheme->free(data.all_parts[j]);
2488: }
2489: }
2490: free(data.all_parts);
2491: return true;
2492:
2493: fail:
2494: if (res->free_parts) {
2495: for (j = 0; j < data.all_cnt; j++) {
2496: if (data.all_parts[j]->parent != NULL)
2497: continue;
2498: data.all_parts[j]->pscheme->free(data.all_parts[j]);
2499: }
2500: }
2501: free(data.all_parts);
2502: return false;
2503: }
2504:
2505: void
2506: free_selected_partitions(struct selected_partitions *selected)
2507: {
2508: size_t i;
2509: struct disk_partitions *parts;
2510:
2511: if (!selected->free_parts)
2512: return;
2513:
2514: for (i = 0; i < selected->num_sel; i++) {
2515: parts = selected->selection[i].parts;
2516:
2517: /* remove from list before testing for other instances */
2518: selected->selection[i].parts = NULL;
2519:
1.74 andvar 2520: /* if this is the secondary partition set, the parent owns it */
1.55 martin 2521: if (parts->parent != NULL)
2522: continue;
2523:
2524: /* only free once (we use the last one) */
2525: if (selection_has_parts(selected, parts))
2526: continue;
2527: parts->pscheme->free(parts);
2528: }
2529: free(selected->selection);
2530: }
2531:
2532: daddr_t
2533: selected_parts_size(struct selected_partitions *selected)
2534: {
2535: struct disk_part_info info;
2536: size_t i;
2537: daddr_t s = 0;
2538:
2539: for (i = 0; i < selected->num_sel; i++) {
2540: if (!selected->selection[i].parts->pscheme->get_part_info(
2541: selected->selection[i].parts,
2542: selected->selection[i].id, &info))
2543: continue;
2544: s += info.size;
2545: }
2546:
2547: return s;
2548: }
2549:
2550: int
2551: clone_target_select(menudesc *m, void *arg)
2552: {
2553: struct clone_target_menu_data *data = arg;
2554:
2555: data->res = m->cursel;
2556: return 1;
2557: }
2558:
2559: bool
2560: clone_partition_data(struct disk_partitions *dest_parts, part_id did,
2561: struct disk_partitions *src_parts, part_id sid)
2562: {
2563: char src_dev[MAXPATHLEN], target_dev[MAXPATHLEN];
2564:
2565: if (!src_parts->pscheme->get_part_device(
2566: src_parts, sid, src_dev, sizeof src_dev, NULL,
1.59 martin 2567: raw_dev_name, true, true))
1.55 martin 2568: return false;
2569: if (!dest_parts->pscheme->get_part_device(
2570: dest_parts, did, target_dev, sizeof target_dev, NULL,
1.59 martin 2571: raw_dev_name, true, true))
1.55 martin 2572: return false;
2573:
1.72 rillig 2574: return run_program(RUN_DISPLAY | RUN_PROGRESS,
1.55 martin 2575: "progress -f %s -b 1m dd bs=1m of=%s",
2576: src_dev, target_dev) == 0;
2577: }
1.56 martin 2578: #endif
2579:
CVSweb <webmaster@jp.NetBSD.org>