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/* $NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $ */
35
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/wait.h>
39#include <sys/queue.h>
40
41#include <ufs/ufs/quota.h>
42
43#include <err.h>
44#include <ctype.h>
45#include <fcntl.h>
46#include <fstab.h>
47#include <libutil.h>
48#include <string.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <unistd.h>
52
53#include "quotacheck.h"
54
55struct partentry {
56	TAILQ_ENTRY(partentry)	 p_entries;
57	char			*p_devname;	/* device name */
58	const char		*p_mntpt;	/* mount point */
59	struct quotafile	*p_qfu;		/* user quota file info ptr */
60	struct quotafile	*p_qfg;		/* group quota file info */
61};
62
63TAILQ_HEAD(part, partentry) badh;
64
65struct diskentry {
66	TAILQ_ENTRY(diskentry)	    d_entries;
67	char			   *d_name;	/* disk base name */
68	TAILQ_HEAD(prt, partentry)  d_part;	/* list of partitions on disk */
69	int			    d_pid;	/* 0 or pid of fsck proc */
70};
71
72TAILQ_HEAD(disk, diskentry) diskh;
73
74static struct diskentry *finddisk(const char *);
75static void addpart(struct fstab *, struct quotafile *, struct quotafile *);
76static int startdisk(struct diskentry *);
77extern void *emalloc(size_t);
78extern char *estrdup(const char *);
79
80int
81checkfstab(int uflag, int gflag)
82{
83	struct fstab *fs;
84	struct diskentry *d, *nextdisk;
85	struct partentry *p;
86	int ret, pid, retcode, passno, sumstatus, status, nextpass;
87	struct quotafile *qfu, *qfg;
88
89	TAILQ_INIT(&badh);
90	TAILQ_INIT(&diskh);
91
92	sumstatus = 0;
93
94	nextpass = 0;
95	for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
96		nextpass = INT_MAX;
97		if (setfsent() == 0) {
98			warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
99			return (8);
100		}
101		while ((fs = getfsent()) != NULL) {
102			if (fs->fs_passno > passno && fs->fs_passno < nextpass)
103				nextpass = fs->fs_passno;
104
105			if (passno != fs->fs_passno)
106				continue;
107
108			qfu = NULL;
109			if (uflag)
110				qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR);
111			qfg = NULL;
112			if (gflag)
113				qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR);
114			if (qfu == NULL && qfg == NULL)
115				continue;
116
117			if (passno == 1) {
118				sumstatus = chkquota(fs->fs_spec, qfu, qfg);
119				if (qfu)
120					quota_close(qfu);
121				if (qfg)
122					quota_close(qfg);
123				if (sumstatus)
124					return (sumstatus);
125				continue;
126			}
127			addpart(fs, qfu, qfg);
128		}
129
130		if (passno == 1)
131			continue;
132
133		TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
134			if ((ret = startdisk(nextdisk)) != 0)
135				return ret;
136		}
137
138		while ((pid = wait(&status)) != -1) {
139			TAILQ_FOREACH(d, &diskh, d_entries)
140				if (d->d_pid == pid)
141					break;
142
143			if (d == NULL) {
144				warnx("Unknown pid %d\n", pid);
145				continue;
146			}
147
148			if (WIFEXITED(status))
149				retcode = WEXITSTATUS(status);
150			else
151				retcode = 0;
152
153			p = TAILQ_FIRST(&d->d_part);
154
155			if (WIFSIGNALED(status)) {
156				(void) fprintf(stderr,
157				    "%s: (%s): EXITED WITH SIGNAL %d\n",
158				    p->p_devname, p->p_mntpt,
159				    WTERMSIG(status));
160				retcode = 8;
161			}
162
163			TAILQ_REMOVE(&d->d_part, p, p_entries);
164
165			if (retcode != 0) {
166				TAILQ_INSERT_TAIL(&badh, p, p_entries);
167				sumstatus |= retcode;
168			} else {
169				free(p->p_devname);
170				if (p->p_qfu)
171					quota_close(p->p_qfu);
172				if (p->p_qfg)
173					quota_close(p->p_qfg);
174				free(p);
175			}
176			d->d_pid = 0;
177
178			if (TAILQ_EMPTY(&d->d_part)) {
179				TAILQ_REMOVE(&diskh, d, d_entries);
180			} else {
181				if ((ret = startdisk(d)) != 0)
182					return ret;
183			}
184		}
185	}
186
187	if (sumstatus) {
188		p = TAILQ_FIRST(&badh);
189		if (p == NULL)
190			return (sumstatus);
191
192		(void) fprintf(stderr,
193			"THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
194			TAILQ_NEXT(p, p_entries) ? "S" : "",
195			"UNEXPECTED INCONSISTENCY:");
196
197		for (; p; p = TAILQ_NEXT(p, p_entries))
198			(void) fprintf(stderr,
199			    "%s: (%s)%s", p->p_devname, p->p_mntpt,
200			    TAILQ_NEXT(p, p_entries) ? ", " : "\n");
201
202		return sumstatus;
203	}
204	(void) endfsent();
205	return (0);
206}
207
208
209static struct diskentry *
210finddisk(const char *name)
211{
212	const char *p;
213	size_t len = 0;
214	struct diskentry *d;
215
216	p = strrchr(name, '/');
217	if (p == NULL)
218		p = name;
219	else
220		p++;
221	for (; *p && !isdigit(*p); p++)
222		continue;
223	for (; *p && isdigit(*p); p++)
224		continue;
225	len = p - name;
226	if (len == 0)
227		len = strlen(name);
228
229	TAILQ_FOREACH(d, &diskh, d_entries)
230		if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
231			return d;
232
233	d = emalloc(sizeof(*d));
234	d->d_name = estrdup(name);
235	d->d_name[len] = '\0';
236	TAILQ_INIT(&d->d_part);
237	d->d_pid = 0;
238
239	TAILQ_INSERT_TAIL(&diskh, d, d_entries);
240
241	return d;
242}
243
244static void
245addpart(struct fstab *fs, struct quotafile *qfu, struct quotafile *qfg)
246{
247	struct diskentry *d = finddisk(fs->fs_spec);
248	struct partentry *p;
249
250	TAILQ_FOREACH(p, &d->d_part, p_entries)
251		if (strcmp(p->p_devname, fs->fs_spec) == 0) {
252			warnx("%s in fstab more than once!\n", fs->fs_spec);
253			return;
254		}
255
256	p = emalloc(sizeof(*p));
257	p->p_devname = estrdup(blockcheck(fs->fs_spec));
258	if (qfu != NULL)
259		p->p_mntpt = quota_fsname(qfu);
260	else
261		p->p_mntpt = quota_fsname(qfg);
262	p->p_qfu = qfu;
263	p->p_qfg = qfg;
264
265	TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
266}
267
268
269static int
270startdisk(struct diskentry *d)
271{
272	struct partentry *p = TAILQ_FIRST(&d->d_part);
273
274	d->d_pid = fork();
275	if (d->d_pid < 0) {
276		perror("fork");
277		return (8);
278	}
279	if (d->d_pid == 0)
280		exit(chkquota(p->p_devname, p->p_qfu, p->p_qfg));
281	return (0);
282}
283