File: | src/sbin/newfs/newfs.c |
Warning: | line 449, column 16 Access to field 'd_secsize' results in a dereference of a null pointer (loaded from variable 'lp') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: newfs.c,v 1.118 2024/01/09 03:16:00 guenther Exp $ */ | |||
2 | /* $NetBSD: newfs.c,v 1.20 1996/05/16 07:13:03 thorpej Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 2002 Networks Associates Technology, Inc. | |||
6 | * All rights reserved. | |||
7 | * | |||
8 | * This software was developed for the FreeBSD Project by Marshall | |||
9 | * Kirk McKusick and Network Associates Laboratories, the Security | |||
10 | * Research Division of Network Associates, Inc. under DARPA/SPAWAR | |||
11 | * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS | |||
12 | * research program. | |||
13 | * | |||
14 | * Copyright (c) 1983, 1989, 1993, 1994 | |||
15 | * The Regents of the University of California. All rights reserved. | |||
16 | * | |||
17 | * Redistribution and use in source and binary forms, with or without | |||
18 | * modification, are permitted provided that the following conditions | |||
19 | * are met: | |||
20 | * 1. Redistributions of source code must retain the above copyright | |||
21 | * notice, this list of conditions and the following disclaimer. | |||
22 | * 2. Redistributions in binary form must reproduce the above copyright | |||
23 | * notice, this list of conditions and the following disclaimer in the | |||
24 | * documentation and/or other materials provided with the distribution. | |||
25 | * 3. Neither the name of the University nor the names of its contributors | |||
26 | * may be used to endorse or promote products derived from this software | |||
27 | * without specific prior written permission. | |||
28 | * | |||
29 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
30 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
33 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
37 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
38 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
39 | * SUCH DAMAGE. | |||
40 | */ | |||
41 | ||||
42 | #include <sys/param.h> /* DEV_BSIZE MAXBSIZE */ | |||
43 | #include <sys/types.h> | |||
44 | #include <sys/stat.h> | |||
45 | #include <sys/ioctl.h> | |||
46 | #include <sys/dkio.h> | |||
47 | #include <sys/disklabel.h> | |||
48 | #include <sys/mount.h> | |||
49 | #include <sys/resource.h> | |||
50 | #include <sys/sysctl.h> | |||
51 | #include <sys/wait.h> | |||
52 | ||||
53 | #include <ufs/ufs/dinode.h> | |||
54 | #include <ufs/ufs/dir.h> | |||
55 | #include <ufs/ffs/fs.h> | |||
56 | ||||
57 | #include <ctype.h> | |||
58 | #include <err.h> | |||
59 | #include <errno(*__errno()).h> | |||
60 | #include <fcntl.h> | |||
61 | #include <paths.h> | |||
62 | #include <stdarg.h> | |||
63 | #include <stdio.h> | |||
64 | #include <stdlib.h> | |||
65 | #include <string.h> | |||
66 | #include <syslog.h> | |||
67 | #include <unistd.h> | |||
68 | #include <limits.h> | |||
69 | #include <signal.h> | |||
70 | #include <util.h> | |||
71 | ||||
72 | #include "mntopts.h" | |||
73 | #include "pathnames.h" | |||
74 | ||||
75 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) | |||
76 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) | |||
77 | ||||
78 | struct mntopt mopts[] = { | |||
79 | MOPT_STDOPTS{ "userquota", 0, 0x02 | 0x04 | 0x10 }, { "groupquota", 0, 0x02 | 0x04 | 0x10 }, { "ro", 0x00000001, 0x02 }, { "rw", 0x00000001 , 0x01 | 0x02 }, { "net", 0, 0x02 }, { "auto", 0, 0x02 }, { "accesstime" , 0x00008000, 0x01 | 0x02 }, { "atime", 0x00008000, 0x01 | 0x02 }, { "dev", 0x00000010, 0x01 | 0x02 }, { "exec", 0x00000004, 0x01 | 0x02 }, { "suid", 0x00000008, 0x01 | 0x02 }, { "rdonly" , 0x00000001, 0x02 }, | |||
80 | MOPT_WXALLOWED{ "wxallowed", 0x00000800, 0x02 }, | |||
81 | MOPT_NOPERM{ "perm", 0x00000020, 0x01 | 0x02 }, | |||
82 | MOPT_ASYNC{ "async", 0x00000040, 0x02 }, | |||
83 | MOPT_UPDATE{ "update", 0x00010000, 0x02 }, | |||
84 | MOPT_FORCE{ "force", 0x00080000, 0x02 }, | |||
85 | { NULL((void *)0) }, | |||
86 | }; | |||
87 | ||||
88 | void fatal(const char *fmt, ...) | |||
89 | __attribute__((__format__ (printf, 1, 2))) | |||
90 | __attribute__((__nonnull__ (1))); | |||
91 | __dead__attribute__((__noreturn__)) void usage(void); | |||
92 | void mkfs(struct partition *, char *, int, int, mode_t, uid_t, gid_t); | |||
93 | void getphysmem(void); | |||
94 | void rewritelabel(char *, int, struct disklabel *); | |||
95 | u_short dkcksum(struct disklabel *); | |||
96 | ||||
97 | /* | |||
98 | * The following two constants set the default block and fragment sizes. | |||
99 | * Both constants must be a power of 2 and meet the following constraints: | |||
100 | * MINBSIZE <= DESBLKSIZE <= MAXBSIZE | |||
101 | * sectorsize <= DESFRAGSIZE <= DESBLKSIZE | |||
102 | * DESBLKSIZE / DESFRAGSIZE <= 8 | |||
103 | */ | |||
104 | #define DFL_FRAGSIZE2048 2048 | |||
105 | #define DFL_BLKSIZE16384 16384 | |||
106 | ||||
107 | /* | |||
108 | * MAXBLKPG determines the maximum number of data blocks which are | |||
109 | * placed in a single cylinder group. The default is one indirect | |||
110 | * block worth of data blocks. | |||
111 | */ | |||
112 | #define MAXBLKPG_FFS1(bsize)((bsize) / sizeof(int32_t)) ((bsize) / sizeof(int32_t)) | |||
113 | #define MAXBLKPG_FFS2(bsize)((bsize) / sizeof(int64_t)) ((bsize) / sizeof(int64_t)) | |||
114 | ||||
115 | /* | |||
116 | * Each file system has a number of inodes statically allocated. | |||
117 | * We allocate one inode slot per NFPI fragments, expecting this | |||
118 | * to be far more than we will ever need. | |||
119 | */ | |||
120 | #define NFPI4 4 | |||
121 | ||||
122 | int mfs; /* run as the memory based filesystem */ | |||
123 | int Nflag; /* run without writing file system */ | |||
124 | int Oflag = 2; /* 1 = 4.4BSD ffs, 2 = ffs2 */ | |||
125 | daddr_t fssize; /* file system size in 512-byte blocks */ | |||
126 | long long sectorsize; /* bytes/sector */ | |||
127 | int fsize = 0; /* fragment size */ | |||
128 | int bsize = 0; /* block size */ | |||
129 | int maxfrgspercg = INT_MAX0x7fffffff; /* maximum fragments per cylinder group */ | |||
130 | int minfree = MINFREE5; /* free space threshold */ | |||
131 | int opt = DEFAULTOPT0; /* optimization preference (space or time) */ | |||
132 | int reqopt = -1; /* opt preference has not been specified */ | |||
133 | int density; /* number of bytes per inode */ | |||
134 | int maxbpg; /* maximum blocks per file in a cyl group */ | |||
135 | int avgfilesize = AVFILESIZ16384;/* expected average file size */ | |||
136 | int avgfilesperdir = AFPDIR64;/* expected number of files per directory */ | |||
137 | int mntflags = MNT_ASYNC0x00000040; /* flags to be passed to mount */ | |||
138 | int quiet = 0; /* quiet flag */ | |||
139 | caddr_t membase; /* start address of memory based filesystem */ | |||
140 | char *disktype; | |||
141 | int unlabeled; | |||
142 | ||||
143 | extern char *__progname; | |||
144 | struct disklabel *getdisklabel(char *, int); | |||
145 | ||||
146 | #ifdef MFS1 | |||
147 | static void waitformount(char *, pid_t); | |||
148 | static int do_exec(const char *, const char *, char *const[]); | |||
149 | static int isdir(const char *); | |||
150 | static void copy(char *, char *); | |||
151 | static int gettmpmnt(char *, size_t); | |||
152 | #endif | |||
153 | ||||
154 | int64_t physmem; | |||
155 | ||||
156 | void | |||
157 | getphysmem(void) | |||
158 | { | |||
159 | int mib[] = { CTL_HW6, HW_PHYSMEM6419 }; | |||
160 | size_t len = sizeof(physmem); | |||
161 | ||||
162 | if (sysctl(mib, 2, &physmem, &len, NULL((void *)0), 0) != 0) | |||
163 | err(1, "can't get physmem"); | |||
164 | } | |||
165 | ||||
166 | int | |||
167 | main(int argc, char *argv[]) | |||
168 | { | |||
169 | int ch; | |||
170 | struct partition *pp; | |||
171 | struct disklabel *lp; | |||
172 | struct disklabel mfsfakelabel; | |||
173 | struct partition oldpartition; | |||
174 | struct stat st; | |||
175 | struct statfs *mp; | |||
176 | struct rlimit rl; | |||
177 | int fsi = -1, oflagset = 0, fso, len, n, maxpartitions; | |||
178 | char *cp = NULL((void *)0), *s1, *s2, *special, *opstring, *realdev; | |||
179 | #ifdef MFS1 | |||
180 | char mountfromname[BUFSIZ1024]; | |||
181 | char *pop = NULL((void *)0), node[PATH_MAX1024]; | |||
182 | pid_t pid; | |||
183 | struct stat mountpoint; | |||
184 | #endif | |||
185 | uid_t mfsuid = 0; | |||
186 | gid_t mfsgid = 0; | |||
187 | mode_t mfsmode = 0; | |||
188 | char *fstype = NULL((void *)0); | |||
189 | char **saveargv = argv; | |||
190 | int ffsflag = 1; | |||
191 | const char *errstr; | |||
192 | long long fssize_input = 0; | |||
193 | int fssize_usebytes = 0; | |||
194 | int defaultfsize; | |||
195 | u_int64_t nsecs; | |||
196 | ||||
197 | if (strstr(__progname, "mfs")) | |||
| ||||
198 | mfs = Nflag = quiet = Oflag = 1; | |||
199 | ||||
200 | getphysmem(); | |||
201 | maxpartitions = getmaxpartitions(); | |||
202 | if (maxpartitions > 26) | |||
203 | fatal("insane maxpartitions value %d", maxpartitions); | |||
204 | ||||
205 | opstring = mfs ? | |||
206 | "O:P:T:b:c:e:f:i:m:o:s:" : | |||
207 | "NO:S:T:b:c:e:f:g:h:i:m:o:qs:t:"; | |||
208 | while ((ch = getopt(argc, argv, opstring)) != -1) { | |||
209 | switch (ch) { | |||
210 | case 'N': | |||
211 | Nflag = 1; | |||
212 | break; | |||
213 | case 'O': | |||
214 | Oflag = strtonum(optarg, 1, 2, &errstr); | |||
215 | if (errstr) | |||
216 | fatal("%s: invalid ffs version", optarg); | |||
217 | oflagset = 1; | |||
218 | break; | |||
219 | case 'S': | |||
220 | if (scan_scaled(optarg, §orsize) == -1 || | |||
221 | sectorsize <= 0 || (sectorsize % DEV_BSIZE(1 << 9))) | |||
222 | fatal("sector size invalid: %s", optarg); | |||
223 | break; | |||
224 | case 'T': | |||
225 | disktype = optarg; | |||
226 | break; | |||
227 | case 'b': | |||
228 | bsize = strtonum(optarg, MINBSIZE4096, MAXBSIZE(64 * 1024), &errstr); | |||
229 | if (errstr) | |||
230 | fatal("block size is %s: %s", errstr, optarg); | |||
231 | break; | |||
232 | case 'c': | |||
233 | maxfrgspercg = strtonum(optarg, 1, INT_MAX0x7fffffff, &errstr); | |||
234 | if (errstr) | |||
235 | fatal("fragments per cylinder group is %s: %s", | |||
236 | errstr, optarg); | |||
237 | break; | |||
238 | case 'e': | |||
239 | maxbpg = strtonum(optarg, 1, INT_MAX0x7fffffff, &errstr); | |||
240 | if (errstr) | |||
241 | fatal("blocks per file in a cylinder group is" | |||
242 | " %s: %s", errstr, optarg); | |||
243 | break; | |||
244 | case 'f': | |||
245 | fsize = strtonum(optarg, MINBSIZE4096 / MAXFRAG8, MAXBSIZE(64 * 1024), | |||
246 | &errstr); | |||
247 | if (errstr) | |||
248 | fatal("fragment size is %s: %s", | |||
249 | errstr, optarg); | |||
250 | break; | |||
251 | case 'g': | |||
252 | avgfilesize = strtonum(optarg, 1, INT_MAX0x7fffffff, &errstr); | |||
253 | if (errstr) | |||
254 | fatal("average file size is %s: %s", | |||
255 | errstr, optarg); | |||
256 | break; | |||
257 | case 'h': | |||
258 | avgfilesperdir = strtonum(optarg, 1, INT_MAX0x7fffffff, &errstr); | |||
259 | if (errstr) | |||
260 | fatal("average files per dir is %s: %s", | |||
261 | errstr, optarg); | |||
262 | break; | |||
263 | case 'i': | |||
264 | density = strtonum(optarg, 1, INT_MAX0x7fffffff, &errstr); | |||
265 | if (errstr) | |||
266 | fatal("bytes per inode is %s: %s", | |||
267 | errstr, optarg); | |||
268 | break; | |||
269 | case 'm': | |||
270 | minfree = strtonum(optarg, 0, 99, &errstr); | |||
271 | if (errstr) | |||
272 | fatal("free space %% is %s: %s", | |||
273 | errstr, optarg); | |||
274 | break; | |||
275 | case 'o': | |||
276 | if (mfs) | |||
277 | getmntopts(optarg, mopts, &mntflags); | |||
278 | else { | |||
279 | if (strcmp(optarg, "space") == 0) | |||
280 | reqopt = opt = FS_OPTSPACE1; | |||
281 | else if (strcmp(optarg, "time") == 0) | |||
282 | reqopt = opt = FS_OPTTIME0; | |||
283 | else | |||
284 | fatal("%s: unknown optimization " | |||
285 | "preference: use `space' or `time'.", | |||
286 | optarg); | |||
287 | } | |||
288 | break; | |||
289 | case 'q': | |||
290 | quiet = 1; | |||
291 | break; | |||
292 | case 's': | |||
293 | if (scan_scaled(optarg, &fssize_input) == -1 || | |||
294 | fssize_input <= 0) | |||
295 | fatal("file system size invalid: %s", optarg); | |||
296 | fssize_usebytes = 0; /* in case of multiple -s */ | |||
297 | for (s1 = optarg; *s1 != '\0'; s1++) | |||
298 | if (isalpha((unsigned char)*s1)) { | |||
299 | fssize_usebytes = 1; | |||
300 | break; | |||
301 | } | |||
302 | break; | |||
303 | case 't': | |||
304 | fstype = optarg; | |||
305 | if (strcmp(fstype, "ffs")) | |||
306 | ffsflag = 0; | |||
307 | break; | |||
308 | #ifdef MFS1 | |||
309 | case 'P': | |||
310 | pop = optarg; | |||
311 | break; | |||
312 | #endif | |||
313 | default: | |||
314 | usage(); | |||
315 | } | |||
316 | if (!ffsflag) | |||
317 | break; | |||
318 | } | |||
319 | argc -= optind; | |||
320 | argv += optind; | |||
321 | ||||
322 | if (ffsflag
| |||
323 | usage(); | |||
324 | ||||
325 | if (mfs
| |||
326 | /* Increase our data size to the max */ | |||
327 | if (getrlimit(RLIMIT_DATA2, &rl) == 0) { | |||
328 | rl.rlim_cur = rl.rlim_max; | |||
329 | (void)setrlimit(RLIMIT_DATA2, &rl); | |||
330 | } | |||
331 | } | |||
332 | ||||
333 | special = argv[0]; | |||
334 | ||||
335 | if (!mfs
| |||
336 | char execname[PATH_MAX1024], name[PATH_MAX1024]; | |||
337 | ||||
338 | if (fstype == NULL((void *)0)) | |||
339 | fstype = readlabelfs(special, 0); | |||
340 | if (fstype != NULL((void *)0) && strcmp(fstype, "ffs")) { | |||
341 | snprintf(name, sizeof name, "newfs_%s", fstype); | |||
342 | saveargv[0] = name; | |||
343 | snprintf(execname, sizeof execname, "%s/newfs_%s", | |||
344 | _PATH_SBIN"/sbin", fstype); | |||
345 | (void)execv(execname, saveargv); | |||
346 | snprintf(execname, sizeof execname, "%s/newfs_%s", | |||
347 | _PATH_USRSBIN"/usr/sbin", fstype); | |||
348 | (void)execv(execname, saveargv); | |||
349 | err(1, "%s not found", name); | |||
350 | } | |||
351 | } | |||
352 | ||||
353 | if (mfs
| |||
354 | /* | |||
355 | * it's an MFS, mounted on "swap." fake up a label. | |||
356 | * XXX XXX XXX | |||
357 | */ | |||
358 | fso = -1; /* XXX; normally done below. */ | |||
359 | ||||
360 | memset(&mfsfakelabel, 0, sizeof(mfsfakelabel)); | |||
361 | mfsfakelabel.d_secsize = 512; | |||
362 | mfsfakelabel.d_nsectors = 64; | |||
363 | mfsfakelabel.d_ntracks = 16; | |||
364 | mfsfakelabel.d_ncylinders = 16; | |||
365 | mfsfakelabel.d_secpercyl = 1024; | |||
366 | DL_SETDSIZE(&mfsfakelabel, 16384)do { u_int64_t __x = (16384); (&mfsfakelabel)->d_secperunith = __x >> 32; (&mfsfakelabel)->d_secperunit = __x ; } while (0); | |||
367 | mfsfakelabel.d_npartitions = 1; | |||
368 | mfsfakelabel.d_version = 1; | |||
369 | DL_SETPSIZE(&mfsfakelabel.d_partitions[0], 16384)do { u_int64_t __x = (16384); (&mfsfakelabel.d_partitions [0])->p_sizeh = __x >> 32; (&mfsfakelabel.d_partitions [0])->p_size = __x; } while (0); | |||
370 | mfsfakelabel.d_partitions[0].p_fragblock = | |||
371 | DISKLABELV1_FFS_FRAGBLOCK(1024, 8)((1024) * (8) == 0 ? 0 : (((ffs((1024) * (8)) - 13) << 3 ) | (ffs(8)))); | |||
372 | mfsfakelabel.d_partitions[0].p_cpg = 16; | |||
373 | ||||
374 | lp = &mfsfakelabel; | |||
375 | pp = &mfsfakelabel.d_partitions[0]; | |||
376 | ||||
377 | goto havelabel; | |||
378 | } | |||
379 | if (Nflag) { | |||
380 | fso = -1; | |||
381 | } else { | |||
382 | fso = opendev(special, O_WRONLY0x0001, 0, &realdev); | |||
383 | if (fso == -1) | |||
384 | fatal("%s: %s", special, strerror(errno(*__errno()))); | |||
385 | special = realdev; | |||
386 | ||||
387 | /* Bail if target special is mounted */ | |||
388 | n = getmntinfo(&mp, MNT_NOWAIT2); | |||
389 | if (n == 0) | |||
390 | fatal("%s: getmntinfo: %s", special, strerror(errno(*__errno()))); | |||
391 | ||||
392 | len = sizeof(_PATH_DEV"/dev/") - 1; | |||
393 | s1 = special; | |||
394 | if (strncmp(_PATH_DEV"/dev/", s1, len) == 0) | |||
395 | s1 += len; | |||
396 | ||||
397 | while (--n >= 0) { | |||
398 | s2 = mp->f_mntfromname; | |||
399 | if (strncmp(_PATH_DEV"/dev/", s2, len) == 0) { | |||
400 | s2 += len - 1; | |||
401 | *s2 = 'r'; | |||
402 | } | |||
403 | if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) | |||
404 | fatal("%s is mounted on %s", | |||
405 | special, mp->f_mntonname); | |||
406 | ++mp; | |||
407 | } | |||
408 | } | |||
409 | if (mfs
| |||
410 | lp = (struct disklabel *)getdiskbyname(disktype); | |||
411 | if (lp == NULL((void *)0)) | |||
412 | fatal("%s: unknown disk type", disktype); | |||
413 | pp = &lp->d_partitions[1]; | |||
414 | } else { | |||
415 | fsi = opendev(special, O_RDONLY0x0000, 0, NULL((void *)0)); | |||
416 | if (fsi == -1) | |||
417 | fatal("%s: %s", special, strerror(errno(*__errno()))); | |||
418 | if (fstat(fsi, &st) == -1) | |||
419 | fatal("%s: %s", special, strerror(errno(*__errno()))); | |||
420 | if (!mfs) { | |||
421 | if (S_ISBLK(st.st_mode)((st.st_mode & 0170000) == 0060000)) | |||
422 | fatal("%s: block device", special); | |||
423 | if (!S_ISCHR(st.st_mode)((st.st_mode & 0170000) == 0020000)) | |||
424 | warnx("%s: not a character-special device", | |||
425 | special); | |||
426 | } | |||
427 | if (*argv[0] == '\0') | |||
428 | fatal("empty partition name supplied"); | |||
429 | cp = argv[0] + strlen(argv[0]) - 1; | |||
430 | if ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) | |||
431 | && !isdigit((unsigned char)*cp)) | |||
432 | fatal("%s: can't figure out file system partition", | |||
433 | argv[0]); | |||
434 | lp = getdisklabel(special, fsi); | |||
435 | if (!mfs) { | |||
436 | if (pledge("stdio disklabel tty", NULL((void *)0)) == -1) | |||
437 | err(1, "pledge"); | |||
438 | } | |||
439 | if (isdigit((unsigned char)*cp)) | |||
440 | pp = &lp->d_partitions[0]; | |||
441 | else | |||
442 | pp = &lp->d_partitions[*cp - 'a']; | |||
443 | if (DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0) | |||
444 | fatal("%s: `%c' partition is unavailable", | |||
445 | argv[0], *cp); | |||
446 | } | |||
447 | havelabel: | |||
448 | if (sectorsize == 0) { | |||
449 | sectorsize = lp->d_secsize; | |||
| ||||
450 | if (sectorsize <= 0) | |||
451 | fatal("%s: no default sector size", argv[0]); | |||
452 | } | |||
453 | ||||
454 | if (fssize_usebytes) { | |||
455 | nsecs = fssize_input / sectorsize; | |||
456 | if (fssize_input % sectorsize != 0) | |||
457 | nsecs++; | |||
458 | } else if (fssize_input == 0) | |||
459 | nsecs = DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size); | |||
460 | else | |||
461 | nsecs = fssize_input; | |||
462 | ||||
463 | if (nsecs > DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) && !mfs) | |||
464 | fatal("%s: maximum file system size on the `%c' partition is " | |||
465 | "%llu sectors", argv[0], *cp, DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size)); | |||
466 | ||||
467 | /* Can't use DL_SECTOBLK() because sectorsize may not be from label! */ | |||
468 | fssize = nsecs * (sectorsize / DEV_BSIZE(1 << 9)); | |||
469 | if (oflagset == 0 && fssize >= INT_MAX0x7fffffff) | |||
470 | Oflag = 2; /* FFS2 */ | |||
471 | defaultfsize = fsize == 0; | |||
472 | if (fsize == 0) { | |||
473 | fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock)(((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) & 0x07) - 1))) == 0 ? 0 : (((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock) >> 3) + 12))) / ((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) & 0x07) - 1))))); | |||
474 | if (fsize <= 0) | |||
475 | fsize = MAXIMUM(DFL_FRAGSIZE, lp->d_secsize)(((2048) > (lp->d_secsize)) ? (2048) : (lp->d_secsize )); | |||
476 | } | |||
477 | if (bsize == 0) { | |||
478 | bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock)((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) >> 3) + 12))); | |||
479 | if (bsize <= 0) | |||
480 | bsize = MINIMUM(DFL_BLKSIZE, 8 * fsize)(((16384) < (8 * fsize)) ? (16384) : (8 * fsize)); | |||
481 | } | |||
482 | if (density == 0) { | |||
483 | density = NFPI4 * fsize; | |||
484 | /* large sectors lead to fewer inodes due to large fsize, | |||
485 | compensate */ | |||
486 | if (defaultfsize && sectorsize > DEV_BSIZE(1 << 9)) | |||
487 | density /= 2; | |||
488 | } | |||
489 | if (minfree < MINFREE5 && opt != FS_OPTSPACE1 && reqopt == -1) { | |||
490 | warnx("warning: changing optimization to space " | |||
491 | "because minfree is less than %d%%\n", MINFREE5); | |||
492 | opt = FS_OPTSPACE1; | |||
493 | } | |||
494 | if (maxbpg == 0) { | |||
495 | if (Oflag <= 1) | |||
496 | maxbpg = MAXBLKPG_FFS1(bsize)((bsize) / sizeof(int32_t)); | |||
497 | else | |||
498 | maxbpg = MAXBLKPG_FFS2(bsize)((bsize) / sizeof(int64_t)); | |||
499 | } | |||
500 | oldpartition = *pp; | |||
501 | #ifdef MFS1 | |||
502 | if (mfs) { | |||
503 | if (realpath(argv[1], node) == NULL((void *)0)) | |||
504 | err(1, "realpath %s", argv[1]); | |||
505 | if (stat(node, &mountpoint) == -1) | |||
506 | err(ECANCELED88, "stat %s", node); | |||
507 | mfsuid = mountpoint.st_uid; | |||
508 | mfsgid = mountpoint.st_gid; | |||
509 | mfsmode = mountpoint.st_mode & ALLPERMS(0004000|0002000|0001000|0000700|0000070|0000007); | |||
510 | } | |||
511 | #endif | |||
512 | ||||
513 | mkfs(pp, special, fsi, fso, mfsmode, mfsuid, mfsgid); | |||
514 | if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition))) | |||
515 | rewritelabel(special, fso, lp); | |||
516 | if (!Nflag) | |||
517 | close(fso); | |||
518 | if (fsi != -1) | |||
519 | close(fsi); | |||
520 | #ifdef MFS1 | |||
521 | if (mfs) { | |||
522 | struct mfs_args args; | |||
523 | char tmpnode[PATH_MAX1024]; | |||
524 | ||||
525 | if (pop != NULL((void *)0) && gettmpmnt(tmpnode, sizeof(tmpnode)) == 0) | |||
526 | errx(1, "Cannot create tmp mountpoint for -P"); | |||
527 | memset(&args, 0, sizeof(args)); | |||
528 | args.base = membase; | |||
529 | args.size = fssize * DEV_BSIZE(1 << 9); | |||
530 | args.export_info.ex_root = -2; | |||
531 | if (mntflags & MNT_RDONLY0x00000001) | |||
532 | args.export_info.ex_flags = MNT_EXRDONLY0x00000080; | |||
533 | if (mntflags & MNT_NOPERM0x00000020) | |||
534 | mntflags |= MNT_NODEV0x00000010 | MNT_NOEXEC0x00000004; | |||
535 | ||||
536 | switch (pid = fork()) { | |||
537 | case -1: | |||
538 | err(10, "mfs"); | |||
539 | case 0: | |||
540 | snprintf(mountfromname, sizeof(mountfromname), | |||
541 | "mfs:%d", getpid()); | |||
542 | break; | |||
543 | default: | |||
544 | if (pop != NULL((void *)0)) { | |||
545 | waitformount(tmpnode, pid); | |||
546 | copy(pop, tmpnode); | |||
547 | unmount(tmpnode, 0); | |||
548 | rmdir(tmpnode); | |||
549 | } | |||
550 | waitformount(node, pid); | |||
551 | exit(0); | |||
552 | /* NOTREACHED */ | |||
553 | } | |||
554 | ||||
555 | (void) setsid(); | |||
556 | (void) close(0); | |||
557 | (void) close(1); | |||
558 | (void) close(2); | |||
559 | (void) chdir("/"); | |||
560 | ||||
561 | args.fspec = mountfromname; | |||
562 | if (pop != NULL((void *)0)) { | |||
563 | int tmpflags = mntflags & ~MNT_RDONLY0x00000001; | |||
564 | if (mount(MOUNT_MFS"mfs", tmpnode, tmpflags, &args) == -1) | |||
565 | exit(errno(*__errno())); /* parent prints message */ | |||
566 | } | |||
567 | if (mount(MOUNT_MFS"mfs", node, mntflags, &args) == -1) | |||
568 | exit(errno(*__errno())); /* parent prints message */ | |||
569 | } | |||
570 | #endif | |||
571 | exit(0); | |||
572 | } | |||
573 | ||||
574 | struct disklabel * | |||
575 | getdisklabel(char *s, int fd) | |||
576 | { | |||
577 | static struct disklabel lab; | |||
578 | ||||
579 | if (ioctl(fd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (char *)&lab) == -1) { | |||
580 | if (disktype != NULL((void *)0)) { | |||
581 | struct disklabel *lp; | |||
582 | ||||
583 | unlabeled++; | |||
584 | lp = getdiskbyname(disktype); | |||
585 | if (lp == NULL((void *)0)) | |||
586 | fatal("%s: unknown disk type", disktype); | |||
587 | return (lp); | |||
588 | } | |||
589 | warn("ioctl (GDINFO)"); | |||
590 | fatal("%s: can't read disk label; disk type must be specified", | |||
591 | s); | |||
592 | } | |||
593 | return (&lab); | |||
594 | } | |||
595 | ||||
596 | void | |||
597 | rewritelabel(char *s, int fd, struct disklabel *lp) | |||
598 | { | |||
599 | if (unlabeled) | |||
600 | return; | |||
601 | ||||
602 | lp->d_checksum = 0; | |||
603 | lp->d_checksum = dkcksum(lp); | |||
604 | if (ioctl(fd, DIOCWDINFO((unsigned long)0x80000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((103))), (char *)lp) == -1) { | |||
605 | warn("ioctl (WDINFO)"); | |||
606 | fatal("%s: can't rewrite disk label", s); | |||
607 | } | |||
608 | } | |||
609 | ||||
610 | void | |||
611 | fatal(const char *fmt, ...) | |||
612 | { | |||
613 | va_list ap; | |||
614 | ||||
615 | va_start(ap, fmt)__builtin_va_start((ap), fmt); | |||
616 | if (fcntl(STDERR_FILENO2, F_GETFL3) == -1) { | |||
617 | openlog(__progname, LOG_CONS0x02, LOG_DAEMON(3<<3)); | |||
618 | vsyslog(LOG_ERR3, fmt, ap); | |||
619 | closelog(); | |||
620 | } else { | |||
621 | vwarnx(fmt, ap); | |||
622 | } | |||
623 | va_end(ap)__builtin_va_end((ap)); | |||
624 | exit(1); | |||
625 | /*NOTREACHED*/ | |||
626 | } | |||
627 | ||||
628 | __dead__attribute__((__noreturn__)) void | |||
629 | usage(void) | |||
630 | { | |||
631 | extern char *__progname; | |||
632 | ||||
633 | if (mfs) { | |||
634 | fprintf(stderr(&__sF[2]), | |||
635 | "usage: %s [-b block-size] [-c fragments-per-cylinder-group] " | |||
636 | "[-e maxbpg]\n" | |||
637 | "\t[-f frag-size] [-i bytes] [-m free-space] [-o options] " | |||
638 | "[-P file]\n" | |||
639 | "\t[-s size] special node\n", | |||
640 | __progname); | |||
641 | } else { | |||
642 | fprintf(stderr(&__sF[2]), | |||
643 | "usage: %s [-Nq] [-b block-size] " | |||
644 | "[-c fragments-per-cylinder-group] [-e maxbpg]\n" | |||
645 | "\t[-f frag-size] [-g avgfilesize] [-h avgfpdir] [-i bytes]\n" | |||
646 | "\t[-m free-space] [-O filesystem-format] [-o optimization]\n" | |||
647 | "\t[-S sector-size] [-s size] [-T disktype] [-t fstype] " | |||
648 | "special\n", | |||
649 | __progname); | |||
650 | } | |||
651 | ||||
652 | exit(1); | |||
653 | } | |||
654 | ||||
655 | #ifdef MFS1 | |||
656 | ||||
657 | static void | |||
658 | waitformount(char *node, pid_t pid) | |||
659 | { | |||
660 | char mountfromname[BUFSIZ1024]; | |||
661 | struct statfs sf; | |||
662 | int status; | |||
663 | pid_t res; | |||
664 | ||||
665 | snprintf(mountfromname, sizeof(mountfromname), "mfs:%d", pid); | |||
666 | for (;;) { | |||
667 | /* | |||
668 | * spin until the mount succeeds | |||
669 | * or the child exits | |||
670 | */ | |||
671 | usleep(1); | |||
672 | ||||
673 | /* | |||
674 | * XXX Here is a race condition: another process | |||
675 | * can mount a filesystem which hides our | |||
676 | * ramdisk before we see the success. | |||
677 | */ | |||
678 | if (statfs(node, &sf) == -1) | |||
679 | err(ECANCELED88, "statfs %s", node); | |||
680 | if (!strcmp(sf.f_mntfromname, mountfromname) && | |||
681 | !strncmp(sf.f_mntonname, node, | |||
682 | MNAMELEN90) && | |||
683 | !strcmp(sf.f_fstypename, "mfs")) { | |||
684 | return; | |||
685 | } | |||
686 | res = waitpid(pid, &status, WNOHANG0x01); | |||
687 | if (res == -1) | |||
688 | err(EDEADLK11, "waitpid"); | |||
689 | if (res != pid) | |||
690 | continue; | |||
691 | if (WIFEXITED(status)(((status) & 0177) == 0)) { | |||
692 | if (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff) == 0) | |||
693 | exit(0); | |||
694 | errx(1, "%s: mount: %s", node, | |||
695 | strerror(WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff))); | |||
696 | } else | |||
697 | errx(EDEADLK11, "abnormal termination"); | |||
698 | } | |||
699 | } | |||
700 | ||||
701 | static int | |||
702 | do_exec(const char *dir, const char *cmd, char *const argv[]) | |||
703 | { | |||
704 | pid_t pid; | |||
705 | int ret, status; | |||
706 | sig_t intsave, quitsave; | |||
707 | ||||
708 | switch (pid = fork()) { | |||
709 | case -1: | |||
710 | err(1, "fork"); | |||
711 | case 0: | |||
712 | if (dir != NULL((void *)0) && chdir(dir) != 0) | |||
713 | err(1, "chdir"); | |||
714 | if (execv(cmd, argv) != 0) | |||
715 | err(1, "%s", cmd); | |||
716 | break; | |||
717 | default: | |||
718 | intsave = signal(SIGINT2, SIG_IGN(void (*)(int))1); | |||
719 | quitsave = signal(SIGQUIT3, SIG_IGN(void (*)(int))1); | |||
720 | for (;;) { | |||
721 | ret = waitpid(pid, &status, 0); | |||
722 | if (ret == -1) | |||
723 | err(11, "waitpid"); | |||
724 | if (WIFEXITED(status)(((status) & 0177) == 0)) { | |||
725 | status = WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff); | |||
726 | if (status != 0) | |||
727 | warnx("%s: exited", cmd); | |||
728 | break; | |||
729 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) { | |||
730 | warnx("%s: %s", cmd, | |||
731 | strsignal(WTERMSIG(status)(((status) & 0177)))); | |||
732 | status = 1; | |||
733 | break; | |||
734 | } | |||
735 | } | |||
736 | signal(SIGINT2, intsave); | |||
737 | signal(SIGQUIT3, quitsave); | |||
738 | return (status); | |||
739 | } | |||
740 | /* NOTREACHED */ | |||
741 | return (-1); | |||
742 | } | |||
743 | ||||
744 | static int | |||
745 | isdir(const char *path) | |||
746 | { | |||
747 | struct stat st; | |||
748 | ||||
749 | if (stat(path, &st) != 0) | |||
750 | err(1, "cannot stat %s", path); | |||
751 | if (!S_ISDIR(st.st_mode)((st.st_mode & 0170000) == 0040000) && !S_ISBLK(st.st_mode)((st.st_mode & 0170000) == 0060000)) | |||
752 | errx(1, "%s: not a dir or a block device", path); | |||
753 | return (S_ISDIR(st.st_mode)((st.st_mode & 0170000) == 0040000)); | |||
754 | } | |||
755 | ||||
756 | static void | |||
757 | copy(char *src, char *dst) | |||
758 | { | |||
759 | int ret, dir, created = 0; | |||
760 | struct ufs_args mount_args; | |||
761 | char mountpoint[MNAMELEN90]; | |||
762 | char *const argv[] = { "pax", "-rw", "-pe", ".", dst, NULL((void *)0) } ; | |||
763 | ||||
764 | dir = isdir(src); | |||
765 | if (dir) | |||
766 | strlcpy(mountpoint, src, sizeof(mountpoint)); | |||
767 | else { | |||
768 | created = gettmpmnt(mountpoint, sizeof(mountpoint)); | |||
769 | memset(&mount_args, 0, sizeof(mount_args)); | |||
770 | mount_args.fspec = src; | |||
771 | ret = mount(MOUNT_FFS"ffs", mountpoint, MNT_RDONLY0x00000001, &mount_args); | |||
772 | if (ret != 0) { | |||
773 | int saved_errno = errno(*__errno()); | |||
774 | if (created && rmdir(mountpoint) != 0) | |||
775 | warn("rmdir %s", mountpoint); | |||
776 | if (unmount(dst, 0) != 0) | |||
777 | warn("unmount %s", dst); | |||
778 | errc(1, saved_errno, "mount %s %s", src, mountpoint); | |||
779 | } | |||
780 | } | |||
781 | ret = do_exec(mountpoint, "/bin/pax", argv); | |||
782 | if (!dir && unmount(mountpoint, 0) != 0) | |||
783 | warn("unmount %s", mountpoint); | |||
784 | if (created && rmdir(mountpoint) != 0) | |||
785 | warn("rmdir %s", mountpoint); | |||
786 | if (ret != 0) { | |||
787 | if (unmount(dst, 0) != 0) | |||
788 | warn("unmount %s", dst); | |||
789 | errx(1, "copy %s to %s failed", mountpoint, dst); | |||
790 | } | |||
791 | } | |||
792 | ||||
793 | static int | |||
794 | gettmpmnt(char *mountpoint, size_t len) | |||
795 | { | |||
796 | const char *tmp = _PATH_TMP"/tmp/"; | |||
797 | const char *mnt = _PATH_MNT"/mnt"; | |||
798 | struct statfs fs; | |||
799 | size_t n; | |||
800 | ||||
801 | if (statfs(tmp, &fs) != 0) | |||
802 | err(1, "statfs %s", tmp); | |||
803 | if (fs.f_flags & MNT_RDONLY0x00000001) { | |||
804 | if (statfs(mnt, &fs) != 0) | |||
805 | err(1, "statfs %s", mnt); | |||
806 | if (strcmp(fs.f_mntonname, "/") != 0) | |||
807 | errx(1, "tmp mountpoint %s busy", mnt); | |||
808 | if (strlcpy(mountpoint, mnt, len) >= len) | |||
809 | errx(1, "tmp mountpoint %s too long", mnt); | |||
810 | return (0); | |||
811 | } | |||
812 | n = strlcpy(mountpoint, tmp, len); | |||
813 | if (n >= len) | |||
814 | errx(1, "tmp mount point too long"); | |||
815 | if (mountpoint[n - 1] != '/') | |||
816 | strlcat(mountpoint, "/", len); | |||
817 | n = strlcat(mountpoint, "mntXXXXXXXXXX", len); | |||
818 | if (n >= len) | |||
819 | errx(1, "tmp mount point too long"); | |||
820 | if (mkdtemp(mountpoint) == NULL((void *)0)) | |||
821 | err(1, "mkdtemp %s", mountpoint); | |||
822 | return (1); | |||
823 | } | |||
824 | ||||
825 | #endif /* MFS */ |