xref: /dragonfly/sbin/fsck/preen.c (revision 7319acd8bfde65d43d79eda128836e175df0177c)
1 /*
2  * Copyright (c) 1990, 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  * 3. 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  * @(#)preen.c      8.5 (Berkeley) 4/28/95
30  * $FreeBSD: src/sbin/fsck/preen.c,v 1.16 1999/12/30 16:32:40 peter Exp $
31  */
32 
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <sys/wait.h>
36 
37 #include <vfs/ufs/dinode.h>
38 
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fstab.h>
42 #include <string.h>
43 
44 #include "fsck.h"
45 
46 char      preen;                        /* just fix normal inconsistencies */
47 
48 struct part {
49           struct    part *next;                   /* forward link of partitions on disk */
50           char      *name;                        /* device name */
51           char      *fsname;            /* mounted filesystem name */
52           long      auxdata;            /* auxillary data for application */
53 } *badlist, **badnext = &badlist;
54 
55 struct disk {
56           char      *name;                        /* disk base name */
57           struct    disk *next;                   /* forward link for list of disks */
58           struct    part *part;                   /* head of list of partitions on disk */
59           int       pid;                          /* If != 0, pid of proc working on */
60 } *disks;
61 
62 int       nrun, ndisks;
63 
64 static void addpart(char *name, char *fsname, long auxdata);
65 static struct disk *finddisk(char *name);
66 static int startdisk(struct disk *dk,
67                     int (*checkit)(char *, char *, long, int));
68 
69 int
checkfstab(int do_preen,int maxrun,int (* docheck)(struct fstab *),int (* chkit)(char *,char *,long,int))70 checkfstab(int do_preen, int maxrun, int (*docheck)(struct fstab *),
71            int (*chkit)(char *, char *, long, int))
72 {
73           struct fstab *fsp;
74           struct disk *dk, *nextdisk;
75           struct part *pt;
76           int ret, pid, retcode, passno, sumstatus, status;
77           long auxdata;
78           char *name;
79 
80           sumstatus = 0;
81           for (passno = 1; passno <= 2; passno++) {
82                     if (setfsent() == 0) {
83                               fprintf(stderr, "Can't open checklist file: %s\n",
84                                   _PATH_FSTAB);
85                               return (8);
86                     }
87                     while ((fsp = getfsent()) != NULL) {
88                               if ((auxdata = (*docheck)(fsp)) == 0)
89                                         continue;
90                               if (do_preen == 0 ||
91                                   (passno == 1 && fsp->fs_passno == 1)) {
92                                         if ((name = blockcheck(fsp->fs_spec)) != NULL) {
93                                                   if ((sumstatus = (*chkit)(name,
94                                                       fsp->fs_file, auxdata, 0)) != 0)
95                                                             return (sumstatus);
96                                         } else if (do_preen)
97                                                   return (8);
98                               } else if (passno == 2 && fsp->fs_passno > 1) {
99                                         if ((name = blockcheck(fsp->fs_spec)) == NULL) {
100                                                   fprintf(stderr, "BAD DISK NAME %s\n",
101                                                             fsp->fs_spec);
102                                                   sumstatus |= 8;
103                                                   continue;
104                                         }
105                                         addpart(name, fsp->fs_file, auxdata);
106                               }
107                     }
108                     if (do_preen == 0)
109                               return (0);
110           }
111           if (do_preen) {
112                     if (maxrun == 0)
113                               maxrun = ndisks;
114                     if (maxrun > ndisks)
115                               maxrun = ndisks;
116                     nextdisk = disks;
117                     for (passno = 0; passno < maxrun; ++passno) {
118                               while ((ret = startdisk(nextdisk, chkit)) && nrun > 0)
119                                         sleep(10);
120                               if (ret)
121                                         return (ret);
122                               nextdisk = nextdisk->next;
123                     }
124                     while ((pid = wait(&status)) != -1) {
125                               for (dk = disks; dk; dk = dk->next)
126                                         if (dk->pid == pid)
127                                                   break;
128                               if (dk == NULL) {
129                                         printf("Unknown pid %d\n", pid);
130                                         continue;
131                               }
132                               if (WIFEXITED(status))
133                                         retcode = WEXITSTATUS(status);
134                               else
135                                         retcode = 0;
136                               if (WIFSIGNALED(status)) {
137                                         printf("%s (%s): EXITED WITH SIGNAL %d\n",
138                                                   dk->part->name, dk->part->fsname,
139                                                   WTERMSIG(status));
140                                         retcode = 8;
141                               }
142                               if (retcode != 0) {
143                                         sumstatus |= retcode;
144                                         *badnext = dk->part;
145                                         badnext = &dk->part->next;
146                                         dk->part = dk->part->next;
147                                         *badnext = NULL;
148                               } else
149                                         dk->part = dk->part->next;
150                               dk->pid = 0;
151                               nrun--;
152                               if (dk->part == NULL)
153                                         ndisks--;
154 
155                               if (nextdisk == NULL) {
156                                         if (dk->part) {
157                                                   while ((ret = startdisk(dk, chkit)) &&
158                                                       nrun > 0)
159                                                             sleep(10);
160                                                   if (ret)
161                                                             return (ret);
162                                         }
163                               } else if (nrun < maxrun && nrun < ndisks) {
164                                         for ( ;; ) {
165                                                   if ((nextdisk = nextdisk->next) == NULL)
166                                                             nextdisk = disks;
167                                                   if (nextdisk->part != NULL &&
168                                                       nextdisk->pid == 0)
169                                                             break;
170                                         }
171                                         while ((ret = startdisk(nextdisk, chkit)) &&
172                                             nrun > 0)
173                                                   sleep(10);
174                                         if (ret)
175                                                   return (ret);
176                               }
177                     }
178           }
179           if (sumstatus) {
180                     if (badlist == NULL)
181                               return (sumstatus);
182                     fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
183                               badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
184                     for (pt = badlist; pt; pt = pt->next)
185                               fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
186                                   pt->next ? ", " : "\n");
187                     return (sumstatus);
188           }
189           endfsent();
190           return (0);
191 }
192 
193 static struct disk *
finddisk(char * name)194 finddisk(char *name)
195 {
196           struct disk *dk, **dkp;
197           char *p;
198           size_t len;
199 
200           p = strrchr(name, '/');
201           p = p == NULL ? name : p + 1;
202           while (*p != '\0' && !isdigit((u_char)*p))
203                     p++;
204           while (isdigit((u_char)*p))
205                     p++;
206           len = (size_t)(p - name);
207           for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
208                     if (strncmp(dk->name, name, len) == 0 &&
209                         dk->name[len] == 0)
210                               return (dk);
211           }
212           if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
213                     fprintf(stderr, "out of memory");
214                     exit (8);
215           }
216           dk = *dkp;
217           if ((dk->name = malloc(len + 1)) == NULL) {
218                     fprintf(stderr, "out of memory");
219                     exit (8);
220           }
221           strncpy(dk->name, name, len);
222           dk->name[len] = '\0';
223           dk->part = NULL;
224           dk->next = NULL;
225           dk->pid = 0;
226           ndisks++;
227           return (dk);
228 }
229 
230 static void
addpart(char * name,char * fsname,long auxdata)231 addpart(char *name, char *fsname, long auxdata)
232 {
233           struct disk *dk = finddisk(name);
234           struct part *pt, **ppt = &dk->part;
235 
236           for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
237                     if (strcmp(pt->name, name) == 0) {
238                               printf("%s in fstab more than once!\n", name);
239                               return;
240                     }
241           if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
242                     fprintf(stderr, "out of memory");
243                     exit (8);
244           }
245           pt = *ppt;
246           if ((pt->name = malloc(strlen(name) + 1)) == NULL) {
247                     fprintf(stderr, "out of memory");
248                     exit (8);
249           }
250           strcpy(pt->name, name);
251           if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL) {
252                     fprintf(stderr, "out of memory");
253                     exit (8);
254           }
255           strcpy(pt->fsname, fsname);
256           pt->next = NULL;
257           pt->auxdata = auxdata;
258 }
259 
260 static int
startdisk(struct disk * dk,int (* checkit)(char *,char *,long,int))261 startdisk(struct disk *dk, int (*checkit)(char *, char *, long ,int))
262 {
263           struct part *pt = dk->part;
264 
265           dk->pid = fork();
266           if (dk->pid < 0) {
267                     perror("fork");
268                     return (8);
269           }
270           if (dk->pid == 0)
271                     exit((*checkit)(pt->name, pt->fsname, pt->auxdata, 1));
272           nrun++;
273           return (0);
274 }
275 
276 char *
blockcheck(char * origname)277 blockcheck(char *origname)
278 {
279           struct stat stblock;
280           char *newname;
281           struct fstab *fsinfo;
282           int retried = 0, len;
283 
284           newname = origname;
285 retry:
286           if (stat(newname, &stblock) < 0) {
287                     newname = getdevpath(newname, 0);
288                     if (stat(newname, &stblock) < 0) {
289                               printf("Can't stat %s: %s\n", newname, strerror(errno));
290                               return (origname);
291                     }
292           }
293           switch(stblock.st_mode & S_IFMT) {
294           case S_IFCHR:
295           case S_IFBLK:
296                     return(newname);
297           case S_IFREG:
298                     return(newname);
299           case S_IFDIR:
300                     if (retried)
301                               break;
302 
303                     len = strlen(origname) - 1;
304                     if (len > 0 && origname[len] == '/')
305                               /* remove trailing slash */
306                               origname[len] = '\0';
307                     if ((fsinfo = getfsfile(origname)) == NULL) {
308                               printf("Can't resolve %s to character special device",
309                                   origname);
310                               return (0);
311                     }
312                     newname = fsinfo->fs_spec;
313                     retried++;
314                     goto retry;
315           }
316           /*
317            * Not a block or character device, just return name and
318            * let the user decide whether to use it.
319            */
320           return (origname);
321 }
322