]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/fsck/preen.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sbin / fsck / preen.c
1 /*      $NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $       */
2
3 /*
4  * Copyright (c) 1990, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 4. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static char sccsid[] = "@(#)preen.c     8.5 (Berkeley) 4/28/95";
38 #else
39 __RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
40 #endif
41 #endif /* not lint */
42
43 #include <sys/param.h>
44 #include <sys/stat.h>
45 #include <sys/wait.h>
46 #include <sys/queue.h>
47
48 #include <err.h>
49 #include <ctype.h>
50 #include <fstab.h>
51 #include <string.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <unistd.h>
55
56 #include "fsutil.h"
57
58 struct partentry {
59         TAILQ_ENTRY(partentry)   p_entries;
60         char                    *p_devname;     /* device name */
61         char                    *p_mntpt;       /* mount point */
62         char                    *p_type;        /* file system type */
63 };
64
65 static TAILQ_HEAD(part, partentry) badh;
66
67 struct diskentry {
68         TAILQ_ENTRY(diskentry)      d_entries;
69         char                       *d_name;     /* disk base name */
70         TAILQ_HEAD(prt, partentry)  d_part;     /* list of partitions on disk */
71         int                         d_pid;      /* 0 or pid of fsck proc */
72 };
73
74 static TAILQ_HEAD(disk, diskentry) diskh;
75
76 static int nrun = 0, ndisks = 0;
77
78 static struct diskentry *finddisk(const char *);
79 static void addpart(const char *, const char *, const char *);
80 static int startdisk(struct diskentry *, 
81     int (*)(const char *, const char *, const char *, const char *, pid_t *));
82 static void printpart(void);
83
84 int
85 checkfstab(int flags, int (*docheck)(struct fstab *), 
86     int (*checkit)(const char *, const char *, const char *, const char *, pid_t *))
87 {
88         struct fstab *fs;
89         struct diskentry *d, *nextdisk;
90         struct partentry *p;
91         int ret, pid, retcode, passno, sumstatus, status, nextpass;
92         const char *name;
93
94         TAILQ_INIT(&badh);
95         TAILQ_INIT(&diskh);
96
97         sumstatus = 0;
98
99         nextpass = 0;
100         for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
101                 if (flags & CHECK_DEBUG)
102                         printf("pass %d\n", passno);
103                 
104                 nextpass = INT_MAX;
105                 if (setfsent() == 0) {
106                         warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
107                         return (8);
108                 }
109                 while ((fs = getfsent()) != 0) {
110                         name = fs->fs_spec;
111                         if (fs->fs_passno > passno && fs->fs_passno < nextpass)
112                                 nextpass = fs->fs_passno;
113
114                         if (passno != fs->fs_passno)
115                                 continue;
116
117                         if ((*docheck)(fs) == 0)
118                                 continue;
119
120                         if (flags & CHECK_DEBUG)
121                                 printf("pass %d, name %s\n", passno, name);
122
123                         if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
124                             (flags & DO_BACKGRD) != 0) {
125                                 if (name == NULL) {
126                                         if (flags & CHECK_PREEN)
127                                                 return 8;
128                                         else
129                                                 continue;
130                                 }
131                                 sumstatus = (*checkit)(fs->fs_vfstype,
132                                     name, fs->fs_file, NULL, NULL);
133
134                                 if (sumstatus)
135                                         return (sumstatus);
136                                 continue;
137                         } 
138                         if (name == NULL) {
139                                 (void) fprintf(stderr,
140                                     "BAD DISK NAME %s\n", fs->fs_spec);
141                                 sumstatus |= 8;
142                                 continue;
143                         }
144                         addpart(fs->fs_vfstype, name, fs->fs_file);
145                 }
146
147                 if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
148                     (flags & DO_BACKGRD) != 0)
149                         continue;
150
151                 if (flags & CHECK_DEBUG) {
152                         printf("Parallel start\n");
153                         printpart();
154                 }
155                 
156                 TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
157                         if ((ret = startdisk(nextdisk, checkit)) != 0)
158                                 return ret;
159                 }
160
161                 if (flags & CHECK_DEBUG) 
162                         printf("Parallel wait\n");
163                 while ((pid = wait(&status)) != -1) {
164                         TAILQ_FOREACH(d, &diskh, d_entries) 
165                                 if (d->d_pid == pid)
166                                         break;
167
168                         if (d == NULL) {
169                                 warnx("Unknown pid %d\n", pid);
170                                 continue;
171                         }
172
173                         if (WIFEXITED(status))
174                                 retcode = WEXITSTATUS(status);
175                         else
176                                 retcode = 0;
177
178                         p = TAILQ_FIRST(&d->d_part);
179
180                         if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
181                                 (void) printf("done %s: %s (%s) = 0x%x\n",
182                                     p->p_type, p->p_devname, p->p_mntpt,
183                                     status);
184
185                         if (WIFSIGNALED(status)) {
186                                 (void) fprintf(stderr,
187                                     "%s: %s (%s): EXITED WITH SIGNAL %d\n",
188                                     p->p_type, p->p_devname, p->p_mntpt,
189                                     WTERMSIG(status));
190                                 retcode = 8;
191                         }
192
193                         TAILQ_REMOVE(&d->d_part, p, p_entries);
194
195                         if (retcode != 0) {
196                                 TAILQ_INSERT_TAIL(&badh, p, p_entries);
197                                 sumstatus |= retcode;
198                         } else {
199                                 free(p->p_type);
200                                 free(p->p_devname);
201                                 free(p);
202                         }
203                         d->d_pid = 0;
204                         nrun--;
205
206                         if (TAILQ_EMPTY(&d->d_part)) {
207                                 TAILQ_REMOVE(&diskh, d, d_entries);
208                                 ndisks--;
209                         } else {
210                                 if ((ret = startdisk(d, checkit)) != 0)
211                                         return ret;
212                         }
213                 }
214                 if (flags & CHECK_DEBUG) {
215                         printf("Parallel end\n");
216                         printpart();
217                 }
218         }
219
220         if (!(flags & CHECK_PREEN))
221                         return 0;
222
223         if (sumstatus) {
224                 p = TAILQ_FIRST(&badh);
225                 if (p == NULL)
226                         return (sumstatus);
227
228                 (void) fprintf(stderr,
229                         "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
230                         TAILQ_NEXT(p, p_entries) ? "S" : "",
231                         "UNEXPECTED INCONSISTENCY:");
232
233                 for (; p; p = TAILQ_NEXT(p, p_entries))
234                         (void) fprintf(stderr,
235                             "%s: %s (%s)%s", p->p_type, p->p_devname,
236                             p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
237
238                 return sumstatus;
239         }
240         (void) endfsent();
241         return (0);
242 }
243
244
245 static struct diskentry *
246 finddisk(const char *name)
247 {
248         const char *p;
249         size_t len = 0;
250         struct diskentry *d;
251
252         p = strrchr(name, '/');
253         if (p == NULL)
254                 p = name;
255         else
256                 p++;
257         for (; *p && !isdigit(*p); p++)
258                 continue;
259         for (; *p && isdigit(*p); p++)
260                 continue;
261         len = p - name;
262         if (len == 0)
263                 len = strlen(name);
264
265         TAILQ_FOREACH(d, &diskh, d_entries) 
266                 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
267                         return d;
268
269         d = emalloc(sizeof(*d));
270         d->d_name = estrdup(name);
271         d->d_name[len] = '\0';
272         TAILQ_INIT(&d->d_part);
273         d->d_pid = 0;
274
275         TAILQ_INSERT_TAIL(&diskh, d, d_entries);
276         ndisks++;
277
278         return d;
279 }
280
281
282 static void
283 printpart(void)
284 {
285         struct diskentry *d;
286         struct partentry *p;
287
288         TAILQ_FOREACH(d, &diskh, d_entries) {
289                 (void) printf("disk %s: ", d->d_name);
290                 TAILQ_FOREACH(p, &d->d_part, p_entries)
291                         (void) printf("%s ", p->p_devname);
292                 (void) printf("\n");
293         }
294 }
295
296
297 static void
298 addpart(const char *type, const char *dev, const char *mntpt)
299 {
300         struct diskentry *d = finddisk(dev);
301         struct partentry *p;
302
303         TAILQ_FOREACH(p, &d->d_part, p_entries)
304                 if (strcmp(p->p_devname, dev) == 0) {
305                         warnx("%s in fstab more than once!\n", dev);
306                         return;
307                 }
308
309         p = emalloc(sizeof(*p));
310         p->p_devname = estrdup(dev);
311         p->p_mntpt = estrdup(mntpt);
312         p->p_type = estrdup(type);
313
314         TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
315 }
316
317
318 static int
319 startdisk(struct diskentry *d, int (*checkit)(const char *, const char *,
320     const char *, const char *, pid_t *))
321 {
322         struct partentry *p = TAILQ_FIRST(&d->d_part);
323         int rv;
324
325         while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
326             NULL, &d->d_pid)) != 0 && nrun > 0)
327                 sleep(10);
328
329         if (rv == 0)
330                 nrun++;
331
332         return rv;
333 }