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