1175678Smpp/*	$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $	*/
2175678Smpp
31558Srgrimes/*
41558Srgrimes * Copyright (c) 1990, 1993
51558Srgrimes *	The Regents of the University of California.  All rights reserved.
61558Srgrimes *
71558Srgrimes * Redistribution and use in source and binary forms, with or without
81558Srgrimes * modification, are permitted provided that the following conditions
91558Srgrimes * are met:
101558Srgrimes * 1. Redistributions of source code must retain the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer.
121558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131558Srgrimes *    notice, this list of conditions and the following disclaimer in the
141558Srgrimes *    documentation and/or other materials provided with the distribution.
151558Srgrimes * 4. Neither the name of the University nor the names of its contributors
161558Srgrimes *    may be used to endorse or promote products derived from this software
171558Srgrimes *    without specific prior written permission.
181558Srgrimes *
191558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
201558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
211558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
221558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
231558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
241558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
251558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
261558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
271558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
281558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
291558Srgrimes * SUCH DAMAGE.
30175678Smpp *
31175678Smpp * $FreeBSD$
321558Srgrimes */
331558Srgrimes
34175678Smpp#include <sys/cdefs.h>
35175678Smpp#ifndef lint
36114589Sobrien#if 0
37175678Smppstatic char sccsid[] = "@(#)preen.c	8.5 (Berkeley) 4/28/95";
38175678Smpp#else
39175678Smpp__RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
40175678Smpp#endif
41114589Sobrien#endif /* not lint */
421558Srgrimes
431558Srgrimes#include <sys/param.h>
441558Srgrimes#include <sys/stat.h>
451558Srgrimes#include <sys/wait.h>
46175678Smpp#include <sys/queue.h>
4723798Sbde
48207736Smckusick#include <ufs/ufs/quota.h>
49207736Smckusick
50175678Smpp#include <err.h>
5123798Sbde#include <ctype.h>
52207736Smckusick#include <fcntl.h>
531558Srgrimes#include <fstab.h>
54207736Smckusick#include <libutil.h>
551558Srgrimes#include <string.h>
56101592Sphk#include <stdio.h>
57101592Sphk#include <stdlib.h>
58101592Sphk#include <unistd.h>
5923675Speter
60175678Smpp#include "quotacheck.h"
611558Srgrimes
62175678Smppstruct partentry {
63175678Smpp	TAILQ_ENTRY(partentry)	 p_entries;
64180187Sdes	char			*p_devname;	/* device name */
65207736Smckusick	const char		*p_mntpt;	/* mount point */
66207736Smckusick	struct quotafile	*p_qfu;		/* user quota file info ptr */
67207736Smckusick	struct quotafile	*p_qfg;		/* group quota file info */
68175678Smpp};
69101592Sphk
70175678SmppTAILQ_HEAD(part, partentry) badh;
711558Srgrimes
72175678Smppstruct diskentry {
73180187Sdes	TAILQ_ENTRY(diskentry)	    d_entries;
74180187Sdes	char			   *d_name;	/* disk base name */
75175678Smpp	TAILQ_HEAD(prt, partentry)  d_part;	/* list of partitions on disk */
76175678Smpp	int			    d_pid;	/* 0 or pid of fsck proc */
77175678Smpp};
781558Srgrimes
79175678SmppTAILQ_HEAD(disk, diskentry) diskh;
801558Srgrimes
81175678Smppstatic struct diskentry *finddisk(const char *);
82207736Smckusickstatic void addpart(struct fstab *, struct quotafile *, struct quotafile *);
83175678Smppstatic int startdisk(struct diskentry *);
84175678Smppextern void *emalloc(size_t);
85175678Smppextern char *estrdup(const char *);
8623675Speter
877585Sbdeint
88207736Smckusickcheckfstab(int uflag, int gflag)
891558Srgrimes{
90175678Smpp	struct fstab *fs;
91175678Smpp	struct diskentry *d, *nextdisk;
92175678Smpp	struct partentry *p;
93175678Smpp	int ret, pid, retcode, passno, sumstatus, status, nextpass;
94207736Smckusick	struct quotafile *qfu, *qfg;
951558Srgrimes
96175678Smpp	TAILQ_INIT(&badh);
97175678Smpp	TAILQ_INIT(&diskh);
98175678Smpp
991558Srgrimes	sumstatus = 0;
100175678Smpp
101175678Smpp	nextpass = 0;
102175678Smpp	for (passno = 1; nextpass != INT_MAX; passno = nextpass) {
103175678Smpp		nextpass = INT_MAX;
1041558Srgrimes		if (setfsent() == 0) {
105175678Smpp			warnx("Can't open checklist file: %s\n", _PATH_FSTAB);
1061558Srgrimes			return (8);
1071558Srgrimes		}
108175678Smpp		while ((fs = getfsent()) != 0) {
109175678Smpp			if (fs->fs_passno > passno && fs->fs_passno < nextpass)
110175678Smpp				nextpass = fs->fs_passno;
111175678Smpp
112175678Smpp			if (passno != fs->fs_passno)
1131558Srgrimes				continue;
114175678Smpp
115207736Smckusick			qfu = NULL;
116207736Smckusick			if (uflag)
117207736Smckusick				qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR);
118207736Smckusick			qfg = NULL;
119207736Smckusick			if (gflag)
120207736Smckusick				qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR);
121207736Smckusick			if (qfu == NULL && qfg == NULL)
122175678Smpp				continue;
123175678Smpp
124175678Smpp			if (passno == 1) {
125207736Smckusick				sumstatus = chkquota(fs->fs_spec, qfu, qfg);
126207736Smckusick				if (qfu)
127207736Smckusick					quota_close(qfu);
128207736Smckusick				if (qfg)
129207736Smckusick					quota_close(qfg);
130175678Smpp				if (sumstatus)
131175678Smpp					return (sumstatus);
132175678Smpp				continue;
133180187Sdes			}
134207736Smckusick			addpart(fs, qfu, qfg);
1351558Srgrimes		}
136175678Smpp
137175678Smpp		if (passno == 1)
138175678Smpp			continue;
139175678Smpp
140175678Smpp		TAILQ_FOREACH(nextdisk, &diskh, d_entries) {
141175678Smpp			if ((ret = startdisk(nextdisk)) != 0)
142175678Smpp				return ret;
1431558Srgrimes		}
144175678Smpp
1451558Srgrimes		while ((pid = wait(&status)) != -1) {
146180187Sdes			TAILQ_FOREACH(d, &diskh, d_entries)
147175678Smpp				if (d->d_pid == pid)
1481558Srgrimes					break;
149175678Smpp
150175678Smpp			if (d == NULL) {
151175678Smpp				warnx("Unknown pid %d\n", pid);
1521558Srgrimes				continue;
1531558Srgrimes			}
154175678Smpp
1551558Srgrimes			if (WIFEXITED(status))
1561558Srgrimes				retcode = WEXITSTATUS(status);
1571558Srgrimes			else
1581558Srgrimes				retcode = 0;
159175678Smpp
160175678Smpp			p = TAILQ_FIRST(&d->d_part);
161175678Smpp
1621558Srgrimes			if (WIFSIGNALED(status)) {
163175678Smpp				(void) fprintf(stderr,
164207736Smckusick				    "%s: (%s): EXITED WITH SIGNAL %d\n",
165207736Smckusick				    p->p_devname, p->p_mntpt,
166175678Smpp				    WTERMSIG(status));
1671558Srgrimes				retcode = 8;
1681558Srgrimes			}
169175678Smpp
170175678Smpp			TAILQ_REMOVE(&d->d_part, p, p_entries);
171175678Smpp
1721558Srgrimes			if (retcode != 0) {
173175678Smpp				TAILQ_INSERT_TAIL(&badh, p, p_entries);
1741558Srgrimes				sumstatus |= retcode;
175175678Smpp			} else {
176175678Smpp				free(p->p_devname);
177207736Smckusick				if (p->p_qfu)
178207736Smckusick					quota_close(p->p_qfu);
179207736Smckusick				if (p->p_qfg)
180207736Smckusick					quota_close(p->p_qfg);
181175678Smpp				free(p);
182175678Smpp			}
183175678Smpp			d->d_pid = 0;
1841558Srgrimes
185175678Smpp			if (TAILQ_EMPTY(&d->d_part)) {
186175678Smpp				TAILQ_REMOVE(&diskh, d, d_entries);
187175678Smpp			} else {
188175678Smpp				if ((ret = startdisk(d)) != 0)
189175678Smpp					return ret;
1901558Srgrimes			}
1911558Srgrimes		}
1921558Srgrimes	}
193175678Smpp
1941558Srgrimes	if (sumstatus) {
195175678Smpp		p = TAILQ_FIRST(&badh);
196175678Smpp		if (p == NULL)
1971558Srgrimes			return (sumstatus);
198175678Smpp
199175678Smpp		(void) fprintf(stderr,
200175678Smpp			"THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
201175678Smpp			TAILQ_NEXT(p, p_entries) ? "S" : "",
202175678Smpp			"UNEXPECTED INCONSISTENCY:");
203175678Smpp
204175678Smpp		for (; p; p = TAILQ_NEXT(p, p_entries))
205175678Smpp			(void) fprintf(stderr,
206207736Smckusick			    "%s: (%s)%s", p->p_devname, p->p_mntpt,
207207736Smckusick			    TAILQ_NEXT(p, p_entries) ? ", " : "\n");
208175678Smpp
209175678Smpp		return sumstatus;
2101558Srgrimes	}
211175678Smpp	(void) endfsent();
2121558Srgrimes	return (0);
2131558Srgrimes}
2141558Srgrimes
215175678Smpp
216175678Smppstatic struct diskentry *
217175678Smppfinddisk(const char *name)
2181558Srgrimes{
219175678Smpp	const char *p;
220175678Smpp	size_t len = 0;
221175678Smpp	struct diskentry *d;
2221558Srgrimes
22335095Sbde	p = strrchr(name, '/');
224175678Smpp	if (p == NULL)
225175678Smpp		p = name;
226175678Smpp	else
22735095Sbde		p++;
228175678Smpp	for (; *p && !isdigit(*p); p++)
229175678Smpp		continue;
230175678Smpp	for (; *p && isdigit(*p); p++)
231175678Smpp		continue;
232175678Smpp	len = p - name;
233175678Smpp	if (len == 0)
234175678Smpp		len = strlen(name);
235175678Smpp
236180187Sdes	TAILQ_FOREACH(d, &diskh, d_entries)
237175678Smpp		if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
238175678Smpp			return d;
239175678Smpp
240175678Smpp	d = emalloc(sizeof(*d));
241175678Smpp	d->d_name = estrdup(name);
242175678Smpp	d->d_name[len] = '\0';
243175678Smpp	TAILQ_INIT(&d->d_part);
244175678Smpp	d->d_pid = 0;
245175678Smpp
246175678Smpp	TAILQ_INSERT_TAIL(&diskh, d, d_entries);
247175678Smpp
248175678Smpp	return d;
2491558Srgrimes}
2501558Srgrimes
25123675Speterstatic void
252207736Smckusickaddpart(struct fstab *fs, struct quotafile *qfu, struct quotafile *qfg)
2531558Srgrimes{
254207736Smckusick	struct diskentry *d = finddisk(fs->fs_spec);
255175678Smpp	struct partentry *p;
2561558Srgrimes
257175678Smpp	TAILQ_FOREACH(p, &d->d_part, p_entries)
258207736Smckusick		if (strcmp(p->p_devname, fs->fs_spec) == 0) {
259207736Smckusick			warnx("%s in fstab more than once!\n", fs->fs_spec);
2601558Srgrimes			return;
2611558Srgrimes		}
262175678Smpp
263175678Smpp	p = emalloc(sizeof(*p));
264207736Smckusick	p->p_devname = estrdup(blockcheck(fs->fs_spec));
265207736Smckusick	if (qfu != NULL)
266207736Smckusick		p->p_mntpt = quota_fsname(qfu);
267207736Smckusick	else
268207736Smckusick		p->p_mntpt = quota_fsname(qfg);
269207736Smckusick	p->p_qfu = qfu;
270207736Smckusick	p->p_qfg = qfg;
271175678Smpp
272175678Smpp	TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
2731558Srgrimes}
2741558Srgrimes
275175678Smpp
27623675Speterstatic int
277175678Smppstartdisk(struct diskentry *d)
2781558Srgrimes{
279175678Smpp	struct partentry *p = TAILQ_FIRST(&d->d_part);
2801558Srgrimes
281175678Smpp	d->d_pid = fork();
282175678Smpp	if (d->d_pid < 0) {
28341474Sjulian		perror("fork");
2841558Srgrimes		return (8);
2851558Srgrimes	}
286175678Smpp	if (d->d_pid == 0)
287207736Smckusick		exit(chkquota(p->p_devname, p->p_qfu, p->p_qfg));
2881558Srgrimes	return (0);
2891558Srgrimes}
290