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