]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/fsck/preen.c
ifconfig: fix 'ifconfig -l ether'
[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
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         int                      p_failok;      /* failok option set */
64 };
65
66 static TAILQ_HEAD(part, partentry) badh;
67
68 struct diskentry {
69         TAILQ_ENTRY(diskentry)      d_entries;
70         char                       *d_name;     /* disk base name */
71         TAILQ_HEAD(prt, partentry)  d_part;     /* list of partitions on disk */
72         int                         d_pid;      /* 0 or pid of fsck proc */
73 };
74
75 static TAILQ_HEAD(disk, diskentry) diskh;
76
77 static int nrun = 0, ndisks = 0;
78
79 static struct diskentry *finddisk(const char *);
80 static void addpart(const char *, const char *, const char *, const int);
81 static int startdisk(struct diskentry *, 
82     int (*)(const char *, const char *, const char *, const char *, pid_t *));
83 static void printpart(void);
84
85 int
86 checkfstab(int flags, int (*docheck)(struct fstab *), 
87     int (*checkit)(const char *, const char *, const char *, const char *, pid_t *))
88 {
89         struct fstab *fs;
90         struct diskentry *d, *nextdisk;
91         struct partentry *p;
92         int ret, pid, retcode, passno, sumstatus, status, nextpass;
93         const char *name;
94
95         TAILQ_INIT(&badh);
96         TAILQ_INIT(&diskh);
97
98         sumstatus = 0;
99
100         nextpass = 0;
101         for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
102                 if (flags & CHECK_DEBUG)
103                         printf("pass %d\n", passno);
104                 
105                 nextpass = INT_MAX;
106                 if (setfsent() == 0) {
107                         warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
108                         return (8);
109                 }
110                 while ((fs = getfsent()) != NULL) {
111                         name = fs->fs_spec;
112                         if (fs->fs_passno > passno && fs->fs_passno < nextpass)
113                                 nextpass = fs->fs_passno;
114
115                         if (passno != fs->fs_passno)
116                                 continue;
117
118                         if ((*docheck)(fs) == 0)
119                                 continue;
120
121                         if (flags & CHECK_DEBUG)
122                                 printf("pass %d, name %s\n", passno, name);
123
124                         if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
125                             (flags & DO_BACKGRD) != 0) {
126                                 if (name == NULL) {
127                                         if (flags & CHECK_PREEN)
128                                                 return 8;
129                                         else
130                                                 continue;
131                                 }
132                                 sumstatus = (*checkit)(fs->fs_vfstype,
133                                     name, fs->fs_file, NULL, NULL);
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                             getfsopt(fs, "failok"));
146                 }
147
148                 if ((flags & CHECK_PREEN) == 0 || passno == 1 ||
149                     (flags & DO_BACKGRD) != 0)
150                         continue;
151
152                 if (flags & CHECK_DEBUG) {
153                         printf("Parallel start\n");
154                         printpart();
155                 }
156                 
157                 TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
158                         if ((ret = startdisk(nextdisk, checkit)) != 0)
159                                 return ret;
160                 }
161
162                 if (flags & CHECK_DEBUG) 
163                         printf("Parallel wait\n");
164                 while ((pid = wait(&status)) != -1) {
165                         TAILQ_FOREACH(d, &diskh, d_entries) 
166                                 if (d->d_pid == pid)
167                                         break;
168
169                         if (d == NULL) {
170                                 warnx("Unknown pid %d\n", pid);
171                                 continue;
172                         }
173
174                         p = TAILQ_FIRST(&d->d_part);
175
176                         if (WIFEXITED(status) == 0) {
177                                 retcode = 0;
178                         } else if (p->p_failok == 0) {
179                                 retcode = WEXITSTATUS(status);
180                         } else {
181                                 retcode = 0;
182                                 fprintf(stderr, "%s: failok SPECIFIED, FSCK "
183                                     "ERROR(S) IGNORED\n", p->p_devname);
184                         }
185
186                         if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
187                                 (void) printf("done %s: %s (%s) = 0x%x\n",
188                                     p->p_type, p->p_devname, p->p_mntpt,
189                                     status);
190
191                         if (WIFSIGNALED(status)) {
192                                 (void) fprintf(stderr,
193                                     "%s: %s (%s): EXITED WITH SIGNAL %d\n",
194                                     p->p_type, p->p_devname, p->p_mntpt,
195                                     WTERMSIG(status));
196                                 retcode = 8;
197                         }
198
199                         TAILQ_REMOVE(&d->d_part, p, p_entries);
200
201                         if (retcode != 0) {
202                                 TAILQ_INSERT_TAIL(&badh, p, p_entries);
203                                 sumstatus |= retcode;
204                         } else {
205                                 free(p->p_type);
206                                 free(p->p_devname);
207                                 free(p);
208                         }
209                         d->d_pid = 0;
210                         nrun--;
211
212                         if (TAILQ_EMPTY(&d->d_part)) {
213                                 TAILQ_REMOVE(&diskh, d, d_entries);
214                                 ndisks--;
215                         } else {
216                                 if ((ret = startdisk(d, checkit)) != 0)
217                                         return ret;
218                         }
219                 }
220                 if (flags & CHECK_DEBUG) {
221                         printf("Parallel end\n");
222                         printpart();
223                 }
224         }
225
226         if (!(flags & CHECK_PREEN))
227                         return 0;
228
229         if (sumstatus) {
230                 p = TAILQ_FIRST(&badh);
231                 if (p == NULL)
232                         return (sumstatus);
233
234                 (void) fprintf(stderr,
235                         "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
236                         TAILQ_NEXT(p, p_entries) ? "S" : "",
237                         "UNEXPECTED INCONSISTENCY:");
238
239                 for (; p; p = TAILQ_NEXT(p, p_entries))
240                         (void) fprintf(stderr,
241                             "%s: %s (%s)%s", p->p_type, p->p_devname,
242                             p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
243
244                 return sumstatus;
245         }
246         (void) endfsent();
247         return (0);
248 }
249
250 static struct diskentry *
251 finddisk(const char *name)
252 {
253         const char *p;
254         size_t len = 0;
255         struct diskentry *d;
256
257         p = strrchr(name, '/');
258         if (p == NULL)
259                 p = name;
260         else
261                 p++;
262         for (; *p && !isdigit(*p); p++)
263                 continue;
264         for (; *p && isdigit(*p); p++)
265                 continue;
266         len = p - name;
267         if (len == 0)
268                 len = strlen(name);
269
270         TAILQ_FOREACH(d, &diskh, d_entries) 
271                 if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
272                         return d;
273
274         d = emalloc(sizeof(*d));
275         d->d_name = estrdup(name);
276         d->d_name[len] = '\0';
277         TAILQ_INIT(&d->d_part);
278         d->d_pid = 0;
279
280         TAILQ_INSERT_TAIL(&diskh, d, d_entries);
281         ndisks++;
282
283         return d;
284 }
285
286
287 static void
288 printpart(void)
289 {
290         struct diskentry *d;
291         struct partentry *p;
292
293         TAILQ_FOREACH(d, &diskh, d_entries) {
294                 (void) printf("disk %s: ", d->d_name);
295                 TAILQ_FOREACH(p, &d->d_part, p_entries)
296                         (void) printf("%s ", p->p_devname);
297                 (void) printf("\n");
298         }
299 }
300
301
302 static void
303 addpart(const char *type, const char *dev, const char *mntpt, const int failok)
304 {
305         struct diskentry *d = finddisk(dev);
306         struct partentry *p;
307
308         TAILQ_FOREACH(p, &d->d_part, p_entries)
309                 if (strcmp(p->p_devname, dev) == 0) {
310                         warnx("%s in fstab more than once!\n", dev);
311                         return;
312                 }
313
314         p = emalloc(sizeof(*p));
315         p->p_devname = estrdup(dev);
316         p->p_mntpt = estrdup(mntpt);
317         p->p_type = estrdup(type);
318         p->p_failok = failok;
319
320         TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
321 }
322
323
324 static int
325 startdisk(struct diskentry *d, int (*checkit)(const char *, const char *,
326     const char *, const char *, pid_t *))
327 {
328         struct partentry *p = TAILQ_FIRST(&d->d_part);
329         int rv;
330
331         while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
332             NULL, &d->d_pid)) != 0 && nrun > 0)
333                 sleep(10);
334
335         if (rv == 0)
336                 nrun++;
337
338         return rv;
339 }