| @@ -1,1766 +1,1772 @@ | | | @@ -1,1766 +1,1772 @@ |
1 | /* $NetBSD: disks.c,v 1.72 2021/01/31 22:45:46 rillig Exp $ */ | | 1 | /* $NetBSD: disks.c,v 1.73 2021/07/14 18:56:05 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright 1997 Piermont Information Systems Inc. | | 4 | * Copyright 1997 Piermont Information Systems Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Philip A. Nelson for Piermont Information Systems Inc. | | 7 | * Written by Philip A. Nelson for Piermont Information Systems Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 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 | | 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 | | 18 | * or promote products derived from this software without specific prior |
19 | * written permission. | | 19 | * written permission. |
20 | * | | 20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' | | 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 | | 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE | | 24 | * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE |
25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
31 | * THE POSSIBILITY OF SUCH DAMAGE. | | 31 | * THE POSSIBILITY OF SUCH DAMAGE. |
32 | * | | 32 | * |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | /* disks.c -- routines to deal with finding disks and labeling disks. */ | | 35 | /* disks.c -- routines to deal with finding disks and labeling disks. */ |
36 | | | 36 | |
37 | | | 37 | |
38 | #include <assert.h> | | 38 | #include <assert.h> |
39 | #include <errno.h> | | 39 | #include <errno.h> |
40 | #include <inttypes.h> | | 40 | #include <inttypes.h> |
41 | #include <stdio.h> | | 41 | #include <stdio.h> |
42 | #include <stdlib.h> | | 42 | #include <stdlib.h> |
43 | #include <unistd.h> | | 43 | #include <unistd.h> |
44 | #include <fcntl.h> | | 44 | #include <fcntl.h> |
45 | #include <fnmatch.h> | | 45 | #include <fnmatch.h> |
46 | #include <util.h> | | 46 | #include <util.h> |
47 | #include <uuid.h> | | 47 | #include <uuid.h> |
48 | #include <paths.h> | | 48 | #include <paths.h> |
49 | #include <fstab.h> | | 49 | #include <fstab.h> |
50 | | | 50 | |
51 | #include <sys/param.h> | | 51 | #include <sys/param.h> |
52 | #include <sys/sysctl.h> | | 52 | #include <sys/sysctl.h> |
53 | #include <sys/swap.h> | | 53 | #include <sys/swap.h> |
54 | #include <sys/disklabel_gpt.h> | | 54 | #include <sys/disklabel_gpt.h> |
55 | #include <ufs/ufs/dinode.h> | | 55 | #include <ufs/ufs/dinode.h> |
56 | #include <ufs/ffs/fs.h> | | 56 | #include <ufs/ffs/fs.h> |
57 | | | 57 | |
58 | #include <dev/scsipi/scsipi_all.h> | | 58 | #include <dev/scsipi/scsipi_all.h> |
59 | #include <sys/scsiio.h> | | 59 | #include <sys/scsiio.h> |
60 | | | 60 | |
61 | #include <dev/ata/atareg.h> | | 61 | #include <dev/ata/atareg.h> |
62 | #include <sys/ataio.h> | | 62 | #include <sys/ataio.h> |
63 | | | 63 | |
64 | #include "defs.h" | | 64 | #include "defs.h" |
65 | #include "md.h" | | 65 | #include "md.h" |
66 | #include "msg_defs.h" | | 66 | #include "msg_defs.h" |
67 | #include "menu_defs.h" | | 67 | #include "menu_defs.h" |
68 | #include "txtwalk.h" | | 68 | #include "txtwalk.h" |
69 | | | 69 | |
70 | /* #define DEBUG_VERBOSE 1 */ | | 70 | /* #define DEBUG_VERBOSE 1 */ |
71 | | | 71 | |
72 | /* Disk descriptions */ | | 72 | /* Disk descriptions */ |
73 | struct disk_desc { | | 73 | struct disk_desc { |
74 | char dd_name[SSTRSIZE]; | | 74 | char dd_name[SSTRSIZE]; |
75 | char dd_descr[256]; | | 75 | char dd_descr[256]; |
76 | bool dd_no_mbr, dd_no_part; | | 76 | bool dd_no_mbr, dd_no_part; |
77 | uint dd_cyl; | | 77 | uint dd_cyl; |
78 | uint dd_head; | | 78 | uint dd_head; |
79 | uint dd_sec; | | 79 | uint dd_sec; |
80 | uint dd_secsize; | | 80 | uint dd_secsize; |
81 | daddr_t dd_totsec; | | 81 | daddr_t dd_totsec; |
82 | }; | | 82 | }; |
83 | | | 83 | |
84 | #define NAME_PREFIX "NAME=" | | 84 | #define NAME_PREFIX "NAME=" |
85 | static const char name_prefix[] = NAME_PREFIX; | | 85 | static const char name_prefix[] = NAME_PREFIX; |
86 | | | 86 | |
87 | /* things we could have as /sbin/newfs_* and /sbin/fsck_* */ | | 87 | /* things we could have as /sbin/newfs_* and /sbin/fsck_* */ |
88 | static const char *extern_fs_with_chk[] = { | | 88 | static const char *extern_fs_with_chk[] = { |
89 | "ext2fs", "lfs", "msdos", "v7fs" | | 89 | "ext2fs", "lfs", "msdos", "v7fs" |
90 | }; | | 90 | }; |
91 | | | 91 | |
92 | /* things we could have as /sbin/newfs_* but not /sbin/fsck_* */ | | 92 | /* things we could have as /sbin/newfs_* but not /sbin/fsck_* */ |
93 | static const char *extern_fs_newfs_only[] = { | | 93 | static const char *extern_fs_newfs_only[] = { |
94 | "sysvbfs", "udf" | | 94 | "sysvbfs", "udf" |
95 | }; | | 95 | }; |
96 | | | 96 | |
97 | /* Local prototypes */ | | 97 | /* Local prototypes */ |
98 | static int found_fs(struct data *, size_t, const struct lookfor*); | | 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*); | | 99 | static int found_fs_nocheck(struct data *, size_t, const struct lookfor*); |
100 | static int fsck_preen(const char *, const char *, bool silent); | | 100 | static int fsck_preen(const char *, const char *, bool silent); |
101 | static void fixsb(const char *, const char *); | | 101 | static void fixsb(const char *, const char *); |
102 | | | 102 | |
103 | | | 103 | |
104 | static bool tmpfs_on_var_shm(void); | | 104 | static bool tmpfs_on_var_shm(void); |
105 | | | 105 | |
106 | const char * | | 106 | const char * |
107 | getfslabelname(uint f, uint f_version) | | 107 | getfslabelname(uint f, uint f_version) |
108 | { | | 108 | { |
109 | if (f == FS_TMPFS) | | 109 | if (f == FS_TMPFS) |
110 | return "tmpfs"; | | 110 | return "tmpfs"; |
111 | else if (f == FS_MFS) | | 111 | else if (f == FS_MFS) |
112 | return "mfs"; | | 112 | return "mfs"; |
113 | else if (f == FS_BSDFFS && f_version > 0) | | 113 | else if (f == FS_BSDFFS && f_version > 0) |
114 | return f_version == 2 ? | | 114 | return f_version == 2 ? |
115 | msg_string(MSG_fs_type_ffsv2) : msg_string(MSG_fs_type_ffs); | | 115 | msg_string(MSG_fs_type_ffsv2) : msg_string(MSG_fs_type_ffs); |
116 | else if (f == FS_EX2FS && f_version == 1) | | 116 | else if (f == FS_EX2FS && f_version == 1) |
117 | return msg_string(MSG_fs_type_ext2old); | | 117 | return msg_string(MSG_fs_type_ext2old); |
118 | else if (f >= __arraycount(fstypenames) || fstypenames[f] == NULL) | | 118 | else if (f >= __arraycount(fstypenames) || fstypenames[f] == NULL) |
119 | return "invalid"; | | 119 | return "invalid"; |
120 | return fstypenames[f]; | | 120 | return fstypenames[f]; |
121 | } | | 121 | } |
122 | | | 122 | |
123 | /* | | 123 | /* |
124 | * Decide wether we want to mount a tmpfs on /var/shm: we do this always | | 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, | | 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. | | 126 | * shm_open() and friends will not perform well anyway. |
127 | */ | | 127 | */ |
128 | static bool | | 128 | static bool |
129 | tmpfs_on_var_shm() | | 129 | tmpfs_on_var_shm() |
130 | { | | 130 | { |
131 | uint64_t ram; | | 131 | uint64_t ram; |
132 | size_t len; | | 132 | size_t len; |
133 | | | 133 | |
134 | len = sizeof(ram); | | 134 | len = sizeof(ram); |
135 | if (sysctlbyname("hw.usermem64", &ram, &len, NULL, 0)) | | 135 | if (sysctlbyname("hw.usermem64", &ram, &len, NULL, 0)) |
136 | return false; | | 136 | return false; |
137 | | | 137 | |
138 | return ram > 16 * MEG; | | 138 | return ram > 16 * MEG; |
139 | } | | 139 | } |
140 | | | 140 | |
141 | /* from src/sbin/atactl/atactl.c | | 141 | /* from src/sbin/atactl/atactl.c |
142 | * extract_string: copy a block of bytes out of ataparams and make | | 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 | | 143 | * a proper string out of it, truncating trailing spaces and preserving |
144 | * strict typing. And also, not doing unaligned accesses. | | 144 | * strict typing. And also, not doing unaligned accesses. |
145 | */ | | 145 | */ |
146 | static void | | 146 | static void |
147 | ata_extract_string(char *buf, size_t bufmax, | | 147 | ata_extract_string(char *buf, size_t bufmax, |
148 | uint8_t *bytes, unsigned numbytes, | | 148 | uint8_t *bytes, unsigned numbytes, |
149 | int needswap) | | 149 | int needswap) |
150 | { | | 150 | { |
151 | unsigned i; | | 151 | unsigned i; |
152 | size_t j; | | 152 | size_t j; |
153 | unsigned char ch1, ch2; | | 153 | unsigned char ch1, ch2; |
154 | | | 154 | |
155 | for (i = 0, j = 0; i < numbytes; i += 2) { | | 155 | for (i = 0, j = 0; i < numbytes; i += 2) { |
156 | ch1 = bytes[i]; | | 156 | ch1 = bytes[i]; |
157 | ch2 = bytes[i+1]; | | 157 | ch2 = bytes[i+1]; |
158 | if (needswap && j < bufmax-1) { | | 158 | if (needswap && j < bufmax-1) { |
159 | buf[j++] = ch2; | | 159 | buf[j++] = ch2; |
160 | } | | 160 | } |
161 | if (j < bufmax-1) { | | 161 | if (j < bufmax-1) { |
162 | buf[j++] = ch1; | | 162 | buf[j++] = ch1; |
163 | } | | 163 | } |
164 | if (!needswap && j < bufmax-1) { | | 164 | if (!needswap && j < bufmax-1) { |
165 | buf[j++] = ch2; | | 165 | buf[j++] = ch2; |
166 | } | | 166 | } |
167 | } | | 167 | } |
168 | while (j > 0 && buf[j-1] == ' ') { | | 168 | while (j > 0 && buf[j-1] == ' ') { |
169 | j--; | | 169 | j--; |
170 | } | | 170 | } |
171 | buf[j] = '\0'; | | 171 | buf[j] = '\0'; |
172 | } | | 172 | } |
173 | | | 173 | |
174 | /* | | 174 | /* |
175 | * from src/sbin/scsictl/scsi_subr.c | | 175 | * from src/sbin/scsictl/scsi_subr.c |
176 | */ | | 176 | */ |
177 | #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377') | | 177 | #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377') |
178 | | | 178 | |
179 | static void | | 179 | static void |
180 | scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen) | | 180 | scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen) |
181 | { | | 181 | { |
182 | u_char *dst = (u_char *)sdst; | | 182 | u_char *dst = (u_char *)sdst; |
183 | const u_char *src = (const u_char *)ssrc; | | 183 | const u_char *src = (const u_char *)ssrc; |
184 | | | 184 | |
185 | /* Trim leading and trailing blanks and NULs. */ | | 185 | /* Trim leading and trailing blanks and NULs. */ |
186 | while (slen > 0 && STRVIS_ISWHITE(src[0])) | | 186 | while (slen > 0 && STRVIS_ISWHITE(src[0])) |
187 | ++src, --slen; | | 187 | ++src, --slen; |
188 | while (slen > 0 && STRVIS_ISWHITE(src[slen - 1])) | | 188 | while (slen > 0 && STRVIS_ISWHITE(src[slen - 1])) |
189 | --slen; | | 189 | --slen; |
190 | | | 190 | |
191 | while (slen > 0) { | | 191 | while (slen > 0) { |
192 | if (*src < 0x20 || *src >= 0x80) { | | 192 | if (*src < 0x20 || *src >= 0x80) { |
193 | /* non-printable characters */ | | 193 | /* non-printable characters */ |
194 | dlen -= 4; | | 194 | dlen -= 4; |
195 | if (dlen < 1) | | 195 | if (dlen < 1) |
196 | break; | | 196 | break; |
197 | *dst++ = '\\'; | | 197 | *dst++ = '\\'; |
198 | *dst++ = ((*src & 0300) >> 6) + '0'; | | 198 | *dst++ = ((*src & 0300) >> 6) + '0'; |
199 | *dst++ = ((*src & 0070) >> 3) + '0'; | | 199 | *dst++ = ((*src & 0070) >> 3) + '0'; |
200 | *dst++ = ((*src & 0007) >> 0) + '0'; | | 200 | *dst++ = ((*src & 0007) >> 0) + '0'; |
201 | } else if (*src == '\\') { | | 201 | } else if (*src == '\\') { |
202 | /* quote characters */ | | 202 | /* quote characters */ |
203 | dlen -= 2; | | 203 | dlen -= 2; |
204 | if (dlen < 1) | | 204 | if (dlen < 1) |
205 | break; | | 205 | break; |
206 | *dst++ = '\\'; | | 206 | *dst++ = '\\'; |
207 | *dst++ = '\\'; | | 207 | *dst++ = '\\'; |
208 | } else { | | 208 | } else { |
209 | /* normal characters */ | | 209 | /* normal characters */ |
210 | if (--dlen < 1) | | 210 | if (--dlen < 1) |
211 | break; | | 211 | break; |
212 | *dst++ = *src; | | 212 | *dst++ = *src; |
213 | } | | 213 | } |
214 | ++src, --slen; | | 214 | ++src, --slen; |
215 | } | | 215 | } |
216 | | | 216 | |
217 | *dst++ = 0; | | 217 | *dst++ = 0; |
218 | } | | 218 | } |
219 | | | 219 | |
220 | | | 220 | |
221 | static int | | 221 | static int |
222 | get_descr_scsi(struct disk_desc *dd) | | 222 | get_descr_scsi(struct disk_desc *dd) |
223 | { | | 223 | { |
224 | struct scsipi_inquiry_data inqbuf; | | 224 | struct scsipi_inquiry_data inqbuf; |
225 | struct scsipi_inquiry cmd; | | 225 | struct scsipi_inquiry cmd; |
226 | scsireq_t req; | | 226 | scsireq_t req; |
227 | /* x4 in case every character is escaped, +1 for NUL. */ | | 227 | /* x4 in case every character is escaped, +1 for NUL. */ |
228 | char vendor[(sizeof(inqbuf.vendor) * 4) + 1], | | 228 | char vendor[(sizeof(inqbuf.vendor) * 4) + 1], |
229 | product[(sizeof(inqbuf.product) * 4) + 1], | | 229 | product[(sizeof(inqbuf.product) * 4) + 1], |
230 | revision[(sizeof(inqbuf.revision) * 4) + 1]; | | 230 | revision[(sizeof(inqbuf.revision) * 4) + 1]; |
231 | char size[5]; | | 231 | char size[5]; |
232 | | | 232 | |
233 | memset(&inqbuf, 0, sizeof(inqbuf)); | | 233 | memset(&inqbuf, 0, sizeof(inqbuf)); |
234 | memset(&cmd, 0, sizeof(cmd)); | | 234 | memset(&cmd, 0, sizeof(cmd)); |
235 | memset(&req, 0, sizeof(req)); | | 235 | memset(&req, 0, sizeof(req)); |
236 | | | 236 | |
237 | cmd.opcode = INQUIRY; | | 237 | cmd.opcode = INQUIRY; |
238 | cmd.length = sizeof(inqbuf); | | 238 | cmd.length = sizeof(inqbuf); |
239 | memcpy(req.cmd, &cmd, sizeof(cmd)); | | 239 | memcpy(req.cmd, &cmd, sizeof(cmd)); |
240 | req.cmdlen = sizeof(cmd); | | 240 | req.cmdlen = sizeof(cmd); |
241 | req.databuf = &inqbuf; | | 241 | req.databuf = &inqbuf; |
242 | req.datalen = sizeof(inqbuf); | | 242 | req.datalen = sizeof(inqbuf); |
243 | req.timeout = 10000; | | 243 | req.timeout = 10000; |
244 | req.flags = SCCMD_READ; | | 244 | req.flags = SCCMD_READ; |
245 | req.senselen = SENSEBUFLEN; | | 245 | req.senselen = SENSEBUFLEN; |
246 | | | 246 | |
247 | if (!disk_ioctl(dd->dd_name, SCIOCCOMMAND, &req) | | 247 | if (!disk_ioctl(dd->dd_name, SCIOCCOMMAND, &req) |
248 | || req.retsts != SCCMD_OK) | | 248 | || req.retsts != SCCMD_OK) |
249 | return 0; | | 249 | return 0; |
250 | | | 250 | |
251 | scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, | | 251 | scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor, |
252 | sizeof(inqbuf.vendor)); | | 252 | sizeof(inqbuf.vendor)); |
253 | scsi_strvis(product, sizeof(product), inqbuf.product, | | 253 | scsi_strvis(product, sizeof(product), inqbuf.product, |
254 | sizeof(inqbuf.product)); | | 254 | sizeof(inqbuf.product)); |
255 | scsi_strvis(revision, sizeof(revision), inqbuf.revision, | | 255 | scsi_strvis(revision, sizeof(revision), inqbuf.revision, |
256 | sizeof(inqbuf.revision)); | | 256 | sizeof(inqbuf.revision)); |
257 | | | 257 | |
258 | humanize_number(size, sizeof(size), | | 258 | humanize_number(size, sizeof(size), |
259 | (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, | | 259 | (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, |
260 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); | | 260 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); |
261 | | | 261 | |
262 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), | | 262 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), |
263 | "%s (%s, %s %s)", | | 263 | "%s (%s, %s %s)", |
264 | dd->dd_name, size, vendor, product); | | 264 | dd->dd_name, size, vendor, product); |
265 | | | 265 | |
266 | return 1; | | 266 | return 1; |
267 | } | | 267 | } |
268 | | | 268 | |
269 | static int | | 269 | static int |
270 | get_descr_ata(struct disk_desc *dd) | | 270 | get_descr_ata(struct disk_desc *dd) |
271 | { | | 271 | { |
272 | struct atareq req; | | 272 | struct atareq req; |
273 | static union { | | 273 | static union { |
274 | unsigned char inbuf[DEV_BSIZE]; | | 274 | unsigned char inbuf[DEV_BSIZE]; |
275 | struct ataparams inqbuf; | | 275 | struct ataparams inqbuf; |
276 | } inbuf; | | 276 | } inbuf; |
277 | struct ataparams *inqbuf = &inbuf.inqbuf; | | 277 | struct ataparams *inqbuf = &inbuf.inqbuf; |
278 | char model[sizeof(inqbuf->atap_model)+1]; | | 278 | char model[sizeof(inqbuf->atap_model)+1]; |
279 | char size[5]; | | 279 | char size[5]; |
280 | int needswap = 0; | | 280 | int needswap = 0; |
281 | | | 281 | |
282 | memset(&inbuf, 0, sizeof(inbuf)); | | 282 | memset(&inbuf, 0, sizeof(inbuf)); |
283 | memset(&req, 0, sizeof(req)); | | 283 | memset(&req, 0, sizeof(req)); |
284 | | | 284 | |
285 | req.flags = ATACMD_READ; | | 285 | req.flags = ATACMD_READ; |
286 | req.command = WDCC_IDENTIFY; | | 286 | req.command = WDCC_IDENTIFY; |
287 | req.databuf = (void *)&inbuf; | | 287 | req.databuf = (void *)&inbuf; |
288 | req.datalen = sizeof(inbuf); | | 288 | req.datalen = sizeof(inbuf); |
289 | req.timeout = 1000; | | 289 | req.timeout = 1000; |
290 | | | 290 | |
291 | if (!disk_ioctl(dd->dd_name, ATAIOCCOMMAND, &req) | | 291 | if (!disk_ioctl(dd->dd_name, ATAIOCCOMMAND, &req) |
292 | || req.retsts != ATACMD_OK) | | 292 | || req.retsts != ATACMD_OK) |
293 | return 0; | | 293 | return 0; |
294 | | | 294 | |
295 | #if BYTE_ORDER == LITTLE_ENDIAN | | 295 | #if BYTE_ORDER == LITTLE_ENDIAN |
296 | /* | | 296 | /* |
297 | * On little endian machines, we need to shuffle the string | | 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 | | 298 | * byte order. However, we don't have to do this for NEC or |
299 | * Mitsumi ATAPI devices | | 299 | * Mitsumi ATAPI devices |
300 | */ | | 300 | */ |
301 | | | 301 | |
302 | if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC && | | 302 | if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC && |
303 | (inqbuf->atap_config & WDC_CFG_ATAPI) && | | 303 | (inqbuf->atap_config & WDC_CFG_ATAPI) && |
304 | ((inqbuf->atap_model[0] == 'N' && | | 304 | ((inqbuf->atap_model[0] == 'N' && |
305 | inqbuf->atap_model[1] == 'E') || | | 305 | inqbuf->atap_model[1] == 'E') || |
306 | (inqbuf->atap_model[0] == 'F' && | | 306 | (inqbuf->atap_model[0] == 'F' && |
307 | inqbuf->atap_model[1] == 'X')))) { | | 307 | inqbuf->atap_model[1] == 'X')))) { |
308 | needswap = 1; | | 308 | needswap = 1; |
309 | } | | 309 | } |
310 | #endif | | 310 | #endif |
311 | | | 311 | |
312 | ata_extract_string(model, sizeof(model), | | 312 | ata_extract_string(model, sizeof(model), |
313 | inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap); | | 313 | inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap); |
314 | humanize_number(size, sizeof(size), | | 314 | humanize_number(size, sizeof(size), |
315 | (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, | | 315 | (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, |
316 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); | | 316 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); |
317 | | | 317 | |
318 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)", | | 318 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)", |
319 | dd->dd_name, size, model); | | 319 | dd->dd_name, size, model); |
320 | | | 320 | |
321 | return 1; | | 321 | return 1; |
322 | } | | 322 | } |
323 | | | 323 | |
324 | static void | | 324 | static void |
325 | get_descr(struct disk_desc *dd) | | 325 | get_descr(struct disk_desc *dd) |
326 | { | | 326 | { |
327 | char size[5]; | | 327 | char size[5]; |
328 | dd->dd_descr[0] = '\0'; | | 328 | dd->dd_descr[0] = '\0'; |
329 | | | 329 | |
330 | /* try ATA */ | | 330 | /* try ATA */ |
331 | if (get_descr_ata(dd)) | | 331 | if (get_descr_ata(dd)) |
332 | goto done; | | 332 | goto done; |
333 | /* try SCSI */ | | 333 | /* try SCSI */ |
334 | if (get_descr_scsi(dd)) | | 334 | if (get_descr_scsi(dd)) |
335 | goto done; | | 335 | goto done; |
336 | | | 336 | |
337 | /* XXX: identify for ld @ NVME or microSD */ | | 337 | /* XXX: identify for ld @ NVME or microSD */ |
338 | | | 338 | |
339 | /* XXX: get description from raid, cgd, vnd... */ | | 339 | /* XXX: get description from raid, cgd, vnd... */ |
340 | done: | | 340 | done: |
341 | /* punt, just give some generic info */ | | 341 | /* punt, just give some generic info */ |
342 | humanize_number(size, sizeof(size), | | 342 | humanize_number(size, sizeof(size), |
343 | (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, | | 343 | (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec, |
344 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); | | 344 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); |
345 | | | 345 | |
346 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), | | 346 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), |
347 | "%s (%s)", dd->dd_name, size); | | 347 | "%s (%s)", dd->dd_name, size); |
348 | } | | 348 | } |
349 | | | 349 | |
350 | /* | | 350 | /* |
351 | * State for helper callback for get_default_cdrom | | 351 | * State for helper callback for get_default_cdrom |
352 | */ | | 352 | */ |
353 | struct default_cdrom_data { | | 353 | struct default_cdrom_data { |
354 | char *device; | | 354 | char *device; |
355 | size_t max_len; | | 355 | size_t max_len; |
356 | bool found; | | 356 | bool found; |
357 | }; | | 357 | }; |
358 | | | 358 | |
359 | /* | | 359 | /* |
360 | * Helper function for get_default_cdrom, gets passed a device | | 360 | * Helper function for get_default_cdrom, gets passed a device |
361 | * name and a void pointer to default_cdrom_data. | | 361 | * name and a void pointer to default_cdrom_data. |
362 | */ | | 362 | */ |
363 | static bool | | 363 | static bool |
364 | get_default_cdrom_helper(void *state, const char *dev) | | 364 | get_default_cdrom_helper(void *state, const char *dev) |
365 | { | | 365 | { |
366 | struct default_cdrom_data *data = state; | | 366 | struct default_cdrom_data *data = state; |
367 | | | 367 | |
368 | if (!is_cdrom_device(dev, false)) | | 368 | if (!is_cdrom_device(dev, false)) |
369 | return true; | | 369 | return true; |
370 | | | 370 | |
371 | strlcpy(data->device, dev, data->max_len); | | 371 | strlcpy(data->device, dev, data->max_len); |
372 | strlcat(data->device, "a", data->max_len); /* default to partition a */ | | 372 | strlcat(data->device, "a", data->max_len); /* default to partition a */ |
373 | data->found = true; | | 373 | data->found = true; |
374 | | | 374 | |
375 | return false; /* one is enough, stop iteration */ | | 375 | return false; /* one is enough, stop iteration */ |
376 | } | | 376 | } |
377 | | | 377 | |
378 | /* | | 378 | /* |
379 | * Set the argument to the name of the first CD devices actually | | 379 | * Set the argument to the name of the first CD devices actually |
380 | * available, leave it unmodified otherwise. | | 380 | * available, leave it unmodified otherwise. |
381 | * Return true if a device has been found. | | 381 | * Return true if a device has been found. |
382 | */ | | 382 | */ |
383 | bool | | 383 | bool |
384 | get_default_cdrom(char *cd, size_t max_len) | | 384 | get_default_cdrom(char *cd, size_t max_len) |
385 | { | | 385 | { |
386 | struct default_cdrom_data state; | | 386 | struct default_cdrom_data state; |
387 | | | 387 | |
388 | state.device = cd; | | 388 | state.device = cd; |
389 | state.max_len = max_len; | | 389 | state.max_len = max_len; |
390 | state.found = false; | | 390 | state.found = false; |
391 | | | 391 | |
392 | if (enumerate_disks(&state, get_default_cdrom_helper)) | | 392 | if (enumerate_disks(&state, get_default_cdrom_helper)) |
393 | return state.found; | | 393 | return state.found; |
394 | | | 394 | |
395 | return false; | | 395 | return false; |
396 | } | | 396 | } |
397 | | | 397 | |
398 | static bool | | 398 | static bool |
399 | get_wedge_descr(struct disk_desc *dd) | | 399 | get_wedge_descr(struct disk_desc *dd) |
400 | { | | 400 | { |
401 | struct dkwedge_info dkw; | | 401 | struct dkwedge_info dkw; |
402 | | | 402 | |
403 | if (!get_wedge_info(dd->dd_name, &dkw)) | | 403 | if (!get_wedge_info(dd->dd_name, &dkw)) |
404 | return false; | | 404 | return false; |
405 | | | 405 | |
406 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s@%s)", | | 406 | snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s@%s)", |
407 | dkw.dkw_wname, dkw.dkw_devname, dkw.dkw_parent); | | 407 | dkw.dkw_wname, dkw.dkw_devname, dkw.dkw_parent); |
408 | return true; | | 408 | return true; |
409 | } | | 409 | } |
410 | | | 410 | |
411 | static bool | | 411 | static bool |
412 | get_name_and_parent(const char *dev, char *name, char *parent) | | 412 | get_name_and_parent(const char *dev, char *name, char *parent) |
413 | { | | 413 | { |
414 | struct dkwedge_info dkw; | | 414 | struct dkwedge_info dkw; |
415 | | | 415 | |
416 | if (!get_wedge_info(dev, &dkw)) | | 416 | if (!get_wedge_info(dev, &dkw)) |
417 | return false; | | 417 | return false; |
418 | strcpy(name, (const char *)dkw.dkw_wname); | | 418 | strcpy(name, (const char *)dkw.dkw_wname); |
419 | strcpy(parent, dkw.dkw_parent); | | 419 | strcpy(parent, dkw.dkw_parent); |
420 | return true; | | 420 | return true; |
421 | } | | 421 | } |
422 | | | 422 | |
423 | static bool | | 423 | static bool |
424 | find_swap_part_on(const char *dev, char *swap_name) | | 424 | find_swap_part_on(const char *dev, char *swap_name) |
425 | { | | 425 | { |
426 | struct dkwedge_list dkwl; | | 426 | struct dkwedge_list dkwl; |
427 | struct dkwedge_info *dkw; | | 427 | struct dkwedge_info *dkw; |
428 | u_int i; | | 428 | u_int i; |
429 | bool res = false; | | 429 | bool res = false; |
430 | | | 430 | |
431 | if (!get_wedge_list(dev, &dkwl)) | | 431 | if (!get_wedge_list(dev, &dkwl)) |
432 | return false; | | 432 | return false; |
433 | | | 433 | |
434 | dkw = dkwl.dkwl_buf; | | 434 | dkw = dkwl.dkwl_buf; |
435 | for (i = 0; i < dkwl.dkwl_nwedges; i++) { | | 435 | for (i = 0; i < dkwl.dkwl_nwedges; i++) { |
436 | res = strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) == 0; | | 436 | res = strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) == 0; |
437 | if (res) { | | 437 | if (res) { |
438 | strcpy(swap_name, (const char*)dkw[i].dkw_wname); | | 438 | strcpy(swap_name, (const char*)dkw[i].dkw_wname); |
439 | break; | | 439 | break; |
440 | } | | 440 | } |
441 | } | | 441 | } |
442 | free(dkwl.dkwl_buf); | | 442 | free(dkwl.dkwl_buf); |
443 | | | 443 | |
444 | return res; | | 444 | return res; |
445 | } | | 445 | } |
446 | | | 446 | |
447 | static bool | | 447 | static bool |
448 | is_ffs_wedge(const char *dev) | | 448 | is_ffs_wedge(const char *dev) |
449 | { | | 449 | { |
450 | struct dkwedge_info dkw; | | 450 | struct dkwedge_info dkw; |
451 | | | 451 | |
452 | if (!get_wedge_info(dev, &dkw)) | | 452 | if (!get_wedge_info(dev, &dkw)) |
453 | return false; | | 453 | return false; |
454 | | | 454 | |
455 | return strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) == 0; | | 455 | return strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) == 0; |
456 | } | | 456 | } |
457 | | | 457 | |
458 | /* | | 458 | /* |
459 | * Does this device match an entry in our default CDROM device list? | | 459 | * Does this device match an entry in our default CDROM device list? |
460 | * If looking for install targets, we also flag floopy devices. | | 460 | * If looking for install targets, we also flag floopy devices. |
461 | */ | | 461 | */ |
462 | bool | | 462 | bool |
463 | is_cdrom_device(const char *dev, bool as_target) | | 463 | is_cdrom_device(const char *dev, bool as_target) |
464 | { | | 464 | { |
465 | static const char *target_devices[] = { | | 465 | static const char *target_devices[] = { |
466 | #ifdef CD_NAMES | | 466 | #ifdef CD_NAMES |
467 | CD_NAMES | | 467 | CD_NAMES |
468 | #endif | | 468 | #endif |
469 | #if defined(CD_NAMES) && defined(FLOPPY_NAMES) | | 469 | #if defined(CD_NAMES) && defined(FLOPPY_NAMES) |
470 | , | | 470 | , |
471 | #endif | | 471 | #endif |
472 | #ifdef FLOPPY_NAMES | | 472 | #ifdef FLOPPY_NAMES |
473 | FLOPPY_NAMES | | 473 | FLOPPY_NAMES |
474 | #endif | | 474 | #endif |
475 | #if defined(CD_NAMES) || defined(FLOPPY_NAMES) | | 475 | #if defined(CD_NAMES) || defined(FLOPPY_NAMES) |
476 | , | | 476 | , |
477 | #endif | | 477 | #endif |
478 | 0 | | 478 | 0 |
479 | }; | | 479 | }; |
480 | static const char *src_devices[] = { | | 480 | static const char *src_devices[] = { |
481 | #ifdef CD_NAMES | | 481 | #ifdef CD_NAMES |
482 | CD_NAMES , | | 482 | CD_NAMES , |
483 | #endif | | 483 | #endif |
484 | 0 | | 484 | 0 |
485 | }; | | 485 | }; |
486 | | | 486 | |
487 | for (const char **dev_pat = as_target ? target_devices : src_devices; | | 487 | for (const char **dev_pat = as_target ? target_devices : src_devices; |
488 | *dev_pat; dev_pat++) | | 488 | *dev_pat; dev_pat++) |
489 | if (fnmatch(*dev_pat, dev, 0) == 0) | | 489 | if (fnmatch(*dev_pat, dev, 0) == 0) |
490 | return true; | | 490 | return true; |
491 | | | 491 | |
492 | return false; | | 492 | return false; |
493 | } | | 493 | } |
494 | | | 494 | |
495 | /* does this device match any entry in the driver list? */ | | 495 | /* does this device match any entry in the driver list? */ |
496 | static bool | | 496 | static bool |
497 | dev_in_list(const char *dev, const char **list) | | 497 | dev_in_list(const char *dev, const char **list) |
498 | { | | 498 | { |
499 | | | 499 | |
500 | for ( ; *list; list++) { | | 500 | for ( ; *list; list++) { |
501 | | | 501 | |
502 | size_t len = strlen(*list); | | 502 | size_t len = strlen(*list); |
503 | | | 503 | |
504 | /* start of name matches? */ | | 504 | /* start of name matches? */ |
505 | if (strncmp(dev, *list, len) == 0) { | | 505 | if (strncmp(dev, *list, len) == 0) { |
506 | char *endp; | | 506 | char *endp; |
507 | int e; | | 507 | int e; |
508 | | | 508 | |
509 | /* remainder of name is a decimal number? */ | | 509 | /* remainder of name is a decimal number? */ |
510 | strtou(dev+len, &endp, 10, 0, INT_MAX, &e); | | 510 | strtou(dev+len, &endp, 10, 0, INT_MAX, &e); |
511 | if (endp && *endp == 0 && e == 0) | | 511 | if (endp && *endp == 0 && e == 0) |
512 | return true; | | 512 | return true; |
513 | } | | 513 | } |
514 | } | | 514 | } |
515 | | | 515 | |
516 | return false; | | 516 | return false; |
517 | } | | 517 | } |
518 | | | 518 | |
519 | bool | | 519 | bool |
520 | is_bootable_device(const char *dev) | | 520 | is_bootable_device(const char *dev) |
521 | { | | 521 | { |
522 | static const char *non_bootable_devs[] = { | | 522 | static const char *non_bootable_devs[] = { |
523 | "raid", /* bootcode lives outside of raid */ | | 523 | "raid", /* bootcode lives outside of raid */ |
524 | "xbd", /* xen virtual device, can not boot from that */ | | 524 | "xbd", /* xen virtual device, can not boot from that */ |
525 | NULL | | 525 | NULL |
526 | }; | | 526 | }; |
527 | | | 527 | |
528 | return !dev_in_list(dev, non_bootable_devs); | | 528 | return !dev_in_list(dev, non_bootable_devs); |
529 | } | | 529 | } |
530 | | | 530 | |
531 | bool | | 531 | bool |
532 | is_partitionable_device(const char *dev) | | 532 | is_partitionable_device(const char *dev) |
533 | { | | 533 | { |
534 | static const char *non_partitionable_devs[] = { | | 534 | static const char *non_partitionable_devs[] = { |
535 | "dk", /* this is already a partitioned slice */ | | 535 | "dk", /* this is already a partitioned slice */ |
536 | NULL | | 536 | NULL |
537 | }; | | 537 | }; |
538 | | | 538 | |
539 | return !dev_in_list(dev, non_partitionable_devs); | | 539 | return !dev_in_list(dev, non_partitionable_devs); |
540 | } | | 540 | } |
541 | | | 541 | |
542 | /* | | 542 | /* |
543 | * Multi-purpose helper function: | | 543 | * Multi-purpose helper function: |
544 | * iterate all known disks, invoke a callback for each. | | 544 | * iterate all known disks, invoke a callback for each. |
545 | * Stop iteration when the callback returns false. | | 545 | * Stop iteration when the callback returns false. |
546 | * Return true when iteration actually happend, false on error. | | 546 | * Return true when iteration actually happend, false on error. |
547 | */ | | 547 | */ |
548 | bool | | 548 | bool |
549 | enumerate_disks(void *state, bool (*func)(void *state, const char *dev)) | | 549 | enumerate_disks(void *state, bool (*func)(void *state, const char *dev)) |
550 | { | | 550 | { |
551 | static const int mib[] = { CTL_HW, HW_DISKNAMES }; | | 551 | static const int mib[] = { CTL_HW, HW_DISKNAMES }; |
552 | static const unsigned int miblen = __arraycount(mib); | | 552 | static const unsigned int miblen = __arraycount(mib); |
553 | const char *xd; | | 553 | const char *xd; |
554 | char *disk_names; | | 554 | char *disk_names; |
555 | size_t len; | | 555 | size_t len; |
556 | | | 556 | |
557 | if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) | | 557 | if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) |
558 | return false; | | 558 | return false; |
559 | | | 559 | |
560 | disk_names = malloc(len); | | 560 | disk_names = malloc(len); |
561 | if (disk_names == NULL) | | 561 | if (disk_names == NULL) |
562 | return false; | | 562 | return false; |
563 | | | 563 | |
564 | if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) { | | 564 | if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) { |
565 | free(disk_names); | | 565 | free(disk_names); |
566 | return false; | | 566 | return false; |
567 | } | | 567 | } |
568 | | | 568 | |
569 | for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) { | | 569 | for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) { |
570 | if (!(*func)(state, xd)) | | 570 | if (!(*func)(state, xd)) |
571 | break; | | 571 | break; |
572 | } | | 572 | } |
573 | free(disk_names); | | 573 | free(disk_names); |
574 | | | 574 | |
575 | return true; | | 575 | return true; |
576 | } | | 576 | } |
577 | | | 577 | |
578 | /* | | 578 | /* |
579 | * Helper state for get_disks | | 579 | * Helper state for get_disks |
580 | */ | | 580 | */ |
581 | struct get_disks_state { | | 581 | struct get_disks_state { |
582 | int numdisks; | | 582 | int numdisks; |
583 | struct disk_desc *dd; | | 583 | struct disk_desc *dd; |
584 | bool with_non_partitionable; | | 584 | bool with_non_partitionable; |
585 | }; | | 585 | }; |
586 | | | 586 | |
587 | /* | | 587 | /* |
588 | * Helper function for get_disks enumartion | | 588 | * Helper function for get_disks enumartion |
589 | */ | | 589 | */ |
590 | static bool | | 590 | static bool |
591 | get_disks_helper(void *arg, const char *dev) | | 591 | get_disks_helper(void *arg, const char *dev) |
592 | { | | 592 | { |
593 | struct get_disks_state *state = arg; | | 593 | struct get_disks_state *state = arg; |
594 | struct disk_geom geo; | | 594 | struct disk_geom geo; |
595 | | | 595 | |
596 | /* is this a CD device? */ | | 596 | /* is this a CD device? */ |
597 | if (is_cdrom_device(dev, true)) | | 597 | if (is_cdrom_device(dev, true)) |
598 | return true; | | 598 | return true; |
599 | | | 599 | |
600 | memset(state->dd, 0, sizeof(*state->dd)); | | 600 | memset(state->dd, 0, sizeof(*state->dd)); |
601 | strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2); | | 601 | strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2); |
602 | state->dd->dd_no_mbr = !is_bootable_device(dev); | | 602 | state->dd->dd_no_mbr = !is_bootable_device(dev); |
603 | state->dd->dd_no_part = !is_partitionable_device(dev); | | 603 | state->dd->dd_no_part = !is_partitionable_device(dev); |
604 | | | 604 | |
605 | if (state->dd->dd_no_part && !state->with_non_partitionable) | | 605 | if (state->dd->dd_no_part && !state->with_non_partitionable) |
606 | return true; | | 606 | return true; |
607 | | | 607 | |
608 | if (!get_disk_geom(state->dd->dd_name, &geo)) { | | 608 | if (!get_disk_geom(state->dd->dd_name, &geo)) { |
609 | if (errno == ENOENT) | | 609 | if (errno == ENOENT) |
610 | return true; | | 610 | return true; |
611 | if (errno != ENOTTY || !state->dd->dd_no_part) | | 611 | if (errno != ENOTTY || !state->dd->dd_no_part) |
612 | /* | | 612 | /* |
613 | * Allow plain partitions, | | 613 | * Allow plain partitions, |
614 | * like already existing wedges | | 614 | * like already existing wedges |
615 | * (like dk0) if marked as | | 615 | * (like dk0) if marked as |
616 | * non-partitioning device. | | 616 | * non-partitioning device. |
617 | * For all other cases, continue | | 617 | * For all other cases, continue |
618 | * with the next disk. | | 618 | * with the next disk. |
619 | */ | | 619 | */ |
620 | return true; | | 620 | return true; |
621 | if (!is_ffs_wedge(state->dd->dd_name)) | | 621 | if (!is_ffs_wedge(state->dd->dd_name)) |
622 | return true; | | 622 | return true; |
623 | } | | 623 | } |
624 | | | 624 | |
625 | /* | | 625 | /* |
626 | * Exclude a disk mounted as root partition, | | 626 | * Exclude a disk mounted as root partition, |
627 | * in case of install-image on a USB memstick. | | 627 | * in case of install-image on a USB memstick. |
628 | */ | | 628 | */ |
629 | if (is_active_rootpart(state->dd->dd_name, | | 629 | if (is_active_rootpart(state->dd->dd_name, |
630 | state->dd->dd_no_part ? -1 : 0)) | | 630 | state->dd->dd_no_part ? -1 : 0)) |
631 | return true; | | 631 | return true; |
632 | | | 632 | |
633 | state->dd->dd_cyl = geo.dg_ncylinders; | | 633 | state->dd->dd_cyl = geo.dg_ncylinders; |
634 | state->dd->dd_head = geo.dg_ntracks; | | 634 | state->dd->dd_head = geo.dg_ntracks; |
635 | state->dd->dd_sec = geo.dg_nsectors; | | 635 | state->dd->dd_sec = geo.dg_nsectors; |
636 | state->dd->dd_secsize = geo.dg_secsize; | | 636 | state->dd->dd_secsize = geo.dg_secsize; |
637 | state->dd->dd_totsec = geo.dg_secperunit; | | 637 | state->dd->dd_totsec = geo.dg_secperunit; |
638 | | | 638 | |
639 | if (!state->dd->dd_no_part || !get_wedge_descr(state->dd)) | | 639 | if (!state->dd->dd_no_part || !get_wedge_descr(state->dd)) |
640 | get_descr(state->dd); | | 640 | get_descr(state->dd); |
641 | state->dd++; | | 641 | state->dd++; |
642 | state->numdisks++; | | 642 | state->numdisks++; |
643 | if (state->numdisks == MAX_DISKS) | | 643 | if (state->numdisks == MAX_DISKS) |
644 | return false; | | 644 | return false; |
645 | | | 645 | |
646 | return true; | | 646 | return true; |
647 | } | | 647 | } |
648 | | | 648 | |
649 | /* | | 649 | /* |
650 | * Get all disk devices that are not CDs. | | 650 | * Get all disk devices that are not CDs. |
651 | * Optionally leave out those that can not be partitioned further. | | 651 | * Optionally leave out those that can not be partitioned further. |
652 | */ | | 652 | */ |
653 | static int | | 653 | static int |
654 | get_disks(struct disk_desc *dd, bool with_non_partitionable) | | 654 | get_disks(struct disk_desc *dd, bool with_non_partitionable) |
655 | { | | 655 | { |
656 | struct get_disks_state state; | | 656 | struct get_disks_state state; |
657 | | | 657 | |
658 | /* initialize */ | | 658 | /* initialize */ |
659 | state.numdisks = 0; | | 659 | state.numdisks = 0; |
660 | state.dd = dd; | | 660 | state.dd = dd; |
661 | state.with_non_partitionable = with_non_partitionable; | | 661 | state.with_non_partitionable = with_non_partitionable; |
662 | | | 662 | |
663 | if (enumerate_disks(&state, get_disks_helper)) | | 663 | if (enumerate_disks(&state, get_disks_helper)) |
664 | return state.numdisks; | | 664 | return state.numdisks; |
665 | | | 665 | |
666 | return 0; | | 666 | return 0; |
667 | } | | 667 | } |
668 | | | 668 | |
669 | #ifdef DEBUG_VERBOSE | | 669 | #ifdef DEBUG_VERBOSE |
670 | static void | | 670 | static void |
671 | dump_parts(const struct disk_partitions *parts) | | 671 | dump_parts(const struct disk_partitions *parts) |
672 | { | | 672 | { |
673 | fprintf(stderr, "%s partitions on %s:\n", | | 673 | fprintf(stderr, "%s partitions on %s:\n", |
674 | MSG_XLAT(parts->pscheme->short_name), parts->disk); | | 674 | MSG_XLAT(parts->pscheme->short_name), parts->disk); |
675 | | | 675 | |
676 | for (size_t p = 0; p < parts->num_part; p++) { | | 676 | for (size_t p = 0; p < parts->num_part; p++) { |
677 | struct disk_part_info info; | | 677 | struct disk_part_info info; |
678 | | | 678 | |
679 | if (parts->pscheme->get_part_info( | | 679 | if (parts->pscheme->get_part_info( |
680 | parts, p, &info)) { | | 680 | parts, p, &info)) { |
681 | fprintf(stderr, " #%zu: start: %" PRIu64 " " | | 681 | fprintf(stderr, " #%zu: start: %" PRIu64 " " |
682 | "size: %" PRIu64 ", flags: %x\n", | | 682 | "size: %" PRIu64 ", flags: %x\n", |
683 | p, info.start, info.size, | | 683 | p, info.start, info.size, |
684 | info.flags); | | 684 | info.flags); |
685 | if (info.nat_type) | | 685 | if (info.nat_type) |
686 | fprintf(stderr, "\ttype: %s\n", | | 686 | fprintf(stderr, "\ttype: %s\n", |
687 | info.nat_type->description); | | 687 | info.nat_type->description); |
688 | } else { | | 688 | } else { |
689 | fprintf(stderr, "failed to get info " | | 689 | fprintf(stderr, "failed to get info " |
690 | "for partition #%zu\n", p); | | 690 | "for partition #%zu\n", p); |
691 | } | | 691 | } |
692 | } | | 692 | } |
693 | fprintf(stderr, "%" PRIu64 " sectors free, disk size %" PRIu64 | | 693 | fprintf(stderr, "%" PRIu64 " sectors free, disk size %" PRIu64 |
694 | " sectors, %zu partitions used\n", parts->free_space, | | 694 | " sectors, %zu partitions used\n", parts->free_space, |
695 | parts->disk_size, parts->num_part); | | 695 | parts->disk_size, parts->num_part); |
696 | } | | 696 | } |
697 | #endif | | 697 | #endif |
698 | | | 698 | |
699 | static bool | | 699 | static bool |
700 | delete_scheme(struct pm_devs *p) | | 700 | delete_scheme(struct pm_devs *p) |
701 | { | | 701 | { |
702 | | | 702 | |
703 | if (!ask_noyes(MSG_removepartswarn)) | | 703 | if (!ask_noyes(MSG_removepartswarn)) |
704 | return false; | | 704 | return false; |
705 | | | 705 | |
706 | p->parts->pscheme->free(p->parts); | | 706 | p->parts->pscheme->free(p->parts); |
707 | p->parts = NULL; | | 707 | p->parts = NULL; |
708 | return true; | | 708 | return true; |
709 | } | | 709 | } |
710 | | | 710 | |
711 | | | 711 | |
712 | static void | | 712 | static void |
713 | convert_copy(struct disk_partitions *old_parts, | | 713 | convert_copy(struct disk_partitions *old_parts, |
714 | struct disk_partitions *new_parts) | | 714 | struct disk_partitions *new_parts) |
715 | { | | 715 | { |
716 | struct disk_part_info oinfo, ninfo; | | 716 | struct disk_part_info oinfo, ninfo; |
717 | part_id i; | | 717 | part_id i; |
718 | | | 718 | |
719 | for (i = 0; i < old_parts->num_part; i++) { | | 719 | for (i = 0; i < old_parts->num_part; i++) { |
720 | if (!old_parts->pscheme->get_part_info(old_parts, i, &oinfo)) | | 720 | if (!old_parts->pscheme->get_part_info(old_parts, i, &oinfo)) |
721 | continue; | | 721 | continue; |
722 | | | 722 | |
723 | if (oinfo.flags & PTI_PSCHEME_INTERNAL) | | 723 | if (oinfo.flags & PTI_PSCHEME_INTERNAL) |
724 | continue; | | 724 | continue; |
725 | | | 725 | |
726 | if (oinfo.flags & PTI_SEC_CONTAINER) { | | 726 | if (oinfo.flags & PTI_SEC_CONTAINER) { |
727 | if (old_parts->pscheme->secondary_partitions) { | | 727 | if (old_parts->pscheme->secondary_partitions) { |
728 | struct disk_partitions *sec_part = | | 728 | struct disk_partitions *sec_part = |
729 | old_parts->pscheme-> | | 729 | old_parts->pscheme-> |
730 | secondary_partitions( | | 730 | secondary_partitions( |
731 | old_parts, oinfo.start, false); | | 731 | old_parts, oinfo.start, false); |
732 | if (sec_part) | | 732 | if (sec_part) |
733 | convert_copy(sec_part, new_parts); | | 733 | convert_copy(sec_part, new_parts); |
734 | } | | 734 | } |
735 | continue; | | 735 | continue; |
736 | } | | 736 | } |
737 | | | 737 | |
738 | if (!new_parts->pscheme->adapt_foreign_part_info(new_parts, | | 738 | if (!new_parts->pscheme->adapt_foreign_part_info(new_parts, |
739 | &ninfo, old_parts->pscheme, &oinfo)) | | 739 | &ninfo, old_parts->pscheme, &oinfo)) |
740 | continue; | | 740 | continue; |
741 | new_parts->pscheme->add_partition(new_parts, &ninfo, NULL); | | 741 | new_parts->pscheme->add_partition(new_parts, &ninfo, NULL); |
742 | } | | 742 | } |
743 | } | | 743 | } |
744 | | | 744 | |
745 | bool | | 745 | bool |
746 | convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg) | | 746 | convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg) |
747 | { | | 747 | { |
748 | struct disk_partitions *old_parts, *new_parts; | | 748 | struct disk_partitions *old_parts, *new_parts; |
749 | const struct disk_partitioning_scheme *new_scheme; | | 749 | const struct disk_partitioning_scheme *new_scheme; |
750 | | | 750 | |
751 | *err_msg = NULL; | | 751 | *err_msg = NULL; |
752 | | | 752 | |
753 | old_parts = p->parts; | | 753 | old_parts = p->parts; |
754 | new_scheme = select_part_scheme(p, old_parts->pscheme, | | 754 | new_scheme = select_part_scheme(p, old_parts->pscheme, |
755 | false, MSG_select_other_partscheme); | | 755 | false, MSG_select_other_partscheme); |
756 | | | 756 | |
757 | if (new_scheme == NULL) | | 757 | if (new_scheme == NULL) { |
| | | 758 | if (err_msg) |
| | | 759 | *err_msg = INTERNAL_ERROR; |
758 | return false; | | 760 | return false; |
| | | 761 | } |
759 | | | 762 | |
760 | new_parts = new_scheme->create_new_for_disk(p->diskdev, | | 763 | new_parts = new_scheme->create_new_for_disk(p->diskdev, |
761 | 0, p->dlsize, is_boot_drive, NULL); | | 764 | 0, p->dlsize, is_boot_drive, NULL); |
762 | if (new_parts == NULL) | | 765 | if (new_parts == NULL) { |
| | | 766 | if (err_msg) |
| | | 767 | *err_msg = MSG_out_of_memory; |
763 | return false; | | 768 | return false; |
| | | 769 | } |
764 | | | 770 | |
765 | convert_copy(old_parts, new_parts); | | 771 | convert_copy(old_parts, new_parts); |
766 | | | 772 | |
767 | if (new_parts->num_part == 0) { | | 773 | if (new_parts->num_part == 0 && old_parts->num_part != 0) { |
768 | /* need to cleanup */ | | 774 | /* need to cleanup */ |
769 | new_parts->pscheme->free(new_parts); | | 775 | new_parts->pscheme->free(new_parts); |
770 | return false; | | 776 | return false; |
771 | } | | 777 | } |
772 | | | 778 | |
773 | old_parts->pscheme->free(old_parts); | | 779 | old_parts->pscheme->free(old_parts); |
774 | p->parts = new_parts; | | 780 | p->parts = new_parts; |
775 | return true; | | 781 | return true; |
776 | } | | 782 | } |
777 | | | 783 | |
778 | static struct pm_devs * | | 784 | static struct pm_devs * |
779 | dummy_whole_system_pm(void) | | 785 | dummy_whole_system_pm(void) |
780 | { | | 786 | { |
781 | static struct pm_devs whole_system = { | | 787 | static struct pm_devs whole_system = { |
782 | .diskdev = "/", | | 788 | .diskdev = "/", |
783 | .no_mbr = true, | | 789 | .no_mbr = true, |
784 | .no_part = true, | | 790 | .no_part = true, |
785 | .cur_system = true, | | 791 | .cur_system = true, |
786 | }; | | 792 | }; |
787 | static bool init = false; | | 793 | static bool init = false; |
788 | | | 794 | |
789 | if (!init) { | | 795 | if (!init) { |
790 | strlcpy(whole_system.diskdev_descr, | | 796 | strlcpy(whole_system.diskdev_descr, |
791 | msg_string(MSG_running_system), | | 797 | msg_string(MSG_running_system), |
792 | sizeof whole_system.diskdev_descr); | | 798 | sizeof whole_system.diskdev_descr); |
793 | } | | 799 | } |
794 | | | 800 | |
795 | return &whole_system; | | 801 | return &whole_system; |
796 | } | | 802 | } |
797 | | | 803 | |
798 | int | | 804 | int |
799 | find_disks(const char *doingwhat, bool allow_cur_system) | | 805 | find_disks(const char *doingwhat, bool allow_cur_system) |
800 | { | | 806 | { |
801 | struct disk_desc disks[MAX_DISKS]; | | 807 | struct disk_desc disks[MAX_DISKS]; |
802 | /* need two more menu entries: current system + extended partitioning */ | | 808 | /* need two more menu entries: current system + extended partitioning */ |
803 | menu_ent dsk_menu[__arraycount(disks) + 2]; | | 809 | menu_ent dsk_menu[__arraycount(disks) + 2]; |
804 | struct disk_desc *disk; | | 810 | struct disk_desc *disk; |
805 | int i = 0, skipped = 0; | | 811 | int i = 0, skipped = 0; |
806 | int already_found, numdisks, selected_disk = -1; | | 812 | int already_found, numdisks, selected_disk = -1; |
807 | int menu_no; | | 813 | int menu_no; |
808 | struct pm_devs *pm_i, *pm_last = NULL; | | 814 | struct pm_devs *pm_i, *pm_last = NULL; |
809 | | | 815 | |
810 | memset(dsk_menu, 0, sizeof(dsk_menu)); | | 816 | memset(dsk_menu, 0, sizeof(dsk_menu)); |
811 | | | 817 | |
812 | /* Find disks. */ | | 818 | /* Find disks. */ |
813 | numdisks = get_disks(disks, partman_go <= 0); | | 819 | numdisks = get_disks(disks, partman_go <= 0); |
814 | | | 820 | |
815 | /* need a redraw here, kernel messages hose everything */ | | 821 | /* need a redraw here, kernel messages hose everything */ |
816 | touchwin(stdscr); | | 822 | touchwin(stdscr); |
817 | refresh(); | | 823 | refresh(); |
818 | /* Kill typeahead, it won't be what the user had in mind */ | | 824 | /* Kill typeahead, it won't be what the user had in mind */ |
819 | fpurge(stdin); | | 825 | fpurge(stdin); |
820 | | | 826 | |
821 | /* | | 827 | /* |
822 | * partman_go: <0 - we want to see menu with extended partitioning | | 828 | * partman_go: <0 - we want to see menu with extended partitioning |
823 | * ==0 - we want to see simple select disk menu | | 829 | * ==0 - we want to see simple select disk menu |
824 | * >0 - we do not want to see any menus, just detect | | 830 | * >0 - we do not want to see any menus, just detect |
825 | * all disks | | 831 | * all disks |
826 | */ | | 832 | */ |
827 | if (partman_go <= 0) { | | 833 | if (partman_go <= 0) { |
828 | if (numdisks == 0 && !allow_cur_system) { | | 834 | if (numdisks == 0 && !allow_cur_system) { |
829 | /* No disks found! */ | | 835 | /* No disks found! */ |
830 | hit_enter_to_continue(MSG_nodisk, NULL); | | 836 | hit_enter_to_continue(MSG_nodisk, NULL); |
831 | /*endwin();*/ | | 837 | /*endwin();*/ |
832 | return -1; | | 838 | return -1; |
833 | } else { | | 839 | } else { |
834 | /* One or more disks found or current system allowed */ | | 840 | /* One or more disks found or current system allowed */ |
835 | i = 0; | | 841 | i = 0; |
836 | if (allow_cur_system) { | | 842 | if (allow_cur_system) { |
837 | dsk_menu[i].opt_name = MSG_running_system; | | 843 | dsk_menu[i].opt_name = MSG_running_system; |
838 | dsk_menu[i].opt_flags = OPT_EXIT; | | 844 | dsk_menu[i].opt_flags = OPT_EXIT; |
839 | dsk_menu[i].opt_action = set_menu_select; | | 845 | dsk_menu[i].opt_action = set_menu_select; |
840 | i++; | | 846 | i++; |
841 | } | | 847 | } |
842 | for (; i < numdisks+allow_cur_system; i++) { | | 848 | for (; i < numdisks+allow_cur_system; i++) { |
843 | dsk_menu[i].opt_name = | | 849 | dsk_menu[i].opt_name = |
844 | disks[i-allow_cur_system].dd_descr; | | 850 | disks[i-allow_cur_system].dd_descr; |
845 | dsk_menu[i].opt_flags = OPT_EXIT; | | 851 | dsk_menu[i].opt_flags = OPT_EXIT; |
846 | dsk_menu[i].opt_action = set_menu_select; | | 852 | dsk_menu[i].opt_action = set_menu_select; |
847 | } | | 853 | } |
848 | if (partman_go < 0) { | | 854 | if (partman_go < 0) { |
849 | dsk_menu[i].opt_name = MSG_partman; | | 855 | dsk_menu[i].opt_name = MSG_partman; |
850 | dsk_menu[i].opt_flags = OPT_EXIT; | | 856 | dsk_menu[i].opt_flags = OPT_EXIT; |
851 | dsk_menu[i].opt_action = set_menu_select; | | 857 | dsk_menu[i].opt_action = set_menu_select; |
852 | i++; | | 858 | i++; |
853 | } | | 859 | } |
854 | menu_no = new_menu(MSG_Available_disks, | | 860 | menu_no = new_menu(MSG_Available_disks, |
855 | dsk_menu, i, -1, | | 861 | dsk_menu, i, -1, |
856 | 4, 0, 0, MC_SCROLL, | | 862 | 4, 0, 0, MC_SCROLL, |
857 | NULL, NULL, NULL, NULL, MSG_exit_menu_generic); | | 863 | NULL, NULL, NULL, NULL, MSG_exit_menu_generic); |
858 | if (menu_no == -1) | | 864 | if (menu_no == -1) |
859 | return -1; | | 865 | return -1; |
860 | msg_fmt_display(MSG_ask_disk, "%s", doingwhat); | | 866 | msg_fmt_display(MSG_ask_disk, "%s", doingwhat); |
861 | process_menu(menu_no, &selected_disk); | | 867 | process_menu(menu_no, &selected_disk); |
862 | free_menu(menu_no); | | 868 | free_menu(menu_no); |
863 | if (allow_cur_system) { | | 869 | if (allow_cur_system) { |
864 | if (selected_disk == 0) { | | 870 | if (selected_disk == 0) { |
865 | pm = dummy_whole_system_pm(); | | 871 | pm = dummy_whole_system_pm(); |
866 | return 1; | | 872 | return 1; |
867 | } else { | | 873 | } else { |
868 | selected_disk--; | | 874 | selected_disk--; |
869 | } | | 875 | } |
870 | } | | 876 | } |
871 | } | | 877 | } |
872 | if (partman_go < 0 && selected_disk == numdisks) { | | 878 | if (partman_go < 0 && selected_disk == numdisks) { |
873 | partman_go = 1; | | 879 | partman_go = 1; |
874 | return -2; | | 880 | return -2; |
875 | } else | | 881 | } else |
876 | partman_go = 0; | | 882 | partman_go = 0; |
877 | if (selected_disk < 0 || selected_disk >= numdisks) | | 883 | if (selected_disk < 0 || selected_disk >= numdisks) |
878 | return -1; | | 884 | return -1; |
879 | } | | 885 | } |
880 | | | 886 | |
881 | /* Fill pm struct with device(s) info */ | | 887 | /* Fill pm struct with device(s) info */ |
882 | for (i = 0; i < numdisks; i++) { | | 888 | for (i = 0; i < numdisks; i++) { |
883 | if (! partman_go) | | 889 | if (! partman_go) |
884 | disk = disks + selected_disk; | | 890 | disk = disks + selected_disk; |
885 | else { | | 891 | else { |
886 | disk = disks + i; | | 892 | disk = disks + i; |
887 | already_found = 0; | | 893 | already_found = 0; |
888 | SLIST_FOREACH(pm_i, &pm_head, l) { | | 894 | SLIST_FOREACH(pm_i, &pm_head, l) { |
889 | pm_last = pm_i; | | 895 | pm_last = pm_i; |
890 | if (strcmp(pm_i->diskdev, disk->dd_name) == 0) { | | 896 | if (strcmp(pm_i->diskdev, disk->dd_name) == 0) { |
891 | already_found = 1; | | 897 | already_found = 1; |
892 | break; | | 898 | break; |
893 | } | | 899 | } |
894 | } | | 900 | } |
895 | if (pm_i != NULL && already_found) { | | 901 | if (pm_i != NULL && already_found) { |
896 | /* | | 902 | /* |
897 | * We already added this device, but | | 903 | * We already added this device, but |
898 | * partitions might have changed | | 904 | * partitions might have changed |
899 | */ | | 905 | */ |
900 | if (!pm_i->found) { | | 906 | if (!pm_i->found) { |
901 | pm_i->found = true; | | 907 | pm_i->found = true; |
902 | if (pm_i->parts == NULL) { | | 908 | if (pm_i->parts == NULL) { |
903 | pm_i->parts = | | 909 | pm_i->parts = |
904 | partitions_read_disk( | | 910 | partitions_read_disk( |
905 | pm_i->diskdev, | | 911 | pm_i->diskdev, |
906 | disk->dd_totsec, | | 912 | disk->dd_totsec, |
907 | disk->dd_secsize, | | 913 | disk->dd_secsize, |
908 | disk->dd_no_mbr); | | 914 | disk->dd_no_mbr); |
909 | } | | 915 | } |
910 | } | | 916 | } |
911 | continue; | | 917 | continue; |
912 | } | | 918 | } |
913 | } | | 919 | } |
914 | pm = pm_new; | | 920 | pm = pm_new; |
915 | pm->found = 1; | | 921 | pm->found = 1; |
916 | pm->ptstart = 0; | | 922 | pm->ptstart = 0; |
917 | pm->ptsize = 0; | | 923 | pm->ptsize = 0; |
918 | strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev); | | 924 | strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev); |
919 | strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr); | | 925 | strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr); |
920 | /* Use as a default disk if the user has the sets on a local disk */ | | 926 | /* Use as a default disk if the user has the sets on a local disk */ |
921 | strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev); | | 927 | strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev); |
922 | | | 928 | |
923 | /* | | 929 | /* |
924 | * Init disk size and geometry | | 930 | * Init disk size and geometry |
925 | */ | | 931 | */ |
926 | pm->sectorsize = disk->dd_secsize; | | 932 | pm->sectorsize = disk->dd_secsize; |
927 | pm->dlcyl = disk->dd_cyl; | | 933 | pm->dlcyl = disk->dd_cyl; |
928 | pm->dlhead = disk->dd_head; | | 934 | pm->dlhead = disk->dd_head; |
929 | pm->dlsec = disk->dd_sec; | | 935 | pm->dlsec = disk->dd_sec; |
930 | pm->dlsize = disk->dd_totsec; | | 936 | pm->dlsize = disk->dd_totsec; |
931 | if (pm->dlsize == 0) | | 937 | if (pm->dlsize == 0) |
932 | pm->dlsize = | | 938 | pm->dlsize = |
933 | disk->dd_cyl * disk->dd_head * disk->dd_sec; | | 939 | disk->dd_cyl * disk->dd_head * disk->dd_sec; |
934 | | | 940 | |
935 | pm->parts = partitions_read_disk(pm->diskdev, | | 941 | pm->parts = partitions_read_disk(pm->diskdev, |
936 | pm->dlsize, disk->dd_secsize, disk->dd_no_mbr); | | 942 | pm->dlsize, disk->dd_secsize, disk->dd_no_mbr); |
937 | | | 943 | |
938 | again: | | 944 | again: |
939 | | | 945 | |
940 | #ifdef DEBUG_VERBOSE | | 946 | #ifdef DEBUG_VERBOSE |
941 | if (pm->parts) { | | 947 | if (pm->parts) { |
942 | fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr); | | 948 | fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr); |
943 | dump_parts(pm->parts); | | 949 | dump_parts(pm->parts); |
944 | | | 950 | |
945 | if (pm->parts->pscheme->secondary_partitions) { | | 951 | if (pm->parts->pscheme->secondary_partitions) { |
946 | const struct disk_partitions *sparts = | | 952 | const struct disk_partitions *sparts = |
947 | pm->parts->pscheme->secondary_partitions( | | 953 | pm->parts->pscheme->secondary_partitions( |
948 | pm->parts, pm->ptstart, false); | | 954 | pm->parts, pm->ptstart, false); |
949 | if (sparts != NULL) | | 955 | if (sparts != NULL) |
950 | dump_parts(sparts); | | 956 | dump_parts(sparts); |
951 | } | | 957 | } |
952 | } | | 958 | } |
953 | #endif | | 959 | #endif |
954 | | | 960 | |
955 | pm->no_mbr = disk->dd_no_mbr; | | 961 | pm->no_mbr = disk->dd_no_mbr; |
956 | pm->no_part = disk->dd_no_part; | | 962 | pm->no_part = disk->dd_no_part; |
957 | if (!pm->no_part) { | | 963 | if (!pm->no_part) { |
958 | pm->sectorsize = disk->dd_secsize; | | 964 | pm->sectorsize = disk->dd_secsize; |
959 | pm->dlcyl = disk->dd_cyl; | | 965 | pm->dlcyl = disk->dd_cyl; |
960 | pm->dlhead = disk->dd_head; | | 966 | pm->dlhead = disk->dd_head; |
961 | pm->dlsec = disk->dd_sec; | | 967 | pm->dlsec = disk->dd_sec; |
962 | pm->dlsize = disk->dd_totsec; | | 968 | pm->dlsize = disk->dd_totsec; |
963 | if (pm->dlsize == 0) | | 969 | if (pm->dlsize == 0) |
964 | pm->dlsize = | | 970 | pm->dlsize = |
965 | disk->dd_cyl * disk->dd_head * disk->dd_sec; | | 971 | disk->dd_cyl * disk->dd_head * disk->dd_sec; |
966 | | | 972 | |
967 | if (pm->parts && pm->parts->pscheme->size_limit != 0 | | 973 | if (pm->parts && pm->parts->pscheme->size_limit != 0 |
968 | && pm->dlsize > pm->parts->pscheme->size_limit | | 974 | && pm->dlsize > pm->parts->pscheme->size_limit |
969 | && ! partman_go) { | | 975 | && ! partman_go) { |
970 | | | 976 | |
971 | char size[5], limit[5]; | | 977 | char size[5], limit[5]; |
972 | | | 978 | |
973 | humanize_number(size, sizeof(size), | | 979 | humanize_number(size, sizeof(size), |
974 | (uint64_t)pm->dlsize * pm->sectorsize, | | 980 | (uint64_t)pm->dlsize * pm->sectorsize, |
975 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | | 981 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE |
976 | | HN_DECIMAL); | | 982 | | HN_DECIMAL); |
977 | | | 983 | |
978 | humanize_number(limit, sizeof(limit), | | 984 | humanize_number(limit, sizeof(limit), |
979 | (uint64_t)pm->parts->pscheme->size_limit | | 985 | (uint64_t)pm->parts->pscheme->size_limit |
980 | * 512U, | | 986 | * 512U, |
981 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE | | 987 | "", HN_AUTOSCALE, HN_B | HN_NOSPACE |
982 | | HN_DECIMAL); | | 988 | | HN_DECIMAL); |
983 | | | 989 | |
984 | if (logfp) | | 990 | if (logfp) |
985 | fprintf(logfp, | | 991 | fprintf(logfp, |
986 | "disk %s: is too big (%" PRIu64 | | 992 | "disk %s: is too big (%" PRIu64 |
987 | " blocks, %s), will be truncated\n", | | 993 | " blocks, %s), will be truncated\n", |
988 | pm->diskdev, pm->dlsize, | | 994 | pm->diskdev, pm->dlsize, |
989 | size); | | 995 | size); |
990 | | | 996 | |
991 | msg_display_subst(MSG_toobigdisklabel, 5, | | 997 | msg_display_subst(MSG_toobigdisklabel, 5, |
992 | pm->diskdev, | | 998 | pm->diskdev, |
993 | msg_string(pm->parts->pscheme->name), | | 999 | msg_string(pm->parts->pscheme->name), |
994 | msg_string(pm->parts->pscheme->short_name), | | 1000 | msg_string(pm->parts->pscheme->short_name), |
995 | size, limit); | | 1001 | size, limit); |
996 | | | 1002 | |
997 | int sel = -1; | | 1003 | int sel = -1; |
998 | const char *err = NULL; | | 1004 | const char *err = NULL; |
999 | process_menu(MENU_convertscheme, &sel); | | 1005 | process_menu(MENU_convertscheme, &sel); |
1000 | if (sel == 1) { | | 1006 | if (sel == 1) { |
1001 | if (!delete_scheme(pm)) { | | 1007 | if (!delete_scheme(pm)) { |
1002 | return -1; | | 1008 | return -1; |
1003 | } | | 1009 | } |
1004 | goto again; | | 1010 | goto again; |
1005 | } else if (sel == 2) { | | 1011 | } else if (sel == 2) { |
1006 | if (!convert_scheme(pm, | | 1012 | if (!convert_scheme(pm, |
1007 | partman_go < 0, &err)) { | | 1013 | partman_go < 0, &err)) { |
1008 | if (err != NULL) | | 1014 | if (err != NULL) |
1009 | err_msg_win(err); | | 1015 | err_msg_win(err); |
1010 | return -1; | | 1016 | return -1; |
1011 | } | | 1017 | } |
1012 | goto again; | | 1018 | goto again; |
1013 | } else if (sel == 3) { | | 1019 | } else if (sel == 3) { |
1014 | return -1; | | 1020 | return -1; |
1015 | } | | 1021 | } |
1016 | pm->dlsize = pm->parts->pscheme->size_limit; | | 1022 | pm->dlsize = pm->parts->pscheme->size_limit; |
1017 | } | | 1023 | } |
1018 | } else { | | 1024 | } else { |
1019 | pm->sectorsize = 0; | | 1025 | pm->sectorsize = 0; |
1020 | pm->dlcyl = 0; | | 1026 | pm->dlcyl = 0; |
1021 | pm->dlhead = 0; | | 1027 | pm->dlhead = 0; |
1022 | pm->dlsec = 0; | | 1028 | pm->dlsec = 0; |
1023 | pm->dlsize = 0; | | 1029 | pm->dlsize = 0; |
1024 | pm->no_mbr = 1; | | 1030 | pm->no_mbr = 1; |
1025 | } | | 1031 | } |
1026 | pm->dlcylsize = pm->dlhead * pm->dlsec; | | 1032 | pm->dlcylsize = pm->dlhead * pm->dlsec; |
1027 | | | 1033 | |
1028 | if (partman_go) { | | 1034 | if (partman_go) { |
1029 | pm_getrefdev(pm_new); | | 1035 | pm_getrefdev(pm_new); |
1030 | if (SLIST_EMPTY(&pm_head) || pm_last == NULL) | | 1036 | if (SLIST_EMPTY(&pm_head) || pm_last == NULL) |
1031 | SLIST_INSERT_HEAD(&pm_head, pm_new, l); | | 1037 | SLIST_INSERT_HEAD(&pm_head, pm_new, l); |
1032 | else | | 1038 | else |
1033 | SLIST_INSERT_AFTER(pm_last, pm_new, l); | | 1039 | SLIST_INSERT_AFTER(pm_last, pm_new, l); |
1034 | pm_new = malloc(sizeof (struct pm_devs)); | | 1040 | pm_new = malloc(sizeof (struct pm_devs)); |
1035 | memset(pm_new, 0, sizeof *pm_new); | | 1041 | memset(pm_new, 0, sizeof *pm_new); |
1036 | } else | | 1042 | } else |
1037 | /* We are not in partman and do not want to process | | 1043 | /* We are not in partman and do not want to process |
1038 | * all devices, exit */ | | 1044 | * all devices, exit */ |
1039 | break; | | 1045 | break; |
1040 | } | | 1046 | } |
1041 | | | 1047 | |
1042 | return numdisks-skipped; | | 1048 | return numdisks-skipped; |
1043 | } | | 1049 | } |
1044 | | | 1050 | |
1045 | static int | | 1051 | static int |
1046 | sort_part_usage_by_mount(const void *a, const void *b) | | 1052 | sort_part_usage_by_mount(const void *a, const void *b) |
1047 | { | | 1053 | { |
1048 | const struct part_usage_info *pa = a, *pb = b; | | 1054 | const struct part_usage_info *pa = a, *pb = b; |
1049 | | | 1055 | |
1050 | /* sort all real partitions by mount point */ | | 1056 | /* sort all real partitions by mount point */ |
1051 | if ((pa->instflags & PUIINST_MOUNT) && | | 1057 | if ((pa->instflags & PUIINST_MOUNT) && |
1052 | (pb->instflags & PUIINST_MOUNT)) | | 1058 | (pb->instflags & PUIINST_MOUNT)) |
1053 | return strcmp(pa->mount, pb->mount); | | 1059 | return strcmp(pa->mount, pb->mount); |
1054 | | | 1060 | |
1055 | /* real partitions go first */ | | 1061 | /* real partitions go first */ |
1056 | if (pa->instflags & PUIINST_MOUNT) | | 1062 | if (pa->instflags & PUIINST_MOUNT) |
1057 | return -1; | | 1063 | return -1; |
1058 | if (pb->instflags & PUIINST_MOUNT) | | 1064 | if (pb->instflags & PUIINST_MOUNT) |
1059 | return 1; | | 1065 | return 1; |
1060 | | | 1066 | |
1061 | /* arbitrary order for all other partitions */ | | 1067 | /* arbitrary order for all other partitions */ |
1062 | if (pa->type == PT_swap) | | 1068 | if (pa->type == PT_swap) |
1063 | return -1; | | 1069 | return -1; |
1064 | if (pb->type == PT_swap) | | 1070 | if (pb->type == PT_swap) |
1065 | return 1; | | 1071 | return 1; |
1066 | if (pa->type < pb->type) | | 1072 | if (pa->type < pb->type) |
1067 | return -1; | | 1073 | return -1; |
1068 | if (pa->type > pb->type) | | 1074 | if (pa->type > pb->type) |
1069 | return 1; | | 1075 | return 1; |
1070 | if (pa->cur_part_id < pb->cur_part_id) | | 1076 | if (pa->cur_part_id < pb->cur_part_id) |
1071 | return -1; | | 1077 | return -1; |
1072 | if (pa->cur_part_id > pb->cur_part_id) | | 1078 | if (pa->cur_part_id > pb->cur_part_id) |
1073 | return 1; | | 1079 | return 1; |
1074 | return (uintptr_t)a < (uintptr_t)b ? -1 : 1; | | 1080 | return (uintptr_t)a < (uintptr_t)b ? -1 : 1; |
1075 | } | | 1081 | } |
1076 | | | 1082 | |
1077 | int | | 1083 | int |
1078 | make_filesystems(struct install_partition_desc *install) | | 1084 | make_filesystems(struct install_partition_desc *install) |
1079 | { | | 1085 | { |
1080 | int error = 0, partno = -1; | | 1086 | int error = 0, partno = -1; |
1081 | char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX], | | 1087 | char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX], |
1082 | opts[200], opt[30]; | | 1088 | opts[200], opt[30]; |
1083 | size_t i; | | 1089 | size_t i; |
1084 | struct part_usage_info *ptn; | | 1090 | struct part_usage_info *ptn; |
1085 | struct disk_partitions *parts; | | 1091 | struct disk_partitions *parts; |
1086 | const char *mnt_opts = NULL, *fsname = NULL; | | 1092 | const char *mnt_opts = NULL, *fsname = NULL; |
1087 | | | 1093 | |
1088 | if (pm->cur_system) | | 1094 | if (pm->cur_system) |
1089 | return 1; | | 1095 | return 1; |
1090 | | | 1096 | |
1091 | if (pm->no_part) { | | 1097 | if (pm->no_part) { |
1092 | /* check if this target device already has a ffs */ | | 1098 | /* check if this target device already has a ffs */ |
1093 | snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev); | | 1099 | snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev); |
1094 | error = fsck_preen(rdev, "ffs", true); | | 1100 | error = fsck_preen(rdev, "ffs", true); |
1095 | if (error) { | | 1101 | if (error) { |
1096 | if (!ask_noyes(MSG_No_filesystem_newfs)) | | 1102 | if (!ask_noyes(MSG_No_filesystem_newfs)) |
1097 | return EINVAL; | | 1103 | return EINVAL; |
1098 | error = run_program(RUN_DISPLAY | RUN_PROGRESS, | | 1104 | error = run_program(RUN_DISPLAY | RUN_PROGRESS, |
1099 | "/sbin/newfs -V2 -O2 %s", rdev); | | 1105 | "/sbin/newfs -V2 -O2 %s", rdev); |
1100 | } | | 1106 | } |
1101 | | | 1107 | |
1102 | md_pre_mount(install, 0); | | 1108 | md_pre_mount(install, 0); |
1103 | | | 1109 | |
1104 | make_target_dir("/"); | | 1110 | make_target_dir("/"); |
1105 | | | 1111 | |
1106 | snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev); | | 1112 | snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev); |
1107 | error = target_mount_do("-o async", devdev, "/"); | | 1113 | error = target_mount_do("-o async", devdev, "/"); |
1108 | if (error) { | | 1114 | if (error) { |
1109 | msg_display_subst(MSG_mountfail, 2, devdev, "/"); | | 1115 | msg_display_subst(MSG_mountfail, 2, devdev, "/"); |
1110 | hit_enter_to_continue(NULL, NULL); | | 1116 | hit_enter_to_continue(NULL, NULL); |
1111 | } | | 1117 | } |
1112 | | | 1118 | |
1113 | return error; | | 1119 | return error; |
1114 | } | | 1120 | } |
1115 | | | 1121 | |
1116 | /* Making new file systems and mounting them */ | | 1122 | /* Making new file systems and mounting them */ |
1117 | | | 1123 | |
1118 | /* sort to ensure /usr/local is mounted after /usr (etc) */ | | 1124 | /* sort to ensure /usr/local is mounted after /usr (etc) */ |
1119 | qsort(install->infos, install->num, sizeof(*install->infos), | | 1125 | qsort(install->infos, install->num, sizeof(*install->infos), |
1120 | sort_part_usage_by_mount); | | 1126 | sort_part_usage_by_mount); |
1121 | | | 1127 | |
1122 | for (i = 0; i < install->num; i++) { | | 1128 | for (i = 0; i < install->num; i++) { |
1123 | /* | | 1129 | /* |
1124 | * Newfs all file systems marked as needing this. | | 1130 | * Newfs all file systems marked as needing this. |
1125 | * Mount the ones that have a mountpoint in the target. | | 1131 | * Mount the ones that have a mountpoint in the target. |
1126 | */ | | 1132 | */ |
1127 | ptn = &install->infos[i]; | | 1133 | ptn = &install->infos[i]; |
1128 | parts = ptn->parts; | | 1134 | parts = ptn->parts; |
1129 | newfs = NULL; | | 1135 | newfs = NULL; |
1130 | fsname = NULL; | | 1136 | fsname = NULL; |
1131 | | | 1137 | |
1132 | if (ptn->size == 0 || parts == NULL|| ptn->type == PT_swap) | | 1138 | if (ptn->size == 0 || parts == NULL|| ptn->type == PT_swap) |
1133 | continue; | | 1139 | continue; |
1134 | | | 1140 | |
1135 | if (parts->pscheme->get_part_device(parts, ptn->cur_part_id, | | 1141 | if (parts->pscheme->get_part_device(parts, ptn->cur_part_id, |
1136 | devdev, sizeof devdev, &partno, parent_device_only, false, | | 1142 | devdev, sizeof devdev, &partno, parent_device_only, false, |
1137 | false) && is_active_rootpart(devdev, partno)) | | 1143 | false) && is_active_rootpart(devdev, partno)) |
1138 | continue; | | 1144 | continue; |
1139 | | | 1145 | |
1140 | parts->pscheme->get_part_device(parts, ptn->cur_part_id, | | 1146 | parts->pscheme->get_part_device(parts, ptn->cur_part_id, |
1141 | devdev, sizeof devdev, &partno, plain_name, true, true); | | 1147 | devdev, sizeof devdev, &partno, plain_name, true, true); |
1142 | | | 1148 | |
1143 | parts->pscheme->get_part_device(parts, ptn->cur_part_id, | | 1149 | parts->pscheme->get_part_device(parts, ptn->cur_part_id, |
1144 | rdev, sizeof rdev, &partno, raw_dev_name, true, true); | | 1150 | rdev, sizeof rdev, &partno, raw_dev_name, true, true); |
1145 | | | 1151 | |
1146 | opts[0] = 0; | | 1152 | opts[0] = 0; |
1147 | switch (ptn->fs_type) { | | 1153 | switch (ptn->fs_type) { |
1148 | case FS_APPLEUFS: | | 1154 | case FS_APPLEUFS: |
1149 | if (ptn->fs_opt3 != 0) | | 1155 | if (ptn->fs_opt3 != 0) |
1150 | snprintf(opts, sizeof opts, "-i %u", | | 1156 | snprintf(opts, sizeof opts, "-i %u", |
1151 | ptn->fs_opt3); | | 1157 | ptn->fs_opt3); |
1152 | asprintf(&newfs, "/sbin/newfs %s", opts); | | 1158 | asprintf(&newfs, "/sbin/newfs %s", opts); |
1153 | mnt_opts = "-tffs -o async"; | | 1159 | mnt_opts = "-tffs -o async"; |
1154 | fsname = "ffs"; | | 1160 | fsname = "ffs"; |
1155 | break; | | 1161 | break; |
1156 | case FS_BSDFFS: | | 1162 | case FS_BSDFFS: |
1157 | if (ptn->fs_opt3 != 0) | | 1163 | if (ptn->fs_opt3 != 0) |
1158 | snprintf(opts, sizeof opts, "-i %u ", | | 1164 | snprintf(opts, sizeof opts, "-i %u ", |
1159 | ptn->fs_opt3); | | 1165 | ptn->fs_opt3); |
1160 | if (ptn->fs_opt1 != 0) { | | 1166 | if (ptn->fs_opt1 != 0) { |
1161 | snprintf(opt, sizeof opt, "-b %u ", | | 1167 | snprintf(opt, sizeof opt, "-b %u ", |
1162 | ptn->fs_opt1); | | 1168 | ptn->fs_opt1); |
1163 | strcat(opts, opt); | | 1169 | strcat(opts, opt); |
1164 | } | | 1170 | } |
1165 | if (ptn->fs_opt2 != 0) { | | 1171 | if (ptn->fs_opt2 != 0) { |
1166 | snprintf(opt, sizeof opt, "-f %u ", | | 1172 | snprintf(opt, sizeof opt, "-f %u ", |
1167 | ptn->fs_opt2); | | 1173 | ptn->fs_opt2); |
1168 | strcat(opts, opt); | | 1174 | strcat(opts, opt); |
1169 | } | | 1175 | } |
1170 | asprintf(&newfs, | | 1176 | asprintf(&newfs, |
1171 | "/sbin/newfs -V2 -O %d %s", | | 1177 | "/sbin/newfs -V2 -O %d %s", |
1172 | ptn->fs_version == 2 ? 2 : 1, opts); | | 1178 | ptn->fs_version == 2 ? 2 : 1, opts); |
1173 | if (ptn->mountflags & PUIMNT_LOG) | | 1179 | if (ptn->mountflags & PUIMNT_LOG) |
1174 | mnt_opts = "-tffs -o log"; | | 1180 | mnt_opts = "-tffs -o log"; |
1175 | else | | 1181 | else |
1176 | mnt_opts = "-tffs -o async"; | | 1182 | mnt_opts = "-tffs -o async"; |
1177 | fsname = "ffs"; | | 1183 | fsname = "ffs"; |
1178 | break; | | 1184 | break; |
1179 | case FS_BSDLFS: | | 1185 | case FS_BSDLFS: |
1180 | if (ptn->fs_opt1 != 0 && ptn->fs_opt2 != 0) | | 1186 | if (ptn->fs_opt1 != 0 && ptn->fs_opt2 != 0) |
1181 | snprintf(opts, sizeof opts, "-b %u", | | 1187 | snprintf(opts, sizeof opts, "-b %u", |
1182 | ptn->fs_opt1 * ptn->fs_opt2); | | 1188 | ptn->fs_opt1 * ptn->fs_opt2); |
1183 | asprintf(&newfs, "/sbin/newfs_lfs %s", opts); | | 1189 | asprintf(&newfs, "/sbin/newfs_lfs %s", opts); |
1184 | mnt_opts = "-tlfs"; | | 1190 | mnt_opts = "-tlfs"; |
1185 | fsname = "lfs"; | | 1191 | fsname = "lfs"; |
1186 | break; | | 1192 | break; |
1187 | case FS_MSDOS: | | 1193 | case FS_MSDOS: |
1188 | asprintf(&newfs, "/sbin/newfs_msdos"); | | 1194 | asprintf(&newfs, "/sbin/newfs_msdos"); |
1189 | mnt_opts = "-tmsdos"; | | 1195 | mnt_opts = "-tmsdos"; |
1190 | fsname = "msdos"; | | 1196 | fsname = "msdos"; |
1191 | break; | | 1197 | break; |
1192 | case FS_SYSVBFS: | | 1198 | case FS_SYSVBFS: |
1193 | asprintf(&newfs, "/sbin/newfs_sysvbfs"); | | 1199 | asprintf(&newfs, "/sbin/newfs_sysvbfs"); |
1194 | mnt_opts = "-tsysvbfs"; | | 1200 | mnt_opts = "-tsysvbfs"; |
1195 | fsname = "sysvbfs"; | | 1201 | fsname = "sysvbfs"; |
1196 | break; | | 1202 | break; |
1197 | case FS_V7: | | 1203 | case FS_V7: |
1198 | asprintf(&newfs, "/sbin/newfs_v7fs"); | | 1204 | asprintf(&newfs, "/sbin/newfs_v7fs"); |
1199 | mnt_opts = "-tv7fs"; | | 1205 | mnt_opts = "-tv7fs"; |
1200 | fsname = "v7fs"; | | 1206 | fsname = "v7fs"; |
1201 | break; | | 1207 | break; |
1202 | case FS_EX2FS: | | 1208 | case FS_EX2FS: |
1203 | asprintf(&newfs, | | 1209 | asprintf(&newfs, |
1204 | ptn->fs_version == 1 ? | | 1210 | ptn->fs_version == 1 ? |
1205 | "/sbin/newfs_ext2fs -O 0" : | | 1211 | "/sbin/newfs_ext2fs -O 0" : |
1206 | "/sbin/newfs_ext2fs"); | | 1212 | "/sbin/newfs_ext2fs"); |
1207 | mnt_opts = "-text2fs"; | | 1213 | mnt_opts = "-text2fs"; |
1208 | fsname = "ext2fs"; | | 1214 | fsname = "ext2fs"; |
1209 | break; | | 1215 | break; |
1210 | } | | 1216 | } |
1211 | if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) { | | 1217 | if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) { |
1212 | error = run_program(RUN_DISPLAY | RUN_PROGRESS, | | 1218 | error = run_program(RUN_DISPLAY | RUN_PROGRESS, |
1213 | "%s %s", newfs, rdev); | | 1219 | "%s %s", newfs, rdev); |
1214 | } else if ((ptn->instflags & (PUIINST_MOUNT|PUIINST_BOOT)) | | 1220 | } else if ((ptn->instflags & (PUIINST_MOUNT|PUIINST_BOOT)) |
1215 | && fsname != NULL) { | | 1221 | && fsname != NULL) { |
1216 | /* We'd better check it isn't dirty */ | | 1222 | /* We'd better check it isn't dirty */ |
1217 | error = fsck_preen(devdev, fsname, false); | | 1223 | error = fsck_preen(devdev, fsname, false); |
1218 | } | | 1224 | } |
1219 | free(newfs); | | 1225 | free(newfs); |
1220 | if (error != 0) | | 1226 | if (error != 0) |
1221 | return error; | | 1227 | return error; |
1222 | | | 1228 | |
1223 | ptn->instflags &= ~PUIINST_NEWFS; | | 1229 | ptn->instflags &= ~PUIINST_NEWFS; |
1224 | md_pre_mount(install, i); | | 1230 | md_pre_mount(install, i); |
1225 | | | 1231 | |
1226 | if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) && | | 1232 | if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) && |
1227 | mnt_opts != NULL) { | | 1233 | mnt_opts != NULL) { |
1228 | make_target_dir(ptn->mount); | | 1234 | make_target_dir(ptn->mount); |
1229 | error = target_mount_do(mnt_opts, devdev, | | 1235 | error = target_mount_do(mnt_opts, devdev, |
1230 | ptn->mount); | | 1236 | ptn->mount); |
1231 | if (error) { | | 1237 | if (error) { |
1232 | msg_display_subst(MSG_mountfail, 2, devdev, | | 1238 | msg_display_subst(MSG_mountfail, 2, devdev, |
1233 | ptn->mount); | | 1239 | ptn->mount); |
1234 | hit_enter_to_continue(NULL, NULL); | | 1240 | hit_enter_to_continue(NULL, NULL); |
1235 | return error; | | 1241 | return error; |
1236 | } | | 1242 | } |
1237 | } | | 1243 | } |
1238 | } | | 1244 | } |
1239 | return 0; | | 1245 | return 0; |
1240 | } | | 1246 | } |
1241 | | | 1247 | |
1242 | int | | 1248 | int |
1243 | make_fstab(struct install_partition_desc *install) | | 1249 | make_fstab(struct install_partition_desc *install) |
1244 | { | | 1250 | { |
1245 | FILE *f; | | 1251 | FILE *f; |
1246 | const char *dump_dev = NULL; | | 1252 | const char *dump_dev = NULL; |
1247 | const char *dev; | | 1253 | const char *dev; |
1248 | char dev_buf[PATH_MAX], swap_dev[PATH_MAX]; | | 1254 | char dev_buf[PATH_MAX], swap_dev[PATH_MAX]; |
1249 | | | 1255 | |
1250 | if (pm->cur_system) | | 1256 | if (pm->cur_system) |
1251 | return 1; | | 1257 | return 1; |
1252 | | | 1258 | |
1253 | swap_dev[0] = 0; | | 1259 | swap_dev[0] = 0; |
1254 | | | 1260 | |
1255 | /* Create the fstab. */ | | 1261 | /* Create the fstab. */ |
1256 | make_target_dir("/etc"); | | 1262 | make_target_dir("/etc"); |
1257 | f = target_fopen("/etc/fstab", "w"); | | 1263 | f = target_fopen("/etc/fstab", "w"); |
1258 | scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix()); | | 1264 | scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix()); |
1259 | | | 1265 | |
1260 | if (logfp) | | 1266 | if (logfp) |
1261 | (void)fprintf(logfp, | | 1267 | (void)fprintf(logfp, |
1262 | "Making %s/etc/fstab (%s).\n", target_prefix(), | | 1268 | "Making %s/etc/fstab (%s).\n", target_prefix(), |
1263 | pm->diskdev); | | 1269 | pm->diskdev); |
1264 | | | 1270 | |
1265 | if (f == NULL) { | | 1271 | if (f == NULL) { |
1266 | msg_display(MSG_createfstab); | | 1272 | msg_display(MSG_createfstab); |
1267 | if (logfp) | | 1273 | if (logfp) |
1268 | (void)fprintf(logfp, "Failed to make /etc/fstab!\n"); | | 1274 | (void)fprintf(logfp, "Failed to make /etc/fstab!\n"); |
1269 | hit_enter_to_continue(NULL, NULL); | | 1275 | hit_enter_to_continue(NULL, NULL); |
1270 | #ifndef DEBUG | | 1276 | #ifndef DEBUG |
1271 | return 1; | | 1277 | return 1; |
1272 | #else | | 1278 | #else |
1273 | f = stdout; | | 1279 | f = stdout; |
1274 | #endif | | 1280 | #endif |
1275 | } | | 1281 | } |
1276 | | | 1282 | |
1277 | scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/" | | 1283 | scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/" |
1278 | "fstab/ for more examples.\n"); | | 1284 | "fstab/ for more examples.\n"); |
1279 | | | 1285 | |
1280 | if (pm->no_part) { | | 1286 | if (pm->no_part) { |
1281 | /* single dk? target */ | | 1287 | /* single dk? target */ |
1282 | char buf[200], parent[200], swap[200], *prompt; | | 1288 | char buf[200], parent[200], swap[200], *prompt; |
1283 | int res; | | 1289 | int res; |
1284 | | | 1290 | |
1285 | if (!get_name_and_parent(pm->diskdev, buf, parent)) | | 1291 | if (!get_name_and_parent(pm->diskdev, buf, parent)) |
1286 | goto done_with_disks; | | 1292 | goto done_with_disks; |
1287 | scripting_fprintf(f, NAME_PREFIX "%s\t/\tffs\trw\t\t1 1\n", | | 1293 | scripting_fprintf(f, NAME_PREFIX "%s\t/\tffs\trw\t\t1 1\n", |
1288 | buf); | | 1294 | buf); |
1289 | if (!find_swap_part_on(parent, swap)) | | 1295 | if (!find_swap_part_on(parent, swap)) |
1290 | goto done_with_disks; | | 1296 | goto done_with_disks; |
1291 | const char *args[] = { parent, swap }; | | 1297 | const char *args[] = { parent, swap }; |
1292 | prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part), | | 1298 | prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part), |
1293 | __arraycount(args), args); | | 1299 | __arraycount(args), args); |
1294 | res = ask_yesno(prompt); | | 1300 | res = ask_yesno(prompt); |
1295 | free(prompt); | | 1301 | free(prompt); |
1296 | if (res) | | 1302 | if (res) |
1297 | scripting_fprintf(f, NAME_PREFIX "%s\tnone" | | 1303 | scripting_fprintf(f, NAME_PREFIX "%s\tnone" |
1298 | "\tswap\tsw,dp\t\t0 0\n", swap); | | 1304 | "\tswap\tsw,dp\t\t0 0\n", swap); |
1299 | goto done_with_disks; | | 1305 | goto done_with_disks; |
1300 | } | | 1306 | } |
1301 | | | 1307 | |
1302 | for (size_t i = 0; i < install->num; i++) { | | 1308 | for (size_t i = 0; i < install->num; i++) { |
1303 | | | 1309 | |
1304 | const struct part_usage_info *ptn = &install->infos[i]; | | 1310 | const struct part_usage_info *ptn = &install->infos[i]; |
1305 | | | 1311 | |
1306 | if (ptn->size == 0) | | 1312 | if (ptn->size == 0) |
1307 | continue; | | 1313 | continue; |
1308 | | | 1314 | |
1309 | bool is_tmpfs = ptn->type == PT_root && | | 1315 | bool is_tmpfs = ptn->type == PT_root && |
1310 | ptn->fs_type == FS_TMPFS && | | 1316 | ptn->fs_type == FS_TMPFS && |
1311 | (ptn->flags & PUIFLG_JUST_MOUNTPOINT); | | 1317 | (ptn->flags & PUIFLG_JUST_MOUNTPOINT); |
1312 | | | 1318 | |
1313 | if (!is_tmpfs && ptn->type != PT_swap && | | 1319 | if (!is_tmpfs && ptn->type != PT_swap && |
1314 | (ptn->instflags & PUIINST_MOUNT) == 0) | | 1320 | (ptn->instflags & PUIINST_MOUNT) == 0) |
1315 | continue; | | 1321 | continue; |
1316 | | | 1322 | |
1317 | const char *s = ""; | | 1323 | const char *s = ""; |
1318 | const char *mp = ptn->mount; | | 1324 | const char *mp = ptn->mount; |
1319 | const char *fstype = "ffs"; | | 1325 | const char *fstype = "ffs"; |
1320 | int fsck_pass = 0, dump_freq = 0; | | 1326 | int fsck_pass = 0, dump_freq = 0; |
1321 | | | 1327 | |
1322 | if (ptn->parts->pscheme->get_part_device(ptn->parts, | | 1328 | if (ptn->parts->pscheme->get_part_device(ptn->parts, |
1323 | ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL, | | 1329 | ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL, |
1324 | logical_name, true, false)) | | 1330 | logical_name, true, false)) |
1325 | dev = dev_buf; | | 1331 | dev = dev_buf; |
1326 | else | | 1332 | else |
1327 | dev = NULL; | | 1333 | dev = NULL; |
1328 | | | 1334 | |
1329 | if (!*mp) { | | 1335 | if (!*mp) { |
1330 | /* | | 1336 | /* |
1331 | * No mount point specified, comment out line and | | 1337 | * No mount point specified, comment out line and |
1332 | * use /mnt as a placeholder for the mount point. | | 1338 | * use /mnt as a placeholder for the mount point. |
1333 | */ | | 1339 | */ |
1334 | s = "# "; | | 1340 | s = "# "; |
1335 | mp = "/mnt"; | | 1341 | mp = "/mnt"; |
1336 | } | | 1342 | } |
1337 | | | 1343 | |
1338 | switch (ptn->fs_type) { | | 1344 | switch (ptn->fs_type) { |
1339 | case FS_UNUSED: | | 1345 | case FS_UNUSED: |
1340 | continue; | | 1346 | continue; |
1341 | case FS_BSDLFS: | | 1347 | case FS_BSDLFS: |
1342 | /* If there is no LFS, just comment it out. */ | | 1348 | /* If there is no LFS, just comment it out. */ |
1343 | if (!check_lfs_progs()) | | 1349 | if (!check_lfs_progs()) |
1344 | s = "# "; | | 1350 | s = "# "; |
1345 | fstype = "lfs"; | | 1351 | fstype = "lfs"; |
1346 | /* FALLTHROUGH */ | | 1352 | /* FALLTHROUGH */ |
1347 | case FS_BSDFFS: | | 1353 | case FS_BSDFFS: |
1348 | fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2; | | 1354 | fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2; |
1349 | dump_freq = 1; | | 1355 | dump_freq = 1; |
1350 | break; | | 1356 | break; |
1351 | case FS_MSDOS: | | 1357 | case FS_MSDOS: |
1352 | fstype = "msdos"; | | 1358 | fstype = "msdos"; |
1353 | break; | | 1359 | break; |
1354 | case FS_SWAP: | | 1360 | case FS_SWAP: |
1355 | if (swap_dev[0] == 0) { | | 1361 | if (swap_dev[0] == 0) { |
1356 | strlcpy(swap_dev, dev, sizeof swap_dev); | | 1362 | strlcpy(swap_dev, dev, sizeof swap_dev); |
1357 | dump_dev = ",dp"; | | 1363 | dump_dev = ",dp"; |
1358 | } else { | | 1364 | } else { |
1359 | dump_dev = ""; | | 1365 | dump_dev = ""; |
1360 | } | | 1366 | } |
1361 | scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n", | | 1367 | scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n", |
1362 | dev, dump_dev); | | 1368 | dev, dump_dev); |
1363 | continue; | | 1369 | continue; |
1364 | #ifdef HAVE_TMPFS | | 1370 | #ifdef HAVE_TMPFS |
1365 | case FS_TMPFS: | | 1371 | case FS_TMPFS: |
1366 | if (ptn->size < 0) | | 1372 | if (ptn->size < 0) |
1367 | scripting_fprintf(f, | | 1373 | scripting_fprintf(f, |
1368 | "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777," | | 1374 | "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777," |
1369 | "-s=ram%%%" PRIu64 "\n", -ptn->size); | | 1375 | "-s=ram%%%" PRIu64 "\n", -ptn->size); |
1370 | else | | 1376 | else |
1371 | scripting_fprintf(f, | | 1377 | scripting_fprintf(f, |
1372 | "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777," | | 1378 | "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777," |
1373 | "-s=%" PRIu64 "M\n", ptn->size); | | 1379 | "-s=%" PRIu64 "M\n", ptn->size); |
1374 | continue; | | 1380 | continue; |
1375 | #else | | 1381 | #else |
1376 | case FS_MFS: | | 1382 | case FS_MFS: |
1377 | if (swap_dev[0] != 0) | | 1383 | if (swap_dev[0] != 0) |
1378 | scripting_fprintf(f, | | 1384 | scripting_fprintf(f, |
1379 | "%s\t\t/tmp\tmfs\trw,-s=%" | | 1385 | "%s\t\t/tmp\tmfs\trw,-s=%" |
1380 | PRIu64 "\n", swap_dev, ptn->size); | | 1386 | PRIu64 "\n", swap_dev, ptn->size); |
1381 | else | | 1387 | else |
1382 | scripting_fprintf(f, | | 1388 | scripting_fprintf(f, |
1383 | "swap\t\t/tmp\tmfs\trw,-s=%" | | 1389 | "swap\t\t/tmp\tmfs\trw,-s=%" |
1384 | PRIu64 "\n", ptn->size); | | 1390 | PRIu64 "\n", ptn->size); |
1385 | continue; | | 1391 | continue; |
1386 | #endif | | 1392 | #endif |
1387 | case FS_SYSVBFS: | | 1393 | case FS_SYSVBFS: |
1388 | fstype = "sysvbfs"; | | 1394 | fstype = "sysvbfs"; |
1389 | make_target_dir("/stand"); | | 1395 | make_target_dir("/stand"); |
1390 | break; | | 1396 | break; |
1391 | default: | | 1397 | default: |
1392 | fstype = "???"; | | 1398 | fstype = "???"; |
1393 | s = "# "; | | 1399 | s = "# "; |
1394 | break; | | 1400 | break; |
1395 | } | | 1401 | } |
1396 | /* The code that remounts root rw doesn't check the partition */ | | 1402 | /* The code that remounts root rw doesn't check the partition */ |
1397 | if (strcmp(mp, "/") == 0 && | | 1403 | if (strcmp(mp, "/") == 0 && |
1398 | (ptn->instflags & PUIINST_MOUNT) == 0) | | 1404 | (ptn->instflags & PUIINST_MOUNT) == 0) |
1399 | s = "# "; | | 1405 | s = "# "; |
1400 | | | 1406 | |
1401 | scripting_fprintf(f, | | 1407 | scripting_fprintf(f, |
1402 | "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n", | | 1408 | "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n", |
1403 | s, dev, mp, fstype, | | 1409 | s, dev, mp, fstype, |
1404 | ptn->mountflags & PUIMNT_LOG ? ",log" : "", | | 1410 | ptn->mountflags & PUIMNT_LOG ? ",log" : "", |
1405 | ptn->mountflags & PUIMNT_NOAUTO ? ",noauto" : "", | | 1411 | ptn->mountflags & PUIMNT_NOAUTO ? ",noauto" : "", |
1406 | ptn->mountflags & PUIMNT_ASYNC ? ",async" : "", | | 1412 | ptn->mountflags & PUIMNT_ASYNC ? ",async" : "", |
1407 | ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "", | | 1413 | ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "", |
1408 | ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "", | | 1414 | ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "", |
1409 | ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "", | | 1415 | ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "", |
1410 | ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "", | | 1416 | ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "", |
1411 | ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "", | | 1417 | ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "", |
1412 | dump_freq, fsck_pass); | | 1418 | dump_freq, fsck_pass); |
1413 | } | | 1419 | } |
1414 | | | 1420 | |
1415 | done_with_disks: | | 1421 | done_with_disks: |
1416 | if (cdrom_dev[0] == 0) | | 1422 | if (cdrom_dev[0] == 0) |
1417 | get_default_cdrom(cdrom_dev, sizeof(cdrom_dev)); | | 1423 | get_default_cdrom(cdrom_dev, sizeof(cdrom_dev)); |
1418 | | | 1424 | |
1419 | /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */ | | 1425 | /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */ |
1420 | scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n"); | | 1426 | scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n"); |
1421 | scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n"); | | 1427 | scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n"); |
1422 | scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n"); | | 1428 | scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n"); |
1423 | if (cdrom_dev[0] != 0) | | 1429 | if (cdrom_dev[0] != 0) |
1424 | scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n", | | 1430 | scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n", |
1425 | cdrom_dev); | | 1431 | cdrom_dev); |
1426 | scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n", | | 1432 | scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n", |
1427 | tmpfs_on_var_shm() ? "" : "#"); | | 1433 | tmpfs_on_var_shm() ? "" : "#"); |
1428 | make_target_dir("/kern"); | | 1434 | make_target_dir("/kern"); |
1429 | make_target_dir("/proc"); | | 1435 | make_target_dir("/proc"); |
1430 | make_target_dir("/dev/pts"); | | 1436 | make_target_dir("/dev/pts"); |
1431 | if (cdrom_dev[0] != 0) | | 1437 | if (cdrom_dev[0] != 0) |
1432 | make_target_dir("/cdrom"); | | 1438 | make_target_dir("/cdrom"); |
1433 | make_target_dir("/var/shm"); | | 1439 | make_target_dir("/var/shm"); |
1434 | | | 1440 | |
1435 | scripting_fprintf(NULL, "EOF\n"); | | 1441 | scripting_fprintf(NULL, "EOF\n"); |
1436 | | | 1442 | |
1437 | fclose(f); | | 1443 | fclose(f); |
1438 | fflush(NULL); | | 1444 | fflush(NULL); |
1439 | return 0; | | 1445 | return 0; |
1440 | } | | 1446 | } |
1441 | | | 1447 | |
1442 | static bool | | 1448 | static bool |
1443 | find_part_by_name(const char *name, struct disk_partitions **parts, | | 1449 | find_part_by_name(const char *name, struct disk_partitions **parts, |
1444 | part_id *pno) | | 1450 | part_id *pno) |
1445 | { | | 1451 | { |
1446 | struct pm_devs *i; | | 1452 | struct pm_devs *i; |
1447 | struct disk_partitions *ps; | | 1453 | struct disk_partitions *ps; |
1448 | part_id id; | | 1454 | part_id id; |
1449 | struct disk_desc disks[MAX_DISKS]; | | 1455 | struct disk_desc disks[MAX_DISKS]; |
1450 | int n, cnt; | | 1456 | int n, cnt; |
1451 | | | 1457 | |
1452 | if (SLIST_EMPTY(&pm_head)) { | | 1458 | if (SLIST_EMPTY(&pm_head)) { |
1453 | /* | | 1459 | /* |
1454 | * List has not been filled, only "pm" is valid - check | | 1460 | * List has not been filled, only "pm" is valid - check |
1455 | * that first. | | 1461 | * that first. |
1456 | */ | | 1462 | */ |
1457 | if (pm->parts != NULL && | | 1463 | if (pm->parts != NULL && |
1458 | pm->parts->pscheme->find_by_name != NULL) { | | 1464 | pm->parts->pscheme->find_by_name != NULL) { |
1459 | id = pm->parts->pscheme->find_by_name(pm->parts, name); | | 1465 | id = pm->parts->pscheme->find_by_name(pm->parts, name); |
1460 | if (id != NO_PART) { | | 1466 | if (id != NO_PART) { |
1461 | *pno = id; | | 1467 | *pno = id; |
1462 | *parts = pm->parts; | | 1468 | *parts = pm->parts; |
1463 | return true; | | 1469 | return true; |
1464 | } | | 1470 | } |
1465 | } | | 1471 | } |
1466 | /* | | 1472 | /* |
1467 | * Not that easy - check all other disks | | 1473 | * Not that easy - check all other disks |
1468 | */ | | 1474 | */ |
1469 | cnt = get_disks(disks, false); | | 1475 | cnt = get_disks(disks, false); |
1470 | for (n = 0; n < cnt; n++) { | | 1476 | for (n = 0; n < cnt; n++) { |
1471 | if (strcmp(disks[n].dd_name, pm->diskdev) == 0) | | 1477 | if (strcmp(disks[n].dd_name, pm->diskdev) == 0) |
1472 | continue; | | 1478 | continue; |
1473 | ps = partitions_read_disk(disks[n].dd_name, | | 1479 | ps = partitions_read_disk(disks[n].dd_name, |
1474 | disks[n].dd_totsec, | | 1480 | disks[n].dd_totsec, |
1475 | disks[n].dd_secsize, | | 1481 | disks[n].dd_secsize, |
1476 | disks[n].dd_no_mbr); | | 1482 | disks[n].dd_no_mbr); |
1477 | if (ps == NULL) | | 1483 | if (ps == NULL) |
1478 | continue; | | 1484 | continue; |
1479 | if (ps->pscheme->find_by_name == NULL) | | 1485 | if (ps->pscheme->find_by_name == NULL) |
1480 | continue; | | 1486 | continue; |
1481 | id = ps->pscheme->find_by_name(ps, name); | | 1487 | id = ps->pscheme->find_by_name(ps, name); |
1482 | if (id != NO_PART) { | | 1488 | if (id != NO_PART) { |
1483 | *pno = id; | | 1489 | *pno = id; |
1484 | *parts = ps; | | 1490 | *parts = ps; |
1485 | return true; /* XXX this leaks memory */ | | 1491 | return true; /* XXX this leaks memory */ |
1486 | } | | 1492 | } |
1487 | ps->pscheme->free(ps); | | 1493 | ps->pscheme->free(ps); |
1488 | } | | 1494 | } |
1489 | } else { | | 1495 | } else { |
1490 | SLIST_FOREACH(i, &pm_head, l) { | | 1496 | SLIST_FOREACH(i, &pm_head, l) { |
1491 | if (i->parts == NULL) | | 1497 | if (i->parts == NULL) |
1492 | continue; | | 1498 | continue; |
1493 | if (i->parts->pscheme->find_by_name == NULL) | | 1499 | if (i->parts->pscheme->find_by_name == NULL) |
1494 | continue; | | 1500 | continue; |
1495 | id = i->parts->pscheme->find_by_name(i->parts, name); | | 1501 | id = i->parts->pscheme->find_by_name(i->parts, name); |
1496 | if (id == NO_PART) | | 1502 | if (id == NO_PART) |
1497 | continue; | | 1503 | continue; |
1498 | *pno = id; | | 1504 | *pno = id; |
1499 | *parts = i->parts; | | 1505 | *parts = i->parts; |
1500 | return true; | | 1506 | return true; |
1501 | } | | 1507 | } |
1502 | } | | 1508 | } |
1503 | | | 1509 | |
1504 | *pno = NO_PART; | | 1510 | *pno = NO_PART; |
1505 | *parts = NULL; | | 1511 | *parts = NULL; |
1506 | return false; | | 1512 | return false; |
1507 | } | | 1513 | } |
1508 | | | 1514 | |
1509 | static int | | 1515 | static int |
1510 | /*ARGSUSED*/ | | 1516 | /*ARGSUSED*/ |
1511 | process_found_fs(struct data *list, size_t num, const struct lookfor *item, | | 1517 | process_found_fs(struct data *list, size_t num, const struct lookfor *item, |
1512 | bool with_fsck) | | 1518 | bool with_fsck) |
1513 | { | | 1519 | { |
1514 | int error; | | 1520 | int error; |
1515 | char rdev[PATH_MAX], dev[PATH_MAX], | | 1521 | char rdev[PATH_MAX], dev[PATH_MAX], |
1516 | options[STRSIZE], tmp[STRSIZE], *op, *last; | | 1522 | options[STRSIZE], tmp[STRSIZE], *op, *last; |
1517 | const char *fsname = (const char*)item->var; | | 1523 | const char *fsname = (const char*)item->var; |
1518 | part_id pno; | | 1524 | part_id pno; |
1519 | struct disk_partitions *parts; | | 1525 | struct disk_partitions *parts; |
1520 | size_t len; | | 1526 | size_t len; |
1521 | bool first, is_root; | | 1527 | bool first, is_root; |
1522 | | | 1528 | |
1523 | if (num < 2 || strstr(list[2].u.s_val, "noauto") != NULL) | | 1529 | if (num < 2 || strstr(list[2].u.s_val, "noauto") != NULL) |
1524 | return 0; | | 1530 | return 0; |
1525 | | | 1531 | |
1526 | is_root = strcmp(list[1].u.s_val, "/") == 0; | | 1532 | is_root = strcmp(list[1].u.s_val, "/") == 0; |
1527 | if (is_root && target_mounted()) | | 1533 | if (is_root && target_mounted()) |
1528 | return 0; | | 1534 | return 0; |
1529 | | | 1535 | |
1530 | if (strcmp(item->head, name_prefix) == 0) { | | 1536 | if (strcmp(item->head, name_prefix) == 0) { |
1531 | /* this fstab entry uses NAME= syntax */ | | 1537 | /* this fstab entry uses NAME= syntax */ |
1532 | | | 1538 | |
1533 | /* unescape */ | | 1539 | /* unescape */ |
1534 | char *src, *dst; | | 1540 | char *src, *dst; |
1535 | for (src = list[0].u.s_val, dst =src; src[0] != 0; ) { | | 1541 | for (src = list[0].u.s_val, dst =src; src[0] != 0; ) { |
1536 | if (src[0] == '\\' && src[1] != 0) | | 1542 | if (src[0] == '\\' && src[1] != 0) |
1537 | src++; | | 1543 | src++; |
1538 | *dst++ = *src++; | | 1544 | *dst++ = *src++; |
1539 | } | | 1545 | } |
1540 | *dst = 0; | | 1546 | *dst = 0; |
1541 | | | 1547 | |
1542 | if (!find_part_by_name(list[0].u.s_val, | | 1548 | if (!find_part_by_name(list[0].u.s_val, |
1543 | &parts, &pno) || parts == NULL || pno == NO_PART) | | 1549 | &parts, &pno) || parts == NULL || pno == NO_PART) |
1544 | return 0; | | 1550 | return 0; |
1545 | parts->pscheme->get_part_device(parts, pno, | | 1551 | parts->pscheme->get_part_device(parts, pno, |
1546 | dev, sizeof(dev), NULL, plain_name, true, true); | | 1552 | dev, sizeof(dev), NULL, plain_name, true, true); |
1547 | parts->pscheme->get_part_device(parts, pno, | | 1553 | parts->pscheme->get_part_device(parts, pno, |
1548 | rdev, sizeof(rdev), NULL, raw_dev_name, true, true); | | 1554 | rdev, sizeof(rdev), NULL, raw_dev_name, true, true); |
1549 | } else { | | 1555 | } else { |
1550 | /* this fstab entry uses the plain device name */ | | 1556 | /* this fstab entry uses the plain device name */ |
1551 | if (is_root) { | | 1557 | if (is_root) { |
1552 | /* | | 1558 | /* |
1553 | * PR 54480: we can not use the current device name | | 1559 | * PR 54480: we can not use the current device name |
1554 | * as it might be different from the real environment. | | 1560 | * as it might be different from the real environment. |
1555 | * This is an abuse of the functionality, but it used | | 1561 | * This is an abuse of the functionality, but it used |
1556 | * to work before (and still does work if only a single | | 1562 | * to work before (and still does work if only a single |
1557 | * target disk is involved). | | 1563 | * target disk is involved). |
1558 | * Use the device name from the current "pm" instead. | | 1564 | * Use the device name from the current "pm" instead. |
1559 | */ | | 1565 | */ |
1560 | strcpy(rdev, "/dev/r"); | | 1566 | strcpy(rdev, "/dev/r"); |
1561 | strlcat(rdev, pm->diskdev, sizeof(rdev)); | | 1567 | strlcat(rdev, pm->diskdev, sizeof(rdev)); |
1562 | strcpy(dev, "/dev/"); | | 1568 | strcpy(dev, "/dev/"); |
1563 | strlcat(dev, pm->diskdev, sizeof(dev)); | | 1569 | strlcat(dev, pm->diskdev, sizeof(dev)); |
1564 | /* copy over the partition letter, if any */ | | 1570 | /* copy over the partition letter, if any */ |
1565 | len = strlen(list[0].u.s_val); | | 1571 | len = strlen(list[0].u.s_val); |
1566 | if (list[0].u.s_val[len-1] >= 'a' && | | 1572 | if (list[0].u.s_val[len-1] >= 'a' && |
1567 | list[0].u.s_val[len-1] <= | | 1573 | list[0].u.s_val[len-1] <= |
1568 | ('a' + getmaxpartitions())) { | | 1574 | ('a' + getmaxpartitions())) { |
1569 | strlcat(rdev, &list[0].u.s_val[len-1], | | 1575 | strlcat(rdev, &list[0].u.s_val[len-1], |
1570 | sizeof(rdev)); | | 1576 | sizeof(rdev)); |
1571 | strlcat(dev, &list[0].u.s_val[len-1], | | 1577 | strlcat(dev, &list[0].u.s_val[len-1], |
1572 | sizeof(dev)); | | 1578 | sizeof(dev)); |
1573 | } | | 1579 | } |
1574 | } else { | | 1580 | } else { |
1575 | strcpy(rdev, "/dev/r"); | | 1581 | strcpy(rdev, "/dev/r"); |
1576 | strlcat(rdev, list[0].u.s_val, sizeof(rdev)); | | 1582 | strlcat(rdev, list[0].u.s_val, sizeof(rdev)); |
1577 | strcpy(dev, "/dev/"); | | 1583 | strcpy(dev, "/dev/"); |
1578 | strlcat(dev, list[0].u.s_val, sizeof(dev)); | | 1584 | strlcat(dev, list[0].u.s_val, sizeof(dev)); |
1579 | } | | 1585 | } |
1580 | } | | 1586 | } |
1581 | | | 1587 | |
1582 | if (with_fsck) { | | 1588 | if (with_fsck) { |
1583 | /* need the raw device for fsck_preen */ | | 1589 | /* need the raw device for fsck_preen */ |
1584 | error = fsck_preen(rdev, fsname, false); | | 1590 | error = fsck_preen(rdev, fsname, false); |
1585 | if (error != 0) | | 1591 | if (error != 0) |
1586 | return error; | | 1592 | return error; |
1587 | } | | 1593 | } |
1588 | | | 1594 | |
1589 | /* add mount option for fs type */ | | 1595 | /* add mount option for fs type */ |
1590 | strcpy(options, "-t "); | | 1596 | strcpy(options, "-t "); |
1591 | strlcat(options, fsname, sizeof(options)); | | 1597 | strlcat(options, fsname, sizeof(options)); |
1592 | | | 1598 | |
1593 | /* extract mount options from fstab */ | | 1599 | /* extract mount options from fstab */ |
1594 | strlcpy(tmp, list[2].u.s_val, sizeof(tmp)); | | 1600 | strlcpy(tmp, list[2].u.s_val, sizeof(tmp)); |
1595 | for (first = true, op = strtok_r(tmp, ",", &last); op != NULL; | | 1601 | for (first = true, op = strtok_r(tmp, ",", &last); op != NULL; |
1596 | op = strtok_r(NULL, ",", &last)) { | | 1602 | op = strtok_r(NULL, ",", &last)) { |
1597 | if (strcmp(op, FSTAB_RW) == 0 || | | 1603 | if (strcmp(op, FSTAB_RW) == 0 || |
1598 | strcmp(op, FSTAB_RQ) == 0 || | | 1604 | strcmp(op, FSTAB_RQ) == 0 || |
1599 | strcmp(op, FSTAB_RO) == 0 || | | 1605 | strcmp(op, FSTAB_RO) == 0 || |
1600 | strcmp(op, FSTAB_SW) == 0 || | | 1606 | strcmp(op, FSTAB_SW) == 0 || |
1601 | strcmp(op, FSTAB_DP) == 0 || | | 1607 | strcmp(op, FSTAB_DP) == 0 || |
1602 | strcmp(op, FSTAB_XX) == 0) | | 1608 | strcmp(op, FSTAB_XX) == 0) |
1603 | continue; | | 1609 | continue; |
1604 | if (first) { | | 1610 | if (first) { |
1605 | first = false; | | 1611 | first = false; |
1606 | strlcat(options, " -o ", sizeof(options)); | | 1612 | strlcat(options, " -o ", sizeof(options)); |
1607 | } else { | | 1613 | } else { |
1608 | strlcat(options, ",", sizeof(options)); | | 1614 | strlcat(options, ",", sizeof(options)); |
1609 | } | | 1615 | } |
1610 | strlcat(options, op, sizeof(options)); | | 1616 | strlcat(options, op, sizeof(options)); |
1611 | } | | 1617 | } |
1612 | | | 1618 | |
1613 | error = target_mount(options, dev, list[1].u.s_val); | | 1619 | error = target_mount(options, dev, list[1].u.s_val); |
1614 | if (error != 0) { | | 1620 | if (error != 0) { |
1615 | msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val); | | 1621 | msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val); |
1616 | if (!ask_noyes(NULL)) | | 1622 | if (!ask_noyes(NULL)) |
1617 | return error; | | 1623 | return error; |
1618 | } | | 1624 | } |
1619 | return 0; | | 1625 | return 0; |
1620 | } | | 1626 | } |
1621 | | | 1627 | |
1622 | static int | | 1628 | static int |
1623 | /*ARGSUSED*/ | | 1629 | /*ARGSUSED*/ |
1624 | found_fs(struct data *list, size_t num, const struct lookfor *item) | | 1630 | found_fs(struct data *list, size_t num, const struct lookfor *item) |
1625 | { | | 1631 | { |
1626 | return process_found_fs(list, num, item, true); | | 1632 | return process_found_fs(list, num, item, true); |
1627 | } | | 1633 | } |
1628 | | | 1634 | |
1629 | static int | | 1635 | static int |
1630 | /*ARGSUSED*/ | | 1636 | /*ARGSUSED*/ |
1631 | found_fs_nocheck(struct data *list, size_t num, const struct lookfor *item) | | 1637 | found_fs_nocheck(struct data *list, size_t num, const struct lookfor *item) |
1632 | { | | 1638 | { |
1633 | return process_found_fs(list, num, item, false); | | 1639 | return process_found_fs(list, num, item, false); |
1634 | } | | 1640 | } |
1635 | | | 1641 | |
1636 | /* | | 1642 | /* |
1637 | * Do an fsck. On failure, inform the user by showing a warning | | 1643 | * Do an fsck. On failure, inform the user by showing a warning |
1638 | * message and doing menu_ok() before proceeding. | | 1644 | * message and doing menu_ok() before proceeding. |
1639 | * The device passed should be the full qualified path to raw disk | | 1645 | * The device passed should be the full qualified path to raw disk |
1640 | * (e.g. /dev/rwd0a). | | 1646 | * (e.g. /dev/rwd0a). |
1641 | * Returns 0 on success, or nonzero return code from fsck() on failure. | | 1647 | * Returns 0 on success, or nonzero return code from fsck() on failure. |
1642 | */ | | 1648 | */ |
1643 | static int | | 1649 | static int |
1644 | fsck_preen(const char *disk, const char *fsname, bool silent) | | 1650 | fsck_preen(const char *disk, const char *fsname, bool silent) |
1645 | { | | 1651 | { |
1646 | char *prog, err[12]; | | 1652 | char *prog, err[12]; |
1647 | int error; | | 1653 | int error; |
1648 | | | 1654 | |
1649 | if (fsname == NULL) | | 1655 | if (fsname == NULL) |
1650 | return 0; | | 1656 | return 0; |
1651 | /* first, check if fsck program exists, if not, assume ok */ | | 1657 | /* first, check if fsck program exists, if not, assume ok */ |
1652 | asprintf(&prog, "/sbin/fsck_%s", fsname); | | 1658 | asprintf(&prog, "/sbin/fsck_%s", fsname); |
1653 | if (prog == NULL) | | 1659 | if (prog == NULL) |
1654 | return 0; | | 1660 | return 0; |
1655 | if (access(prog, X_OK) != 0) { | | 1661 | if (access(prog, X_OK) != 0) { |
1656 | free(prog); | | 1662 | free(prog); |
1657 | return 0; | | 1663 | return 0; |
1658 | } | | 1664 | } |
1659 | if (!strcmp(fsname,"ffs")) | | 1665 | if (!strcmp(fsname,"ffs")) |
1660 | fixsb(prog, disk); | | 1666 | fixsb(prog, disk); |
1661 | error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk); | | 1667 | error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk); |
1662 | free(prog); | | 1668 | free(prog); |
1663 | if (error != 0 && !silent) { | | 1669 | if (error != 0 && !silent) { |
1664 | sprintf(err, "%d", error); | | 1670 | sprintf(err, "%d", error); |
1665 | msg_display_subst(msg_string(MSG_badfs), 3, | | 1671 | msg_display_subst(msg_string(MSG_badfs), 3, |
1666 | disk, fsname, err); | | 1672 | disk, fsname, err); |
1667 | if (ask_noyes(NULL)) | | 1673 | if (ask_noyes(NULL)) |
1668 | error = 0; | | 1674 | error = 0; |
1669 | /* XXX at this point maybe we should run a full fsck? */ | | 1675 | /* XXX at this point maybe we should run a full fsck? */ |
1670 | } | | 1676 | } |
1671 | return error; | | 1677 | return error; |
1672 | } | | 1678 | } |
1673 | | | 1679 | |
1674 | /* This performs the same function as the etc/rc.d/fixsb script | | 1680 | /* This performs the same function as the etc/rc.d/fixsb script |
1675 | * which attempts to correct problems with ffs1 filesystems | | 1681 | * which attempts to correct problems with ffs1 filesystems |
1676 | * which may have been introduced by booting a netbsd-current kernel | | 1682 | * which may have been introduced by booting a netbsd-current kernel |
1677 | * from between April of 2003 and January 2004. For more information | | 1683 | * from between April of 2003 and January 2004. For more information |
1678 | * This script was developed as a response to NetBSD pr install/25138 | | 1684 | * This script was developed as a response to NetBSD pr install/25138 |
1679 | * Additional prs regarding the original issue include: | | 1685 | * Additional prs regarding the original issue include: |
1680 | * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926 | | 1686 | * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926 |
1681 | */ | | 1687 | */ |
1682 | static void | | 1688 | static void |
1683 | fixsb(const char *prog, const char *disk) | | 1689 | fixsb(const char *prog, const char *disk) |
1684 | { | | 1690 | { |
1685 | int fd; | | 1691 | int fd; |
1686 | int rval; | | 1692 | int rval; |
1687 | union { | | 1693 | union { |
1688 | struct fs fs; | | 1694 | struct fs fs; |
1689 | char buf[SBLOCKSIZE]; | | 1695 | char buf[SBLOCKSIZE]; |
1690 | } sblk; | | 1696 | } sblk; |
1691 | struct fs *fs = &sblk.fs; | | 1697 | struct fs *fs = &sblk.fs; |
1692 | | | 1698 | |
1693 | fd = open(disk, O_RDONLY); | | 1699 | fd = open(disk, O_RDONLY); |
1694 | if (fd == -1) | | 1700 | if (fd == -1) |
1695 | return; | | 1701 | return; |
1696 | | | 1702 | |
1697 | /* Read ffsv1 main superblock */ | | 1703 | /* Read ffsv1 main superblock */ |
1698 | rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1); | | 1704 | rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1); |
1699 | close(fd); | | 1705 | close(fd); |
1700 | if (rval != sizeof sblk.buf) | | 1706 | if (rval != sizeof sblk.buf) |
1701 | return; | | 1707 | return; |
1702 | | | 1708 | |
1703 | if (fs->fs_magic != FS_UFS1_MAGIC && | | 1709 | if (fs->fs_magic != FS_UFS1_MAGIC && |
1704 | fs->fs_magic != FS_UFS1_MAGIC_SWAPPED) | | 1710 | fs->fs_magic != FS_UFS1_MAGIC_SWAPPED) |
1705 | /* Not FFSv1 */ | | 1711 | /* Not FFSv1 */ |
1706 | return; | | 1712 | return; |
1707 | if (fs->fs_old_flags & FS_FLAGS_UPDATED) | | 1713 | if (fs->fs_old_flags & FS_FLAGS_UPDATED) |
1708 | /* properly updated fslevel 4 */ | | 1714 | /* properly updated fslevel 4 */ |
1709 | return; | | 1715 | return; |
1710 | if (fs->fs_bsize != fs->fs_maxbsize) | | 1716 | if (fs->fs_bsize != fs->fs_maxbsize) |
1711 | /* not messed up */ | | 1717 | /* not messed up */ |
1712 | return; | | 1718 | return; |
1713 | | | 1719 | |
1714 | /* | | 1720 | /* |
1715 | * OK we have a munged fs, first 'upgrade' to fslevel 4, | | 1721 | * OK we have a munged fs, first 'upgrade' to fslevel 4, |
1716 | * We specify -b16 in order to stop fsck bleating that the | | 1722 | * We specify -b16 in order to stop fsck bleating that the |
1717 | * sb doesn't match the first alternate. | | 1723 | * sb doesn't match the first alternate. |
1718 | */ | | 1724 | */ |
1719 | run_program(RUN_DISPLAY | RUN_PROGRESS, | | 1725 | run_program(RUN_DISPLAY | RUN_PROGRESS, |
1720 | "%s -p -b 16 -c 4 %s", prog, disk); | | 1726 | "%s -p -b 16 -c 4 %s", prog, disk); |
1721 | /* Then downgrade to fslevel 3 */ | | 1727 | /* Then downgrade to fslevel 3 */ |
1722 | run_program(RUN_DISPLAY | RUN_PROGRESS, | | 1728 | run_program(RUN_DISPLAY | RUN_PROGRESS, |
1723 | "%s -p -c 3 %s", prog, disk); | | 1729 | "%s -p -c 3 %s", prog, disk); |
1724 | } | | 1730 | } |
1725 | | | 1731 | |
1726 | /* | | 1732 | /* |
1727 | * fsck and mount the root partition. | | 1733 | * fsck and mount the root partition. |
1728 | * devdev is the fully qualified block device name. | | 1734 | * devdev is the fully qualified block device name. |
1729 | */ | | 1735 | */ |
1730 | static int | | 1736 | static int |
1731 | mount_root(const char *devdev, bool first, bool writeable, | | 1737 | mount_root(const char *devdev, bool first, bool writeable, |
1732 | struct install_partition_desc *install) | | 1738 | struct install_partition_desc *install) |
1733 | { | | 1739 | { |
1734 | int error; | | 1740 | int error; |
1735 | | | 1741 | |
1736 | error = fsck_preen(devdev, "ffs", false); | | 1742 | error = fsck_preen(devdev, "ffs", false); |
1737 | if (error != 0) | | 1743 | if (error != 0) |
1738 | return error; | | 1744 | return error; |
1739 | | | 1745 | |
1740 | if (first) | | 1746 | if (first) |
1741 | md_pre_mount(install, 0); | | 1747 | md_pre_mount(install, 0); |
1742 | | | 1748 | |
1743 | /* Mount devdev on target's "". | | 1749 | /* Mount devdev on target's "". |
1744 | * If we pass "" as mount-on, Prefixing will DTRT. | | 1750 | * If we pass "" as mount-on, Prefixing will DTRT. |
1745 | * for now, use no options. | | 1751 | * for now, use no options. |
1746 | * XXX consider -o remount in case target root is | | 1752 | * XXX consider -o remount in case target root is |
1747 | * current root, still readonly from single-user? | | 1753 | * current root, still readonly from single-user? |
1748 | */ | | 1754 | */ |
1749 | return target_mount(writeable? "" : "-r", devdev, ""); | | 1755 | return target_mount(writeable? "" : "-r", devdev, ""); |
1750 | } | | 1756 | } |
1751 | | | 1757 | |
1752 | /* Get information on the file systems mounted from the root filesystem. | | 1758 | /* Get information on the file systems mounted from the root filesystem. |
1753 | * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD | | 1759 | * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD |
1754 | * inodes. Fsck them. Mount them. | | 1760 | * inodes. Fsck them. Mount them. |
1755 | */ | | 1761 | */ |
1756 | | | 1762 | |
1757 | int | | 1763 | int |
1758 | mount_disks(struct install_partition_desc *install) | | 1764 | mount_disks(struct install_partition_desc *install) |
1759 | { | | 1765 | { |
1760 | char *fstab; | | 1766 | char *fstab; |
1761 | int fstabsize; | | 1767 | int fstabsize; |
1762 | int error; | | 1768 | int error; |
1763 | char devdev[PATH_MAX]; | | 1769 | char devdev[PATH_MAX]; |
1764 | size_t i, num_fs_types, num_entries; | | 1770 | size_t i, num_fs_types, num_entries; |
1765 | struct lookfor *fstabbuf, *l; | | 1771 | struct lookfor *fstabbuf, *l; |
1766 | | | 1772 | |