1*49f4cf4bSdholland /* $NetBSD: preen.c,v 1.32 2015/06/21 04:01:40 dholland Exp $ */
2fdf6ea6cSchristos
3fdf6ea6cSchristos /*
4fdf6ea6cSchristos * Copyright (c) 1990, 1993
5fdf6ea6cSchristos * The Regents of the University of California. All rights reserved.
6fdf6ea6cSchristos *
7fdf6ea6cSchristos * Redistribution and use in source and binary forms, with or without
8fdf6ea6cSchristos * modification, are permitted provided that the following conditions
9fdf6ea6cSchristos * are met:
10fdf6ea6cSchristos * 1. Redistributions of source code must retain the above copyright
11fdf6ea6cSchristos * notice, this list of conditions and the following disclaimer.
12fdf6ea6cSchristos * 2. Redistributions in binary form must reproduce the above copyright
13fdf6ea6cSchristos * notice, this list of conditions and the following disclaimer in the
14fdf6ea6cSchristos * documentation and/or other materials provided with the distribution.
15bf07c871Sagc * 3. Neither the name of the University nor the names of its contributors
16fdf6ea6cSchristos * may be used to endorse or promote products derived from this software
17fdf6ea6cSchristos * without specific prior written permission.
18fdf6ea6cSchristos *
19fdf6ea6cSchristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20fdf6ea6cSchristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21fdf6ea6cSchristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22fdf6ea6cSchristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23fdf6ea6cSchristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24fdf6ea6cSchristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25fdf6ea6cSchristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26fdf6ea6cSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27fdf6ea6cSchristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28fdf6ea6cSchristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29fdf6ea6cSchristos * SUCH DAMAGE.
30fdf6ea6cSchristos */
31fdf6ea6cSchristos
3226ba0ba0Slukem #include <sys/cdefs.h>
33fdf6ea6cSchristos #ifndef lint
34fdf6ea6cSchristos #if 0
35d3b61af7Slukem static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95";
36fdf6ea6cSchristos #else
37*49f4cf4bSdholland __RCSID("$NetBSD: preen.c,v 1.32 2015/06/21 04:01:40 dholland Exp $");
38fdf6ea6cSchristos #endif
39fdf6ea6cSchristos #endif /* not lint */
40fdf6ea6cSchristos
41*49f4cf4bSdholland /*
42*49f4cf4bSdholland * used by sbin/fsck
43*49f4cf4bSdholland * used by usr.sbin/quotacheck
44*49f4cf4bSdholland */
45*49f4cf4bSdholland
46fdf6ea6cSchristos #include <sys/param.h>
47fdf6ea6cSchristos #include <sys/stat.h>
48fdf6ea6cSchristos #include <sys/wait.h>
49fdf6ea6cSchristos #include <sys/queue.h>
5009e8908eSchristos #include <sys/disk.h>
5109e8908eSchristos #include <sys/ioctl.h>
52fdf6ea6cSchristos
53d3b61af7Slukem #include <err.h>
54d3b61af7Slukem #include <ctype.h>
55fdf6ea6cSchristos #include <fstab.h>
5609e8908eSchristos #include <fcntl.h>
57fdf6ea6cSchristos #include <string.h>
58fdf6ea6cSchristos #include <stdio.h>
59fdf6ea6cSchristos #include <stdlib.h>
60fdf6ea6cSchristos #include <unistd.h>
612a1607d0Schristos #include <util.h>
62fdf6ea6cSchristos
637dfca760Schristos #include "fsutil.h"
64742b48d5Schristos #include "exitvalues.h"
65fdf6ea6cSchristos
66fdf6ea6cSchristos struct partentry {
67fdf6ea6cSchristos TAILQ_ENTRY(partentry) p_entries;
687dfca760Schristos char *p_devname; /* device name */
697dfca760Schristos char *p_mntpt; /* mount point */
70fdf6ea6cSchristos char *p_type; /* file system type */
71ef1bd36bSchristos void *p_auxarg; /* auxiliary argument */
72fdf6ea6cSchristos };
73fdf6ea6cSchristos
74fdf6ea6cSchristos TAILQ_HEAD(part, partentry) badh;
75fdf6ea6cSchristos
76fdf6ea6cSchristos struct diskentry {
77fdf6ea6cSchristos TAILQ_ENTRY(diskentry) d_entries;
78fdf6ea6cSchristos char *d_name; /* disk base name */
79fdf6ea6cSchristos TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */
80fdf6ea6cSchristos int d_pid; /* 0 or pid of fsck proc */
81fdf6ea6cSchristos };
82fdf6ea6cSchristos
8309e8908eSchristos TAILQ_HEAD(diskinfo, diskentry) diskh;
84fdf6ea6cSchristos
85fdf6ea6cSchristos static int nrun = 0, ndisks = 0;
86fdf6ea6cSchristos
87f97f5096Slukem static struct diskentry *finddisk(const char *);
88f97f5096Slukem static void addpart(const char *, const char *, const char *, void *);
89f97f5096Slukem static int startdisk(struct diskentry *,
90f97f5096Slukem int (*)(const char *, const char *, const char *, void *, pid_t *));
91f97f5096Slukem static void printpart(void);
92fdf6ea6cSchristos
93fdf6ea6cSchristos int
checkfstab(int flags,int maxrun,void * (* docheck)(struct fstab *),int (* checkit)(const char *,const char *,const char *,void *,pid_t *))94f97f5096Slukem checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *),
95f97f5096Slukem int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
96fdf6ea6cSchristos {
97fdf6ea6cSchristos struct fstab *fs;
98fdf6ea6cSchristos struct diskentry *d, *nextdisk;
99fdf6ea6cSchristos struct partentry *p;
100fdf6ea6cSchristos int ret, pid, retcode, passno, sumstatus, status;
101ef1bd36bSchristos void *auxarg;
102b93acf4aSmycroft const char *name;
103742b48d5Schristos int error = FSCK_EXIT_OK;
104fdf6ea6cSchristos
105fdf6ea6cSchristos TAILQ_INIT(&badh);
106fdf6ea6cSchristos TAILQ_INIT(&diskh);
107fdf6ea6cSchristos
108742b48d5Schristos sumstatus = FSCK_EXIT_OK;
109fdf6ea6cSchristos
110fdf6ea6cSchristos for (passno = 1; passno <= 2; passno++) {
111fdf6ea6cSchristos if (setfsent() == 0) {
1126742cb18Sgrant warnx("Can't open checklist file: %s", _PATH_FSTAB);
113742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
114fdf6ea6cSchristos }
115fdf6ea6cSchristos while ((fs = getfsent()) != 0) {
1165727faddSchristos char buf[MAXPATHLEN];
1175727faddSchristos const char *fsspec;
118ef1bd36bSchristos if ((auxarg = (*docheck)(fs)) == NULL)
119fdf6ea6cSchristos continue;
1205727faddSchristos fsspec = getfsspecname(buf, sizeof(buf), fs->fs_spec);
1215727faddSchristos if (fsspec == NULL) {
1225727faddSchristos warn("%s", buf);
1235727faddSchristos return FSCK_EXIT_CHECK_FAILED;
1245727faddSchristos }
1255727faddSchristos name = blockcheck(fsspec);
1267dfca760Schristos if (flags & CHECK_DEBUG)
127fdf6ea6cSchristos printf("pass %d, name %s\n", passno, name);
128fdf6ea6cSchristos
1297dfca760Schristos if ((flags & CHECK_PREEN) == 0 ||
1307dfca760Schristos (passno == 1 && fs->fs_passno == 1)) {
131fdf6ea6cSchristos if (name == NULL) {
1327dfca760Schristos if (flags & CHECK_PREEN)
133742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
134fdf6ea6cSchristos else
135fdf6ea6cSchristos continue;
136fdf6ea6cSchristos }
137ef1bd36bSchristos sumstatus = (*checkit)(fs->fs_vfstype,
138ef1bd36bSchristos name, fs->fs_file, auxarg, NULL);
139fdf6ea6cSchristos
1405f101a47Schristos if (sumstatus) {
1415f101a47Schristos if ((flags & CHECK_NOFIX) == 0)
142742b48d5Schristos return sumstatus;
143742b48d5Schristos else if (error < sumstatus)
144742b48d5Schristos error = sumstatus;
1455f101a47Schristos }
146fdf6ea6cSchristos } else if (passno == 2 && fs->fs_passno > 1) {
147fdf6ea6cSchristos if (name == NULL) {
148fdf6ea6cSchristos (void) fprintf(stderr,
1495727faddSchristos "BAD DISK NAME %s\n", fsspec);
150742b48d5Schristos sumstatus = FSCK_EXIT_CHECK_FAILED;
151fdf6ea6cSchristos continue;
152fdf6ea6cSchristos }
153ef1bd36bSchristos addpart(fs->fs_vfstype, name, fs->fs_file,
154ef1bd36bSchristos auxarg);
155fdf6ea6cSchristos }
156fdf6ea6cSchristos }
1577dfca760Schristos if ((flags & CHECK_PREEN) == 0)
1585f101a47Schristos return error;
159fdf6ea6cSchristos }
160fdf6ea6cSchristos
1617dfca760Schristos if (flags & CHECK_DEBUG)
162fdf6ea6cSchristos printpart();
163fdf6ea6cSchristos
1647dfca760Schristos if (flags & CHECK_PREEN) {
165fdf6ea6cSchristos if (maxrun == 0)
166fdf6ea6cSchristos maxrun = ndisks;
167fdf6ea6cSchristos if (maxrun > ndisks)
168fdf6ea6cSchristos maxrun = ndisks;
169dacdbbf6Slukem nextdisk = TAILQ_FIRST(&diskh);
170fdf6ea6cSchristos for (passno = 0; passno < maxrun; ++passno) {
1715f101a47Schristos if ((ret = startdisk(nextdisk, checkit)) != 0) {
1725f101a47Schristos if ((flags & CHECK_NOFIX) == 0)
173fdf6ea6cSchristos return ret;
174742b48d5Schristos else if (error < ret)
175742b48d5Schristos error = ret;
1765f101a47Schristos }
1779e2e804cSlukem nextdisk = TAILQ_NEXT(nextdisk, d_entries);
178fdf6ea6cSchristos }
179fdf6ea6cSchristos
180fdf6ea6cSchristos while ((pid = wait(&status)) != -1) {
181dacdbbf6Slukem TAILQ_FOREACH(d, &diskh, d_entries)
182fdf6ea6cSchristos if (d->d_pid == pid)
183fdf6ea6cSchristos break;
184fdf6ea6cSchristos
185fdf6ea6cSchristos if (d == NULL) {
1866742cb18Sgrant warnx("Unknown pid %d", pid);
187fdf6ea6cSchristos continue;
188fdf6ea6cSchristos }
189fdf6ea6cSchristos
190fdf6ea6cSchristos
191fdf6ea6cSchristos if (WIFEXITED(status))
192fdf6ea6cSchristos retcode = WEXITSTATUS(status);
193fdf6ea6cSchristos else
194fdf6ea6cSchristos retcode = 0;
195fdf6ea6cSchristos
196dacdbbf6Slukem p = TAILQ_FIRST(&d->d_part);
197fdf6ea6cSchristos
1987dfca760Schristos if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
19926ba0ba0Slukem (void) printf("done %s: %s (%s) = 0x%x\n",
2007dfca760Schristos p->p_type, p->p_devname, p->p_mntpt,
2017dfca760Schristos status);
202fdf6ea6cSchristos
203fdf6ea6cSchristos if (WIFSIGNALED(status)) {
204fdf6ea6cSchristos (void) fprintf(stderr,
2057dfca760Schristos "%s: %s (%s): EXITED WITH SIGNAL %d\n",
2067dfca760Schristos p->p_type, p->p_devname, p->p_mntpt,
2077dfca760Schristos WTERMSIG(status));
208742b48d5Schristos retcode = FSCK_EXIT_SIGNALLED;
209fdf6ea6cSchristos }
210fdf6ea6cSchristos
211fdf6ea6cSchristos TAILQ_REMOVE(&d->d_part, p, p_entries);
212fdf6ea6cSchristos
213fdf6ea6cSchristos if (retcode != 0) {
214fdf6ea6cSchristos TAILQ_INSERT_TAIL(&badh, p, p_entries);
215fdf6ea6cSchristos sumstatus |= retcode;
216fdf6ea6cSchristos } else {
217fdf6ea6cSchristos free(p->p_type);
2187dfca760Schristos free(p->p_devname);
219fdf6ea6cSchristos free(p);
220fdf6ea6cSchristos }
221fdf6ea6cSchristos d->d_pid = 0;
222fdf6ea6cSchristos nrun--;
223fdf6ea6cSchristos
224dacdbbf6Slukem if (TAILQ_FIRST(&d->d_part) == NULL)
225fdf6ea6cSchristos ndisks--;
226fdf6ea6cSchristos
227fdf6ea6cSchristos if (nextdisk == NULL) {
228dacdbbf6Slukem if (TAILQ_FIRST(&d->d_part) != NULL) {
229ef1bd36bSchristos if ((ret = startdisk(d, checkit)) != 0)
2305f101a47Schristos {
2315f101a47Schristos if ((flags & CHECK_NOFIX) == 0)
232fdf6ea6cSchristos return ret;
233742b48d5Schristos else if (error < ret)
234742b48d5Schristos error = ret;
2355f101a47Schristos }
236fdf6ea6cSchristos }
237fdf6ea6cSchristos } else if (nrun < maxrun && nrun < ndisks) {
238fdf6ea6cSchristos for ( ;; ) {
239dacdbbf6Slukem nextdisk = TAILQ_NEXT(nextdisk,
240dacdbbf6Slukem d_entries);
241fdf6ea6cSchristos if (nextdisk == NULL)
242dacdbbf6Slukem nextdisk = TAILQ_FIRST(&diskh);
243dacdbbf6Slukem if (TAILQ_FIRST(&nextdisk->d_part)
244dacdbbf6Slukem != NULL && nextdisk->d_pid == 0)
245fdf6ea6cSchristos break;
246fdf6ea6cSchristos }
247ef1bd36bSchristos if ((ret = startdisk(nextdisk, checkit)) != 0)
2485f101a47Schristos {
2495f101a47Schristos if ((flags & CHECK_NOFIX) == 0)
250fdf6ea6cSchristos return ret;
251742b48d5Schristos else if (error < ret)
252742b48d5Schristos error = ret;
2535f101a47Schristos }
254fdf6ea6cSchristos }
255fdf6ea6cSchristos }
256fdf6ea6cSchristos }
257fdf6ea6cSchristos if (sumstatus) {
258dacdbbf6Slukem p = TAILQ_FIRST(&badh);
259fdf6ea6cSchristos if (p == NULL)
260742b48d5Schristos return sumstatus;
261fdf6ea6cSchristos
262fdf6ea6cSchristos (void) fprintf(stderr,
263fdf6ea6cSchristos "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
2649e2e804cSlukem TAILQ_NEXT(p, p_entries) ? "S" : "",
265fdf6ea6cSchristos "UNEXPECTED INCONSISTENCY:");
266fdf6ea6cSchristos
2679e2e804cSlukem TAILQ_FOREACH(p, &badh, p_entries)
268fdf6ea6cSchristos (void) fprintf(stderr,
2697dfca760Schristos "%s: %s (%s)%s", p->p_type, p->p_devname,
2709e2e804cSlukem p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
271fdf6ea6cSchristos
272fdf6ea6cSchristos return sumstatus;
273fdf6ea6cSchristos }
274fdf6ea6cSchristos (void) endfsent();
2755f101a47Schristos return error;
276fdf6ea6cSchristos }
277fdf6ea6cSchristos
278fdf6ea6cSchristos
279fdf6ea6cSchristos static struct diskentry *
finddisk(const char * name)280f97f5096Slukem finddisk(const char *name)
281fdf6ea6cSchristos {
282fdf6ea6cSchristos const char *p;
28309e8908eSchristos size_t len, dlen;
284fdf6ea6cSchristos struct diskentry *d;
28509e8908eSchristos char buf[MAXPATHLEN];
28609e8908eSchristos struct dkwedge_info dkw;
28709e8908eSchristos int fd;
288fdf6ea6cSchristos
28909e8908eSchristos if ((fd = opendisk(name, O_RDONLY, buf, sizeof(buf), 0)) != -1) {
29009e8908eSchristos if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1)
29109e8908eSchristos name = dkw.dkw_parent;
29209e8908eSchristos (void)close(fd);
29309e8908eSchristos }
29409e8908eSchristos
29509e8908eSchristos for (dlen = len = strlen(name), p = name + len - 1; p >= name; --p)
296750ce43aSdsl if (isdigit((unsigned char)*p)) {
297fdf6ea6cSchristos len = p - name + 1;
298fdf6ea6cSchristos break;
299fdf6ea6cSchristos }
300fdf6ea6cSchristos if (p < name)
30109e8908eSchristos len = dlen;
302fdf6ea6cSchristos
303dacdbbf6Slukem TAILQ_FOREACH(d, &diskh, d_entries)
304fdf6ea6cSchristos if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
305fdf6ea6cSchristos return d;
306fdf6ea6cSchristos
307fdf6ea6cSchristos d = emalloc(sizeof(*d));
308fdf6ea6cSchristos d->d_name = estrdup(name);
309fdf6ea6cSchristos d->d_name[len] = '\0';
310fdf6ea6cSchristos TAILQ_INIT(&d->d_part);
311fdf6ea6cSchristos d->d_pid = 0;
312fdf6ea6cSchristos
313fdf6ea6cSchristos TAILQ_INSERT_TAIL(&diskh, d, d_entries);
314fdf6ea6cSchristos ndisks++;
315fdf6ea6cSchristos
316fdf6ea6cSchristos return d;
317fdf6ea6cSchristos }
318fdf6ea6cSchristos
319fdf6ea6cSchristos
320fdf6ea6cSchristos static void
printpart(void)321f97f5096Slukem printpart(void)
322fdf6ea6cSchristos {
323fdf6ea6cSchristos struct diskentry *d;
324fdf6ea6cSchristos struct partentry *p;
325fdf6ea6cSchristos
326dacdbbf6Slukem TAILQ_FOREACH(d, &diskh, d_entries) {
327fdf6ea6cSchristos (void) printf("disk %s:", d->d_name);
328dacdbbf6Slukem TAILQ_FOREACH(p, &d->d_part, p_entries)
3297dfca760Schristos (void) printf(" %s", p->p_devname);
330fdf6ea6cSchristos (void) printf("\n");
331fdf6ea6cSchristos }
332fdf6ea6cSchristos }
333fdf6ea6cSchristos
334fdf6ea6cSchristos
335fdf6ea6cSchristos static void
addpart(const char * type,const char * dev,const char * mntpt,void * auxarg)3364475e174Slukem addpart(const char *type, const char *dev, const char *mntpt, void *auxarg)
337fdf6ea6cSchristos {
3384475e174Slukem struct diskentry *d = finddisk(dev);
339fdf6ea6cSchristos struct partentry *p;
340fdf6ea6cSchristos
341dacdbbf6Slukem TAILQ_FOREACH(p, &d->d_part, p_entries)
3424475e174Slukem if (strcmp(p->p_devname, dev) == 0) {
3436742cb18Sgrant warnx("%s in fstab more than once!", dev);
344fdf6ea6cSchristos return;
345fdf6ea6cSchristos }
346fdf6ea6cSchristos
347fdf6ea6cSchristos p = emalloc(sizeof(*p));
3484475e174Slukem p->p_devname = estrdup(dev);
3497dfca760Schristos p->p_mntpt = estrdup(mntpt);
350fdf6ea6cSchristos p->p_type = estrdup(type);
351ef1bd36bSchristos p->p_auxarg = auxarg;
352fdf6ea6cSchristos
353fdf6ea6cSchristos TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
354fdf6ea6cSchristos }
355fdf6ea6cSchristos
356fdf6ea6cSchristos
357fdf6ea6cSchristos static int
startdisk(struct diskentry * d,int (* checkit)(const char *,const char *,const char *,void *,pid_t *))358f97f5096Slukem startdisk(struct diskentry *d,
359f97f5096Slukem int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
360fdf6ea6cSchristos {
361dacdbbf6Slukem struct partentry *p = TAILQ_FIRST(&d->d_part);
362fdf6ea6cSchristos int rv;
363fdf6ea6cSchristos
3647dfca760Schristos while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
365ef1bd36bSchristos p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
366fdf6ea6cSchristos sleep(10);
367fdf6ea6cSchristos
368fdf6ea6cSchristos if (rv == 0)
369fdf6ea6cSchristos nrun++;
370fdf6ea6cSchristos
371fdf6ea6cSchristos return rv;
372fdf6ea6cSchristos }
373