xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsck/setup.c (revision fe0e7ec4)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #define	DKTYPENAMES
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <ustat.h>
36 #include <errno.h>
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/sysmacros.h>
40 #include <sys/mntent.h>
41 #include <sys/mnttab.h>
42 #include <sys/dkio.h>
43 #include <sys/filio.h>
44 #include <sys/isa_defs.h>	/* for ENDIAN defines */
45 #include <sys/int_const.h>
46 #include <sys/vnode.h>
47 #include <sys/stat.h>
48 #include <sys/file.h>
49 #include <sys/fcntl.h>
50 #include <string.h>
51 #include <sys/vfstab.h>
52 #include <sys/fs/udf_volume.h>
53 #include <sys/vtoc.h>
54 #include <locale.h>
55 
56 #include "fsck.h"
57 
58 extern void	errexit(char *, ...);
59 extern int32_t	mounted(char *);
60 extern void	pwarn(char *, ...);
61 extern void	pfatal(char *, ...);
62 extern void	printclean();
63 extern void	bufinit();
64 extern void	ckfini();
65 extern int32_t	bread(int32_t, char *, daddr_t, long);
66 extern int32_t	reply(char *);
67 
68 static int32_t	readvolseq(int32_t);
69 static uint32_t	get_last_block();
70 extern int32_t	verifytag(struct tag *, uint32_t, struct tag *, int);
71 extern char	*tagerrs[];
72 
73 #define	POWEROF2(num)	(((num) & ((num) - 1)) == 0)
74 
75 extern int	mflag;
76 extern char 	hotroot;
77 
78 char avdbuf[MAXBSIZE];		/* buffer for anchor volume descriptor */
79 char *main_vdbuf;		/* buffer for entire main volume sequence */
80 char *res_vdbuf;		/* buffer for reserved volume sequence */
81 int serialnum = -1;		/* set from primary volume descriptor */
82 
83 char *
84 setup(char *dev)
85 {
86 	dev_t rootdev;
87 	struct stat statb;
88 	static char devstr[MAXPATHLEN];
89 	char *raw, *rawname(), *unrawname();
90 	struct ustat ustatb;
91 
92 	havesb = 0;
93 	if (stat("/", &statb) < 0)
94 		errexit(gettext("Can't stat root\n"));
95 	rootdev = statb.st_dev;
96 
97 	devname = devstr;
98 	(void) strncpy(devstr, dev, sizeof (devstr));
99 restat:
100 	if (stat(devstr, &statb) < 0) {
101 		(void) printf(gettext("Can't stat %s\n"), devstr);
102 		exitstat = 34;
103 		return (0);
104 	}
105 	/*
106 	 * A mount point is specified. But the mount point doesn't
107 	 * match entries in the /etc/vfstab.
108 	 * Search mnttab, because if the fs is error locked, it is
109 	 * allowed to be fsck'd while mounted.
110 	 */
111 	if ((statb.st_mode & S_IFMT) == S_IFDIR) {
112 		(void) printf(gettext("%s is not a block or "
113 			"character device\n"), dev);
114 		return (0);
115 	}
116 
117 	if ((statb.st_mode & S_IFMT) == S_IFBLK) {
118 		if (rootdev == statb.st_rdev)
119 			hotroot++;
120 		else if (ustat(statb.st_rdev, &ustatb) == 0) {
121 			(void) printf(gettext("%s is a mounted file system, "
122 				"ignored\n"), dev);
123 			exitstat = 33;
124 			return (0);
125 		}
126 	}
127 	if ((statb.st_mode & S_IFMT) == S_IFDIR) {
128 		FILE *vfstab;
129 		struct vfstab vfsbuf;
130 		/*
131 		 * Check vfstab for a mount point with this name
132 		 */
133 		if ((vfstab = fopen(VFSTAB, "r")) == NULL) {
134 			errexit(gettext("Can't open checklist file: %s\n"),
135 				VFSTAB);
136 		}
137 		while (getvfsent(vfstab, &vfsbuf) == NULL) {
138 			if (strcmp(devstr, vfsbuf.vfs_mountp) == 0) {
139 				if (strcmp(vfsbuf.vfs_fstype,
140 				    MNTTYPE_UDFS) != 0) {
141 					/*
142 					 * found the entry but it is not a
143 					 * udfs filesystem, don't check it
144 					 */
145 					(void) fclose(vfstab);
146 					return (0);
147 				}
148 				(void) strcpy(devstr, vfsbuf.vfs_special);
149 				if (rflag) {
150 					raw = rawname(
151 					    unrawname(vfsbuf.vfs_special));
152 					(void) strcpy(devstr, raw);
153 				}
154 				goto restat;
155 			}
156 		}
157 		(void) fclose(vfstab);
158 
159 	} else if (((statb.st_mode & S_IFMT) != S_IFBLK) &&
160 	    ((statb.st_mode & S_IFMT) != S_IFCHR)) {
161 		if (preen)
162 			pwarn(gettext("file is not a block or "
163 				"character device.\n"));
164 		else if (reply(gettext("file is not a block or "
165 				"character device; OK"))
166 		    == 0)
167 			return (0);
168 		/*
169 		 * To fsck regular files (fs images)
170 		 * we need to clear the rflag since
171 		 * regular files don't have raw names.  --CW
172 		 */
173 		rflag = 0;
174 	}
175 
176 	if (mounted(devstr)) {
177 		if (rflag)
178 			mountedfs++;
179 		else {
180 			(void) printf(gettext("%s is mounted, fsck on BLOCK "
181 				"device ignored\n"), devstr);
182 			exit(33);
183 		}
184 		sync();	/* call sync, only when devstr's mounted */
185 	}
186 	if (rflag) {
187 		char blockname[MAXPATHLEN];
188 		/*
189 		 * For root device check, must check
190 		 * block devices.
191 		 */
192 		(void) strcpy(blockname, devstr);
193 		if (stat(unrawname(blockname), &statb) < 0) {
194 			(void) printf(gettext("Can't stat %s\n"), blockname);
195 			exitstat = 34;
196 			return (0);
197 		}
198 	}
199 	if (rootdev == statb.st_rdev)
200 		hotroot++;
201 	if ((fsreadfd = open(devstr, O_RDONLY)) < 0) {
202 		(void) printf(gettext("Can't open %s\n"), devstr);
203 		exitstat = 34;
204 		return (0);
205 	}
206 	if (preen == 0 || debug != 0)
207 		(void) printf("** %s", devstr);
208 
209 	if (nflag || (fswritefd = open(devstr, O_WRONLY)) < 0) {
210 		fswritefd = -1;
211 		if (preen && !debug)
212 			pfatal(gettext("(NO WRITE ACCESS)\n"));
213 			(void) printf(gettext(" (NO WRITE)"));
214 	}
215 	if (preen == 0)
216 		(void) printf("\n");
217 	if (debug && (hotroot || mountedfs)) {
218 		(void) printf("** %s", devstr);
219 		if (hotroot)
220 			(void) printf(" is root fs%s",
221 				mountedfs? " and": "");
222 		if (mountedfs)
223 			(void) printf(" is mounted");
224 
225 		(void) printf(".\n");
226 	}
227 	fsmodified = 0;
228 	if (readvolseq(1) == 0)
229 		return (0);
230 	if (fflag == 0 && preen &&
231 		lvintp->lvid_int_type == LVI_CLOSE) {
232 		iscorrupt = 0;
233 		printclean();
234 		return (0);
235 	}
236 	listmax = FEGROW;
237 	inphash = (struct fileinfo **)calloc(FEGROW,
238 			sizeof (struct fileinfo *));
239 	inphead = (struct fileinfo *)calloc(FEGROW + 1,
240 			sizeof (struct fileinfo));
241 	if (inphead == NULL || inphash == NULL) {
242 		(void) printf(gettext("cannot alloc %ld bytes for inphead\n"),
243 			listmax * sizeof (struct fileinfo));
244 		goto badsb;
245 	}
246 	inpnext = inphead;
247 	inplast = &inphead[listmax];
248 
249 	bufinit();
250 	return (devstr);
251 
252 badsb:
253 	ckfini();
254 	exitstat = 39;
255 	return (0);
256 }
257 
258 static int
259 check_pri_vol_desc(struct tag *tp)
260 {
261 	pvolp = (struct pri_vol_desc *)tp;
262 	return (0);
263 }
264 
265 static int
266 check_avdp(struct tag *tp)
267 {
268 	avdp = (struct anch_vol_desc_ptr *)tp;
269 	return (0);
270 }
271 
272 static int
273 check_vdp(struct tag *tp)
274 {
275 	volp = (struct vdp_desc *)tp;
276 	return (0);
277 }
278 
279 static int
280 check_iuvd(struct tag *tp)
281 {
282 	iudp = (struct iuvd_desc *)tp;
283 	return (0);
284 }
285 
286 static int
287 check_part_desc(struct tag *tp)
288 {
289 	partp = (struct part_desc *)tp;
290 	/* LINTED */
291 	pheadp = (struct phdr_desc *)&partp->pd_pc_use;
292 	part_start = partp->pd_part_start;
293 	part_len = partp->pd_part_length;
294 	if (debug)
295 		(void) printf("partition start %x len %x\n", part_start,
296 			part_len);
297 	return (0);
298 }
299 
300 static int
301 check_log_desc(struct tag *tp)
302 {
303 	logvp = (struct log_vol_desc *)tp;
304 	return (0);
305 }
306 
307 static int
308 check_unall_desc(struct tag *tp)
309 {
310 	unallp = (struct unall_desc *)tp;
311 	return (0);
312 }
313 
314 /* ARGSUSED */
315 static int
316 check_term_desc(struct tag *tp)
317 {
318 	return (0);
319 }
320 
321 static int
322 check_lvint(struct tag *tp)
323 {
324 	/* LINTED */
325 	lvintp = (struct log_vol_int_desc *)tp;
326 	return (0);
327 }
328 
329 void
330 dump16(char *cp, char *nl)
331 {
332 	int i;
333 	long *ptr;
334 
335 
336 	for (i = 0; i < 16; i += 4) {
337 		/* LINTED */
338 		ptr = (long *)(cp + i);
339 		(void) printf("%08lx ", *ptr);
340 	}
341 	(void) printf(nl);
342 }
343 
344 /*
345  * Read in the super block and its summary info.
346  */
347 /* ARGSUSED */
348 static int
349 readvolseq(int32_t listerr)
350 {
351 	struct tag *tp;
352 	long_ad_t *lap;
353 	struct anch_vol_desc_ptr *avp;
354 	uint8_t *cp, *end;
355 	daddr_t nextblock;
356 	int err;
357 	long	freelen;
358 	daddr_t avdp;
359 
360 	disk_size = get_last_block();
361 	if (debug)
362 		(void) printf("Disk partition size: %x\n", disk_size);
363 
364 	/* LINTED */
365 	avp = (struct anch_vol_desc_ptr *)avdbuf;
366 	tp = &avp->avd_tag;
367 	for (fsbsize = 512; fsbsize <= MAXBSIZE; fsbsize <<= 1) {
368 		avdp = FIRSTAVDP * fsbsize / DEV_BSIZE;
369 		if (bread(fsreadfd, avdbuf, avdp, fsbsize) != 0)
370 			return (0);
371 		err = verifytag(tp, FIRSTAVDP, tp, UD_ANCH_VOL_DESC);
372 		if (debug)
373 			(void) printf("bsize %ld tp->tag %d, %s\n", fsbsize,
374 				tp->tag_id, tagerrs[err]);
375 		if (err == 0)
376 			break;
377 	}
378 	if (fsbsize > MAXBSIZE)
379 		errexit(gettext("Can't find anchor volume descriptor\n"));
380 	secsize = fsbsize;
381 	if (debug)
382 		(void) printf("fsbsize = %ld\n", fsbsize);
383 	main_vdbuf = malloc(avp->avd_main_vdse.ext_len);
384 	res_vdbuf = malloc(avp->avd_res_vdse.ext_len);
385 	if (main_vdbuf == NULL || res_vdbuf == NULL)
386 		errexit("cannot allocate space for volume sequences\n");
387 	if (debug)
388 		(void) printf("reading volume sequences "
389 			"(%d bytes at %x and %x)\n",
390 			avp->avd_main_vdse.ext_len, avp->avd_main_vdse.ext_loc,
391 			avp->avd_res_vdse.ext_loc);
392 	if (bread(fsreadfd, main_vdbuf, fsbtodb(avp->avd_main_vdse.ext_loc),
393 		avp->avd_main_vdse.ext_len) != 0)
394 		return (0);
395 	if (bread(fsreadfd, res_vdbuf, fsbtodb(avp->avd_res_vdse.ext_loc),
396 		avp->avd_res_vdse.ext_len) != 0)
397 		return (0);
398 	end = (uint8_t *)main_vdbuf + avp->avd_main_vdse.ext_len;
399 	nextblock = avp->avd_main_vdse.ext_loc;
400 	for (cp = (uint8_t *)main_vdbuf; cp < end; cp += fsbsize, nextblock++) {
401 		/* LINTED */
402 		tp = (struct tag *)cp;
403 		err = verifytag(tp, nextblock, tp, 0);
404 		if (debug) {
405 			dump16((char *)cp, "");
406 			(void) printf("blk %lx err %s tag %d\n", nextblock,
407 				tagerrs[err], tp->tag_id);
408 		}
409 		if (err == 0) {
410 			if (serialnum >= 0 && tp->tag_sno != serialnum) {
411 				(void) printf(gettext("serial number mismatch "
412 					"tag type %d, block %lx\n"), tp->tag_id,
413 					nextblock);
414 				continue;
415 			}
416 			switch (tp->tag_id) {
417 			case UD_PRI_VOL_DESC:
418 				serialnum = tp->tag_sno;
419 				if (debug) {
420 					(void) printf("serial number = %d\n",
421 						serialnum);
422 				}
423 				err = check_pri_vol_desc(tp);
424 				break;
425 			case UD_ANCH_VOL_DESC:
426 				err = check_avdp(tp);
427 				break;
428 			case UD_VOL_DESC_PTR:
429 				err = check_vdp(tp);
430 				break;
431 			case UD_IMPL_USE_DESC:
432 				err = check_iuvd(tp);
433 				break;
434 			case UD_PART_DESC:
435 				err = check_part_desc(tp);
436 				break;
437 			case UD_LOG_VOL_DESC:
438 				err = check_log_desc(tp);
439 				break;
440 			case UD_UNALL_SPA_DESC:
441 				err = check_unall_desc(tp);
442 				break;
443 			case UD_TERM_DESC:
444 				err = check_term_desc(tp);
445 				goto done;
446 				break;
447 			case UD_LOG_VOL_INT:
448 				err = check_lvint(tp);
449 				break;
450 			default:
451 				(void) printf(gettext("Invalid volume "
452 					"sequence tag %d\n"), tp->tag_id);
453 			}
454 		} else {
455 			(void) printf(gettext("Volume sequence tag error %s\n"),
456 				tagerrs[err]);
457 		}
458 	}
459 done:
460 	if (!partp || !logvp) {
461 		(void) printf(gettext("Missing partition header or"
462 			" logical volume descriptor\n"));
463 		return (0);
464 	}
465 
466 	/* Get the logical volume integrity descriptor */
467 	lvintblock = logvp->lvd_int_seq_ext.ext_loc;
468 	lvintlen = logvp->lvd_int_seq_ext.ext_len;
469 	lvintp = (struct log_vol_int_desc *)malloc(lvintlen);
470 	if (debug)
471 		(void) printf("Logvolint at %x for %d bytes\n", lvintblock,
472 			lvintlen);
473 	if (lvintp == NULL) {
474 		(void) printf(gettext("Can't allocate space for logical"
475 			" volume integrity sequence\n"));
476 		return (0);
477 	}
478 	if (bread(fsreadfd, (char *)lvintp,
479 			fsbtodb(lvintblock), lvintlen) != 0) {
480 		return (0);
481 	}
482 	err = verifytag(&lvintp->lvid_tag, lvintblock, &lvintp->lvid_tag,
483 		UD_LOG_VOL_INT);
484 	if (debug) {
485 		dump16((char *)lvintp, "\n");
486 	}
487 	if (err) {
488 		(void) printf(gettext("Log_vol_int tag error: %s, tag = %d\n"),
489 			tagerrs[err], lvintp->lvid_tag.tag_id);
490 		return (0);
491 	}
492 
493 	/* Get pointer to implementation use area */
494 	lviup = (struct lvid_iu *)&lvintp->lvid_fst[lvintp->lvid_npart*2];
495 	if (debug) {
496 		(void) printf("free space %d total %d ", lvintp->lvid_fst[0],
497 			lvintp->lvid_fst[1]);
498 	(void) printf(gettext("nfiles %d ndirs %d\n"), lviup->lvidiu_nfiles,
499 			lviup->lvidiu_ndirs);
500 	}
501 
502 	/* Set up free block map and read in the existing free space map */
503 	freelen = pheadp->phdr_usb.sad_ext_len;
504 	if (freelen == 0) {
505 		(void) printf(gettext("No partition free map\n"));
506 	}
507 	part_bmp_bytes = (part_len + NBBY - 1) / NBBY;
508 	busymap = calloc((unsigned)part_bmp_bytes, sizeof (char));
509 	if (busymap == NULL) {
510 		(void) printf(gettext("Can't allocate free block bitmap\n"));
511 		return (0);
512 	}
513 	if (freelen) {
514 		part_bmp_sectors =
515 			(part_bmp_bytes + SPACEMAP_OFF + secsize - 1) /
516 			secsize;
517 		part_bmp_loc = pheadp->phdr_usb.sad_ext_loc + part_start;
518 
519 		/* Mark the partition map blocks busy */
520 		markbusy(pheadp->phdr_usb.sad_ext_loc,
521 			part_bmp_sectors * secsize);
522 
523 		spacep = (struct space_bmap_desc *)
524 			malloc(secsize*part_bmp_sectors);
525 		if (spacep == NULL) {
526 			(void) printf(gettext("Can't allocate partition "
527 				"map\n"));
528 			return (0);
529 		}
530 		if (bread(fsreadfd, (char *)spacep, fsbtodb(part_bmp_loc),
531 			part_bmp_sectors * secsize) != 0)
532 			return (0);
533 		cp = (uint8_t *)spacep;
534 		err = verifytag(&spacep->sbd_tag, pheadp->phdr_usb.sad_ext_loc,
535 			&spacep->sbd_tag, UD_SPA_BMAP_DESC);
536 		if (debug) {
537 			dump16((char *)cp, "");
538 			(void) printf("blk %x err %s tag %d\n", part_bmp_loc,
539 				tagerrs[err], spacep->sbd_tag.tag_id);
540 		}
541 		freemap = (char *)cp + SPACEMAP_OFF;
542 		if (debug)
543 			(void) printf("err %s tag %x space bitmap at %x"
544 				" length %d nbits %d nbytes %d\n",
545 				tagerrs[err], spacep->sbd_tag.tag_id,
546 				part_bmp_loc, part_bmp_sectors,
547 				spacep->sbd_nbits, spacep->sbd_nbytes);
548 		if (err) {
549 			(void) printf(gettext("Space bitmap tag error, %s, "
550 				"tag = %d\n"),
551 				tagerrs[err], spacep->sbd_tag.tag_id);
552 			return (0);
553 		}
554 	}
555 
556 	/* Get the fileset descriptor */
557 	lap = (long_ad_t *)&logvp->lvd_lvcu;
558 	filesetblock = lap->lad_ext_loc;
559 	filesetlen = lap->lad_ext_len;
560 	markbusy(filesetblock, filesetlen);
561 	if (debug)
562 		(void) printf("Fileset descriptor at %x for %d bytes\n",
563 			filesetblock, filesetlen);
564 	if (!filesetlen) {
565 		(void) printf(gettext("No file set descriptor found\n"));
566 		return (0);
567 	}
568 	fileset = (struct file_set_desc *)malloc(filesetlen);
569 	if (fileset == NULL) {
570 		(void) printf(gettext("Unable to allocate fileset\n"));
571 		return (0);
572 	}
573 	if (bread(fsreadfd, (char *)fileset, fsbtodb(filesetblock + part_start),
574 		filesetlen) != 0) {
575 		return (0);
576 	}
577 	err = verifytag(&fileset->fsd_tag, filesetblock, &fileset->fsd_tag,
578 		UD_FILE_SET_DESC);
579 	if (err) {
580 		(void) printf(gettext("Fileset tag error, tag = %d, %s\n"),
581 			fileset->fsd_tag.tag_id, tagerrs[err]);
582 		return (0);
583 	}
584 
585 	/* Get the address of the root file entry */
586 	lap = (long_ad_t *)&fileset->fsd_root_icb;
587 	rootblock = lap->lad_ext_loc;
588 	rootlen = lap->lad_ext_len;
589 	if (debug)
590 		(void) printf("Root at %x for %d bytes\n", rootblock, rootlen);
591 
592 	havesb = 1;
593 	return (1);
594 }
595 
596 uint32_t
597 get_last_block()
598 {
599 	struct vtoc vtoc;
600 	struct dk_cinfo dki_info;
601 
602 	if (ioctl(fsreadfd, DKIOCGVTOC, (intptr_t)&vtoc) != 0) {
603 		(void) fprintf(stderr, gettext("Unable to read VTOC\n"));
604 		return (0);
605 	}
606 
607 	if (vtoc.v_sanity != VTOC_SANE) {
608 		(void) fprintf(stderr, gettext("Vtoc.v_sanity != VTOC_SANE\n"));
609 		return (0);
610 	}
611 
612 	if (ioctl(fsreadfd, DKIOCINFO, (intptr_t)&dki_info) != 0) {
613 		(void) fprintf(stderr,
614 		    gettext("Could not get the slice information\n"));
615 		return (0);
616 	}
617 
618 	if (dki_info.dki_partition > V_NUMPAR) {
619 		(void) fprintf(stderr,
620 		    gettext("dki_info.dki_partition > V_NUMPAR\n"));
621 		return (0);
622 	}
623 
624 	return ((uint32_t)vtoc.v_part[dki_info.dki_partition].p_size);
625 }
626