1/*
2 * Copyright (c) 1981, 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#if 0
31#ifndef lint
32static const char copyright[] =
33"@(#) Copyright (c) 1981, 1983, 1993\n\
34	The Regents of the University of California.  All rights reserved.\n";
35#endif /* not lint */
36
37#ifndef lint
38static const char sccsid[] = "@(#)badsect.c	8.1 (Berkeley) 6/5/93";
39#endif
40#endif
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD$");
43
44/*
45 * badsect
46 *
47 * Badsect takes a list of file-system relative sector numbers
48 * and makes files containing the blocks of which these sectors are a part.
49 * It can be used to contain sectors which have problems if these sectors
50 * are not part of the bad file for the pack (see bad144).  For instance,
51 * this program can be used if the driver for the file system in question
52 * does not support bad block forwarding.
53 */
54#include <sys/param.h>
55#include <sys/stat.h>
56#include <sys/disklabel.h>
57
58#include <ufs/ufs/dinode.h>
59#include <ufs/ffs/fs.h>
60
61#include <err.h>
62#include <errno.h>
63#include <dirent.h>
64#include <fcntl.h>
65#include <libufs.h>
66#include <paths.h>
67#include <stdio.h>
68#include <stdlib.h>
69#include <string.h>
70#include <unistd.h>
71
72#define sblock	disk.d_fs
73#define	acg	disk.d_cg
74static struct	uufsd disk;
75static struct	fs *fs = &sblock;
76static int	errs;
77
78int	chkuse(daddr_t, int);
79
80static void
81usage(void)
82{
83	fprintf(stderr, "usage: badsect bbdir blkno ...\n");
84	exit(1);
85}
86
87int
88main(int argc, char *argv[])
89{
90	daddr_t diskbn;
91	daddr_t number;
92	struct stat stbuf, devstat;
93	struct dirent *dp;
94	DIR *dirp;
95	char name[2 * MAXPATHLEN];
96	char *name_dir_end;
97
98	if (argc < 3)
99		usage();
100	if (chdir(argv[1]) < 0 || stat(".", &stbuf) < 0)
101		err(2, "%s", argv[1]);
102	strcpy(name, _PATH_DEV);
103	if ((dirp = opendir(name)) == NULL)
104		err(3, "%s", name);
105	name_dir_end = name + strlen(name);
106	while ((dp = readdir(dirp)) != NULL) {
107		strcpy(name_dir_end, dp->d_name);
108		if (lstat(name, &devstat) < 0)
109			err(4, "%s", name);
110		if (stbuf.st_dev == devstat.st_rdev &&
111		    (devstat.st_mode & IFMT) == IFCHR)
112			break;
113	}
114	closedir(dirp);
115	if (dp == NULL) {
116		printf("Cannot find dev 0%lo corresponding to %s\n",
117		    (u_long)stbuf.st_rdev, argv[1]);
118		exit(5);
119	}
120	if (ufs_disk_fillout(&disk, name) == -1) {
121		if (disk.d_error != NULL)
122			errx(6, "%s: %s", name, disk.d_error);
123		else
124			err(7, "%s", name);
125	}
126	for (argc -= 2, argv += 2; argc > 0; argc--, argv++) {
127		number = strtol(*argv, NULL, 0);
128		if (errno == EINVAL || errno == ERANGE)
129			err(8, "%s", *argv);
130		if (chkuse(number, 1))
131			continue;
132		/*
133		 * Print a warning if converting the block number to a dev_t
134		 * will truncate it.  badsect was not very useful in versions
135		 * of BSD before 4.4 because dev_t was 16 bits and another
136		 * bit was lost by bogus sign extensions.
137		 */
138		diskbn = dbtofsb(fs, number);
139		if ((dev_t)diskbn != diskbn) {
140			printf("sector %ld cannot be represented as a dev_t\n",
141			    (long)number);
142			errs++;
143		}
144		else if (mknod(*argv, IFMT|0600, (dev_t)diskbn) < 0) {
145			warn("%s", *argv);
146			errs++;
147		}
148	}
149	ufs_disk_close(&disk);
150	printf("Don't forget to run ``fsck %s''\n", name);
151	exit(errs);
152}
153
154int
155chkuse(daddr_t blkno, int cnt)
156{
157	int cg;
158	daddr_t fsbn, bn;
159
160	fsbn = dbtofsb(fs, blkno);
161	if ((unsigned)(fsbn+cnt) > fs->fs_size) {
162		printf("block %ld out of range of file system\n", (long)blkno);
163		return (1);
164	}
165	cg = dtog(fs, fsbn);
166	if (fsbn < cgdmin(fs, cg)) {
167		if (cg == 0 || (fsbn+cnt) > cgsblock(fs, cg)) {
168			printf("block %ld in non-data area: cannot attach\n",
169			    (long)blkno);
170			return (1);
171		}
172	} else {
173		if ((fsbn+cnt) > cgbase(fs, cg+1)) {
174			printf("block %ld in non-data area: cannot attach\n",
175			    (long)blkno);
176			return (1);
177		}
178	}
179	if (cgread1(&disk, cg) != 1) {
180		fprintf(stderr, "cg %d: could not be read\n", cg);
181		errs++;
182		return (1);
183	}
184	if (!cg_chkmagic(&acg)) {
185		fprintf(stderr, "cg %d: bad magic number\n", cg);
186		errs++;
187		return (1);
188	}
189	bn = dtogd(fs, fsbn);
190	if (isclr(cg_blksfree(&acg), bn))
191		printf("Warning: sector %ld is in use\n", (long)blkno);
192	return (0);
193}
194