| File: | src/sbin/newfs/newfs.c |
| Warning: | line 450, 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.115 2021/06/03 06:42:03 otto 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; /* 0 = 4.3BSD ffs, 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_MAX2147483647; /* 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 | "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, 0, 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_MAX2147483647, &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_MAX2147483647, &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_MAX2147483647, &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_MAX2147483647, &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_MAX2147483647, &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 | case '?': | |||
| 314 | default: | |||
| 315 | usage(); | |||
| 316 | } | |||
| 317 | if (!ffsflag) | |||
| 318 | break; | |||
| 319 | } | |||
| 320 | argc -= optind; | |||
| 321 | argv += optind; | |||
| 322 | ||||
| 323 | if (ffsflag
| |||
| 324 | usage(); | |||
| 325 | ||||
| 326 | if (mfs
| |||
| 327 | /* Increase our data size to the max */ | |||
| 328 | if (getrlimit(RLIMIT_DATA2, &rl) == 0) { | |||
| 329 | rl.rlim_cur = rl.rlim_max; | |||
| 330 | (void)setrlimit(RLIMIT_DATA2, &rl); | |||
| 331 | } | |||
| 332 | } | |||
| 333 | ||||
| 334 | special = argv[0]; | |||
| 335 | ||||
| 336 | if (!mfs
| |||
| 337 | char execname[PATH_MAX1024], name[PATH_MAX1024]; | |||
| 338 | ||||
| 339 | if (fstype == NULL((void *)0)) | |||
| 340 | fstype = readlabelfs(special, 0); | |||
| 341 | if (fstype != NULL((void *)0) && strcmp(fstype, "ffs")) { | |||
| 342 | snprintf(name, sizeof name, "newfs_%s", fstype); | |||
| 343 | saveargv[0] = name; | |||
| 344 | snprintf(execname, sizeof execname, "%s/newfs_%s", | |||
| 345 | _PATH_SBIN"/sbin", fstype); | |||
| 346 | (void)execv(execname, saveargv); | |||
| 347 | snprintf(execname, sizeof execname, "%s/newfs_%s", | |||
| 348 | _PATH_USRSBIN"/usr/sbin", fstype); | |||
| 349 | (void)execv(execname, saveargv); | |||
| 350 | err(1, "%s not found", name); | |||
| 351 | } | |||
| 352 | } | |||
| 353 | ||||
| 354 | if (mfs
| |||
| 355 | /* | |||
| 356 | * it's an MFS, mounted on "swap." fake up a label. | |||
| 357 | * XXX XXX XXX | |||
| 358 | */ | |||
| 359 | fso = -1; /* XXX; normally done below. */ | |||
| 360 | ||||
| 361 | memset(&mfsfakelabel, 0, sizeof(mfsfakelabel)); | |||
| 362 | mfsfakelabel.d_secsize = 512; | |||
| 363 | mfsfakelabel.d_nsectors = 64; | |||
| 364 | mfsfakelabel.d_ntracks = 16; | |||
| 365 | mfsfakelabel.d_ncylinders = 16; | |||
| 366 | mfsfakelabel.d_secpercyl = 1024; | |||
| 367 | DL_SETDSIZE(&mfsfakelabel, 16384)do { u_int64_t __x = (16384); (&mfsfakelabel)->d_secperunith = __x >> 32; (&mfsfakelabel)->d_secperunit = __x ; } while (0); | |||
| 368 | mfsfakelabel.d_npartitions = 1; | |||
| 369 | mfsfakelabel.d_version = 1; | |||
| 370 | 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); | |||
| 371 | mfsfakelabel.d_partitions[0].p_fragblock = | |||
| 372 | DISKLABELV1_FFS_FRAGBLOCK(1024, 8)((1024) * (8) == 0 ? 0 : (((ffs((1024) * (8)) - 13) << 3 ) | (ffs(8)))); | |||
| 373 | mfsfakelabel.d_partitions[0].p_cpg = 16; | |||
| 374 | ||||
| 375 | lp = &mfsfakelabel; | |||
| 376 | pp = &mfsfakelabel.d_partitions[0]; | |||
| 377 | ||||
| 378 | goto havelabel; | |||
| 379 | } | |||
| 380 | if (Nflag) { | |||
| 381 | fso = -1; | |||
| 382 | } else { | |||
| 383 | fso = opendev(special, O_WRONLY0x0001, 0, &realdev); | |||
| 384 | if (fso == -1) | |||
| 385 | fatal("%s: %s", special, strerror(errno(*__errno()))); | |||
| 386 | special = realdev; | |||
| 387 | ||||
| 388 | /* Bail if target special is mounted */ | |||
| 389 | n = getmntinfo(&mp, MNT_NOWAIT2); | |||
| 390 | if (n == 0) | |||
| 391 | fatal("%s: getmntinfo: %s", special, strerror(errno(*__errno()))); | |||
| 392 | ||||
| 393 | len = sizeof(_PATH_DEV"/dev/") - 1; | |||
| 394 | s1 = special; | |||
| 395 | if (strncmp(_PATH_DEV"/dev/", s1, len) == 0) | |||
| 396 | s1 += len; | |||
| 397 | ||||
| 398 | while (--n >= 0) { | |||
| 399 | s2 = mp->f_mntfromname; | |||
| 400 | if (strncmp(_PATH_DEV"/dev/", s2, len) == 0) { | |||
| 401 | s2 += len - 1; | |||
| 402 | *s2 = 'r'; | |||
| 403 | } | |||
| 404 | if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) | |||
| 405 | fatal("%s is mounted on %s", | |||
| 406 | special, mp->f_mntonname); | |||
| 407 | ++mp; | |||
| 408 | } | |||
| 409 | } | |||
| 410 | if (mfs
| |||
| 411 | lp = (struct disklabel *)getdiskbyname(disktype); | |||
| 412 | if (lp == NULL((void *)0)) | |||
| 413 | fatal("%s: unknown disk type", disktype); | |||
| 414 | pp = &lp->d_partitions[1]; | |||
| 415 | } else { | |||
| 416 | fsi = opendev(special, O_RDONLY0x0000, 0, NULL((void *)0)); | |||
| 417 | if (fsi == -1) | |||
| 418 | fatal("%s: %s", special, strerror(errno(*__errno()))); | |||
| 419 | if (fstat(fsi, &st) == -1) | |||
| 420 | fatal("%s: %s", special, strerror(errno(*__errno()))); | |||
| 421 | if (!mfs) { | |||
| 422 | if (S_ISBLK(st.st_mode)((st.st_mode & 0170000) == 0060000)) | |||
| 423 | fatal("%s: block device", special); | |||
| 424 | if (!S_ISCHR(st.st_mode)((st.st_mode & 0170000) == 0020000)) | |||
| 425 | warnx("%s: not a character-special device", | |||
| 426 | special); | |||
| 427 | } | |||
| 428 | if (*argv[0] == '\0') | |||
| 429 | fatal("empty partition name supplied"); | |||
| 430 | cp = argv[0] + strlen(argv[0]) - 1; | |||
| 431 | if ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) | |||
| 432 | && !isdigit((unsigned char)*cp)) | |||
| 433 | fatal("%s: can't figure out file system partition", | |||
| 434 | argv[0]); | |||
| 435 | lp = getdisklabel(special, fsi); | |||
| 436 | if (!mfs) { | |||
| 437 | if (pledge("stdio disklabel tty", NULL((void *)0)) == -1) | |||
| 438 | err(1, "pledge"); | |||
| 439 | } | |||
| 440 | if (isdigit((unsigned char)*cp)) | |||
| 441 | pp = &lp->d_partitions[0]; | |||
| 442 | else | |||
| 443 | pp = &lp->d_partitions[*cp - 'a']; | |||
| 444 | if (DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) == 0) | |||
| 445 | fatal("%s: `%c' partition is unavailable", | |||
| 446 | argv[0], *cp); | |||
| 447 | } | |||
| 448 | havelabel: | |||
| 449 | if (sectorsize == 0) { | |||
| 450 | sectorsize = lp->d_secsize; | |||
| ||||
| 451 | if (sectorsize <= 0) | |||
| 452 | fatal("%s: no default sector size", argv[0]); | |||
| 453 | } | |||
| 454 | ||||
| 455 | if (fssize_usebytes) { | |||
| 456 | nsecs = fssize_input / sectorsize; | |||
| 457 | if (fssize_input % sectorsize != 0) | |||
| 458 | nsecs++; | |||
| 459 | } else if (fssize_input == 0) | |||
| 460 | nsecs = DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size); | |||
| 461 | else | |||
| 462 | nsecs = fssize_input; | |||
| 463 | ||||
| 464 | if (nsecs > DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size) && !mfs) | |||
| 465 | fatal("%s: maximum file system size on the `%c' partition is " | |||
| 466 | "%llu sectors", argv[0], *cp, DL_GETPSIZE(pp)(((u_int64_t)(pp)->p_sizeh << 32) + (pp)->p_size)); | |||
| 467 | ||||
| 468 | /* Can't use DL_SECTOBLK() because sectorsize may not be from label! */ | |||
| 469 | fssize = nsecs * (sectorsize / DEV_BSIZE(1 << 9)); | |||
| 470 | if (oflagset == 0 && fssize >= INT_MAX2147483647) | |||
| 471 | Oflag = 2; /* FFS2 */ | |||
| 472 | defaultfsize = fsize == 0; | |||
| 473 | if (fsize == 0) { | |||
| 474 | 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))))); | |||
| 475 | if (fsize <= 0) | |||
| 476 | fsize = MAXIMUM(DFL_FRAGSIZE, lp->d_secsize)(((2048) > (lp->d_secsize)) ? (2048) : (lp->d_secsize )); | |||
| 477 | } | |||
| 478 | if (bsize == 0) { | |||
| 479 | bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock)((pp->p_fragblock) == 0 ? 0 : (1 << (((pp->p_fragblock ) >> 3) + 12))); | |||
| 480 | if (bsize <= 0) | |||
| 481 | bsize = MINIMUM(DFL_BLKSIZE, 8 * fsize)(((16384) < (8 * fsize)) ? (16384) : (8 * fsize)); | |||
| 482 | } | |||
| 483 | if (density == 0) { | |||
| 484 | density = NFPI4 * fsize; | |||
| 485 | /* large sectors lead to fewer inodes due to large fsize, | |||
| 486 | compensate */ | |||
| 487 | if (defaultfsize && sectorsize > DEV_BSIZE(1 << 9)) | |||
| 488 | density /= 2; | |||
| 489 | } | |||
| 490 | if (minfree < MINFREE5 && opt != FS_OPTSPACE1 && reqopt == -1) { | |||
| 491 | warnx("warning: changing optimization to space " | |||
| 492 | "because minfree is less than %d%%\n", MINFREE5); | |||
| 493 | opt = FS_OPTSPACE1; | |||
| 494 | } | |||
| 495 | if (maxbpg == 0) { | |||
| 496 | if (Oflag <= 1) | |||
| 497 | maxbpg = MAXBLKPG_FFS1(bsize)((bsize) / sizeof(int32_t)); | |||
| 498 | else | |||
| 499 | maxbpg = MAXBLKPG_FFS2(bsize)((bsize) / sizeof(int64_t)); | |||
| 500 | } | |||
| 501 | oldpartition = *pp; | |||
| 502 | #ifdef MFS1 | |||
| 503 | if (mfs) { | |||
| 504 | if (realpath(argv[1], node) == NULL((void *)0)) | |||
| 505 | err(1, "realpath %s", argv[1]); | |||
| 506 | if (stat(node, &mountpoint) == -1) | |||
| 507 | err(ECANCELED88, "stat %s", node); | |||
| 508 | mfsuid = mountpoint.st_uid; | |||
| 509 | mfsgid = mountpoint.st_gid; | |||
| 510 | mfsmode = mountpoint.st_mode & ALLPERMS(0004000|0002000|0001000|0000700|0000070|0000007); | |||
| 511 | } | |||
| 512 | #endif | |||
| 513 | ||||
| 514 | mkfs(pp, special, fsi, fso, mfsmode, mfsuid, mfsgid); | |||
| 515 | if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition))) | |||
| 516 | rewritelabel(special, fso, lp); | |||
| 517 | if (!Nflag) | |||
| 518 | close(fso); | |||
| 519 | if (fsi != -1) | |||
| 520 | close(fsi); | |||
| 521 | #ifdef MFS1 | |||
| 522 | if (mfs) { | |||
| 523 | struct mfs_args args; | |||
| 524 | char tmpnode[PATH_MAX1024]; | |||
| 525 | ||||
| 526 | if (pop != NULL((void *)0) && gettmpmnt(tmpnode, sizeof(tmpnode)) == 0) | |||
| 527 | errx(1, "Cannot create tmp mountpoint for -P"); | |||
| 528 | memset(&args, 0, sizeof(args)); | |||
| 529 | args.base = membase; | |||
| 530 | args.size = fssize * DEV_BSIZE(1 << 9); | |||
| 531 | args.export_info.ex_root = -2; | |||
| 532 | if (mntflags & MNT_RDONLY0x00000001) | |||
| 533 | args.export_info.ex_flags = MNT_EXRDONLY0x00000080; | |||
| 534 | if (mntflags & MNT_NOPERM0x00000020) | |||
| 535 | mntflags |= MNT_NODEV0x00000010 | MNT_NOEXEC0x00000004; | |||
| 536 | ||||
| 537 | switch (pid = fork()) { | |||
| 538 | case -1: | |||
| 539 | err(10, "mfs"); | |||
| 540 | case 0: | |||
| 541 | snprintf(mountfromname, sizeof(mountfromname), | |||
| 542 | "mfs:%d", getpid()); | |||
| 543 | break; | |||
| 544 | default: | |||
| 545 | if (pop != NULL((void *)0)) { | |||
| 546 | waitformount(tmpnode, pid); | |||
| 547 | copy(pop, tmpnode); | |||
| 548 | unmount(tmpnode, 0); | |||
| 549 | rmdir(tmpnode); | |||
| 550 | } | |||
| 551 | waitformount(node, pid); | |||
| 552 | exit(0); | |||
| 553 | /* NOTREACHED */ | |||
| 554 | } | |||
| 555 | ||||
| 556 | (void) setsid(); | |||
| 557 | (void) close(0); | |||
| 558 | (void) close(1); | |||
| 559 | (void) close(2); | |||
| 560 | (void) chdir("/"); | |||
| 561 | ||||
| 562 | args.fspec = mountfromname; | |||
| 563 | if (pop != NULL((void *)0)) { | |||
| 564 | int tmpflags = mntflags & ~MNT_RDONLY0x00000001; | |||
| 565 | if (mount(MOUNT_MFS"mfs", tmpnode, tmpflags, &args) == -1) | |||
| 566 | exit(errno(*__errno())); /* parent prints message */ | |||
| 567 | } | |||
| 568 | if (mount(MOUNT_MFS"mfs", node, mntflags, &args) == -1) | |||
| 569 | exit(errno(*__errno())); /* parent prints message */ | |||
| 570 | } | |||
| 571 | #endif | |||
| 572 | exit(0); | |||
| 573 | } | |||
| 574 | ||||
| 575 | struct disklabel * | |||
| 576 | getdisklabel(char *s, int fd) | |||
| 577 | { | |||
| 578 | static struct disklabel lab; | |||
| 579 | ||||
| 580 | if (ioctl(fd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((101))), (char *)&lab) == -1) { | |||
| 581 | if (disktype != NULL((void *)0)) { | |||
| 582 | struct disklabel *lp; | |||
| 583 | ||||
| 584 | unlabeled++; | |||
| 585 | lp = getdiskbyname(disktype); | |||
| 586 | if (lp == NULL((void *)0)) | |||
| 587 | fatal("%s: unknown disk type", disktype); | |||
| 588 | return (lp); | |||
| 589 | } | |||
| 590 | warn("ioctl (GDINFO)"); | |||
| 591 | fatal("%s: can't read disk label; disk type must be specified", | |||
| 592 | s); | |||
| 593 | } | |||
| 594 | return (&lab); | |||
| 595 | } | |||
| 596 | ||||
| 597 | void | |||
| 598 | rewritelabel(char *s, int fd, struct disklabel *lp) | |||
| 599 | { | |||
| 600 | if (unlabeled) | |||
| 601 | return; | |||
| 602 | ||||
| 603 | lp->d_checksum = 0; | |||
| 604 | lp->d_checksum = dkcksum(lp); | |||
| 605 | if (ioctl(fd, DIOCWDINFO((unsigned long)0x80000000 | ((sizeof(struct disklabel) & 0x1fff) << 16) | ((('d')) << 8) | ((103))), (char *)lp) == -1) { | |||
| 606 | warn("ioctl (WDINFO)"); | |||
| 607 | fatal("%s: can't rewrite disk label", s); | |||
| 608 | } | |||
| 609 | } | |||
| 610 | ||||
| 611 | void | |||
| 612 | fatal(const char *fmt, ...) | |||
| 613 | { | |||
| 614 | va_list ap; | |||
| 615 | ||||
| 616 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 617 | if (fcntl(STDERR_FILENO2, F_GETFL3) == -1) { | |||
| 618 | openlog(__progname, LOG_CONS0x02, LOG_DAEMON(3<<3)); | |||
| 619 | vsyslog(LOG_ERR3, fmt, ap); | |||
| 620 | closelog(); | |||
| 621 | } else { | |||
| 622 | vwarnx(fmt, ap); | |||
| 623 | } | |||
| 624 | va_end(ap)__builtin_va_end(ap); | |||
| 625 | exit(1); | |||
| 626 | /*NOTREACHED*/ | |||
| 627 | } | |||
| 628 | ||||
| 629 | __dead__attribute__((__noreturn__)) void | |||
| 630 | usage(void) | |||
| 631 | { | |||
| 632 | extern char *__progname; | |||
| 633 | ||||
| 634 | if (mfs) { | |||
| 635 | fprintf(stderr(&__sF[2]), | |||
| 636 | "usage: %s [-b block-size] [-c fragments-per-cylinder-group] " | |||
| 637 | "[-e maxbpg]\n" | |||
| 638 | "\t[-f frag-size] [-i bytes] [-m free-space] [-o options] " | |||
| 639 | "[-P file]\n" | |||
| 640 | "\t[-s size] special node\n", | |||
| 641 | __progname); | |||
| 642 | } else { | |||
| 643 | fprintf(stderr(&__sF[2]), | |||
| 644 | "usage: %s [-Nq] [-b block-size] " | |||
| 645 | "[-c fragments-per-cylinder-group] [-e maxbpg]\n" | |||
| 646 | "\t[-f frag-size] [-g avgfilesize] [-h avgfpdir] [-i bytes]\n" | |||
| 647 | "\t[-m free-space] [-O filesystem-format] [-o optimization]\n" | |||
| 648 | "\t[-S sector-size] [-s size] [-T disktype] [-t fstype] " | |||
| 649 | "special\n", | |||
| 650 | __progname); | |||
| 651 | } | |||
| 652 | ||||
| 653 | exit(1); | |||
| 654 | } | |||
| 655 | ||||
| 656 | #ifdef MFS1 | |||
| 657 | ||||
| 658 | static void | |||
| 659 | waitformount(char *node, pid_t pid) | |||
| 660 | { | |||
| 661 | char mountfromname[BUFSIZ1024]; | |||
| 662 | struct statfs sf; | |||
| 663 | int status; | |||
| 664 | pid_t res; | |||
| 665 | ||||
| 666 | snprintf(mountfromname, sizeof(mountfromname), "mfs:%d", pid); | |||
| 667 | for (;;) { | |||
| 668 | /* | |||
| 669 | * spin until the mount succeeds | |||
| 670 | * or the child exits | |||
| 671 | */ | |||
| 672 | usleep(1); | |||
| 673 | ||||
| 674 | /* | |||
| 675 | * XXX Here is a race condition: another process | |||
| 676 | * can mount a filesystem which hides our | |||
| 677 | * ramdisk before we see the success. | |||
| 678 | */ | |||
| 679 | if (statfs(node, &sf) == -1) | |||
| 680 | err(ECANCELED88, "statfs %s", node); | |||
| 681 | if (!strcmp(sf.f_mntfromname, mountfromname) && | |||
| 682 | !strncmp(sf.f_mntonname, node, | |||
| 683 | MNAMELEN90) && | |||
| 684 | !strcmp(sf.f_fstypename, "mfs")) { | |||
| 685 | return; | |||
| 686 | } | |||
| 687 | res = waitpid(pid, &status, WNOHANG1); | |||
| 688 | if (res == -1) | |||
| 689 | err(EDEADLK11, "waitpid"); | |||
| 690 | if (res != pid) | |||
| 691 | continue; | |||
| 692 | if (WIFEXITED(status)(((status) & 0177) == 0)) { | |||
| 693 | if (WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff) == 0) | |||
| 694 | exit(0); | |||
| 695 | errx(1, "%s: mount: %s", node, | |||
| 696 | strerror(WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff))); | |||
| 697 | } else | |||
| 698 | errx(EDEADLK11, "abnormal termination"); | |||
| 699 | } | |||
| 700 | } | |||
| 701 | ||||
| 702 | static int | |||
| 703 | do_exec(const char *dir, const char *cmd, char *const argv[]) | |||
| 704 | { | |||
| 705 | pid_t pid; | |||
| 706 | int ret, status; | |||
| 707 | sig_t intsave, quitsave; | |||
| 708 | ||||
| 709 | switch (pid = fork()) { | |||
| 710 | case -1: | |||
| 711 | err(1, "fork"); | |||
| 712 | case 0: | |||
| 713 | if (dir != NULL((void *)0) && chdir(dir) != 0) | |||
| 714 | err(1, "chdir"); | |||
| 715 | if (execv(cmd, argv) != 0) | |||
| 716 | err(1, "%s", cmd); | |||
| 717 | break; | |||
| 718 | default: | |||
| 719 | intsave = signal(SIGINT2, SIG_IGN(void (*)(int))1); | |||
| 720 | quitsave = signal(SIGQUIT3, SIG_IGN(void (*)(int))1); | |||
| 721 | for (;;) { | |||
| 722 | ret = waitpid(pid, &status, 0); | |||
| 723 | if (ret == -1) | |||
| 724 | err(11, "waitpid"); | |||
| 725 | if (WIFEXITED(status)(((status) & 0177) == 0)) { | |||
| 726 | status = WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff); | |||
| 727 | if (status != 0) | |||
| 728 | warnx("%s: exited", cmd); | |||
| 729 | break; | |||
| 730 | } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177 ) != 0)) { | |||
| 731 | warnx("%s: %s", cmd, | |||
| 732 | strsignal(WTERMSIG(status)(((status) & 0177)))); | |||
| 733 | status = 1; | |||
| 734 | break; | |||
| 735 | } | |||
| 736 | } | |||
| 737 | signal(SIGINT2, intsave); | |||
| 738 | signal(SIGQUIT3, quitsave); | |||
| 739 | return (status); | |||
| 740 | } | |||
| 741 | /* NOTREACHED */ | |||
| 742 | return (-1); | |||
| 743 | } | |||
| 744 | ||||
| 745 | static int | |||
| 746 | isdir(const char *path) | |||
| 747 | { | |||
| 748 | struct stat st; | |||
| 749 | ||||
| 750 | if (stat(path, &st) != 0) | |||
| 751 | err(1, "cannot stat %s", path); | |||
| 752 | if (!S_ISDIR(st.st_mode)((st.st_mode & 0170000) == 0040000) && !S_ISBLK(st.st_mode)((st.st_mode & 0170000) == 0060000)) | |||
| 753 | errx(1, "%s: not a dir or a block device", path); | |||
| 754 | return (S_ISDIR(st.st_mode)((st.st_mode & 0170000) == 0040000)); | |||
| 755 | } | |||
| 756 | ||||
| 757 | static void | |||
| 758 | copy(char *src, char *dst) | |||
| 759 | { | |||
| 760 | int ret, dir, created = 0; | |||
| 761 | struct ufs_args mount_args; | |||
| 762 | char mountpoint[MNAMELEN90]; | |||
| 763 | char *const argv[] = { "pax", "-rw", "-pe", ".", dst, NULL((void *)0) } ; | |||
| 764 | ||||
| 765 | dir = isdir(src); | |||
| 766 | if (dir) | |||
| 767 | strlcpy(mountpoint, src, sizeof(mountpoint)); | |||
| 768 | else { | |||
| 769 | created = gettmpmnt(mountpoint, sizeof(mountpoint)); | |||
| 770 | memset(&mount_args, 0, sizeof(mount_args)); | |||
| 771 | mount_args.fspec = src; | |||
| 772 | ret = mount(MOUNT_FFS"ffs", mountpoint, MNT_RDONLY0x00000001, &mount_args); | |||
| 773 | if (ret != 0) { | |||
| 774 | int saved_errno = errno(*__errno()); | |||
| 775 | if (created && rmdir(mountpoint) != 0) | |||
| 776 | warn("rmdir %s", mountpoint); | |||
| 777 | if (unmount(dst, 0) != 0) | |||
| 778 | warn("unmount %s", dst); | |||
| 779 | errc(1, saved_errno, "mount %s %s", src, mountpoint); | |||
| 780 | } | |||
| 781 | } | |||
| 782 | ret = do_exec(mountpoint, "/bin/pax", argv); | |||
| 783 | if (!dir && unmount(mountpoint, 0) != 0) | |||
| 784 | warn("unmount %s", mountpoint); | |||
| 785 | if (created && rmdir(mountpoint) != 0) | |||
| 786 | warn("rmdir %s", mountpoint); | |||
| 787 | if (ret != 0) { | |||
| 788 | if (unmount(dst, 0) != 0) | |||
| 789 | warn("unmount %s", dst); | |||
| 790 | errx(1, "copy %s to %s failed", mountpoint, dst); | |||
| 791 | } | |||
| 792 | } | |||
| 793 | ||||
| 794 | static int | |||
| 795 | gettmpmnt(char *mountpoint, size_t len) | |||
| 796 | { | |||
| 797 | const char *tmp = _PATH_TMP"/tmp/"; | |||
| 798 | const char *mnt = _PATH_MNT"/mnt"; | |||
| 799 | struct statfs fs; | |||
| 800 | size_t n; | |||
| 801 | ||||
| 802 | if (statfs(tmp, &fs) != 0) | |||
| 803 | err(1, "statfs %s", tmp); | |||
| 804 | if (fs.f_flags & MNT_RDONLY0x00000001) { | |||
| 805 | if (statfs(mnt, &fs) != 0) | |||
| 806 | err(1, "statfs %s", mnt); | |||
| 807 | if (strcmp(fs.f_mntonname, "/") != 0) | |||
| 808 | errx(1, "tmp mountpoint %s busy", mnt); | |||
| 809 | if (strlcpy(mountpoint, mnt, len) >= len) | |||
| 810 | errx(1, "tmp mountpoint %s too long", mnt); | |||
| 811 | return (0); | |||
| 812 | } | |||
| 813 | n = strlcpy(mountpoint, tmp, len); | |||
| 814 | if (n >= len) | |||
| 815 | errx(1, "tmp mount point too long"); | |||
| 816 | if (mountpoint[n - 1] != '/') | |||
| 817 | strlcat(mountpoint, "/", len); | |||
| 818 | n = strlcat(mountpoint, "mntXXXXXXXXXX", len); | |||
| 819 | if (n >= len) | |||
| 820 | errx(1, "tmp mount point too long"); | |||
| 821 | if (mkdtemp(mountpoint) == NULL((void *)0)) | |||
| 822 | err(1, "mkdtemp %s", mountpoint); | |||
| 823 | return (1); | |||
| 824 | } | |||
| 825 | ||||
| 826 | #endif /* MFS */ |