add vdioctl
[unix-history] / usr / src / usr.sbin / edquota / edquota.c
CommitLineData
2a18434a
KM
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
311ea057 13#ifndef lint
285a6d40 14static char sccsid[] = "@(#)edquota.c 5.3 (Berkeley) %G%";
2a18434a 15#endif not lint
311ea057
KM
16
17/*
18 * Disk quota editor.
19 */
20#include <stdio.h>
21#include <signal.h>
22#include <errno.h>
23#include <pwd.h>
24#include <ctype.h>
25#include <fstab.h>
26
27#include <sys/param.h>
311ea057
KM
28#include <sys/stat.h>
29#include <sys/file.h>
61184f42 30#include <sys/quota.h>
311ea057 31
311ea057 32#define DEFEDITOR "/usr/ucb/vi"
311ea057
KM
33
34struct dquot dq[NMOUNT];
35struct dquot odq[NMOUNT];
36char dqf[NMOUNT][MAXPATHLEN + 1];
37char odqf[NMOUNT][MAXPATHLEN + 1];
38
39char tmpfil[] = "/tmp/EdP.aXXXXX";
1cfb1c19 40char *qfname = "quotas";
311ea057
KM
41char *getenv();
42
43main(argc, argv)
44 char **argv;
45{
61184f42
KM
46 int uid;
47 char *arg0;
311ea057
KM
48
49 mktemp(tmpfil);
50 close(creat(tmpfil, 0600));
51 chown(tmpfil, getuid(), getgid());
52 arg0 = *argv++;
53 if (argc < 2) {
61184f42 54 fprintf(stderr, "Usage: %s [-p username] username ...\n", arg0);
311ea057
KM
55 unlink(tmpfil);
56 exit(1);
57 }
58 --argc;
59 if (getuid()) {
60 fprintf(stderr, "%s: permission denied\n", arg0);
61 unlink(tmpfil);
62 exit(1);
63 }
61184f42
KM
64 if (argc > 2 && strcmp(*argv, "-p") == 0) {
65 argc--, argv++;
66 uid = getentry(*argv++);
67 if (uid < 0) {
68 unlink(tmpfil);
69 exit(1);
70 }
71 getprivs(uid);
72 argc--;
73 while (argc-- > 0) {
74 uid = getentry(*argv++);
75 if (uid < 0)
76 continue;
77 getdiscq(uid, odq, odqf);
78 putprivs(uid);
79 }
80 unlink(tmpfil);
81 exit(0);
82 }
83 while (--argc >= 0) {
84 uid = getentry(*argv++);
85 if (uid < 0)
86 continue;
87 getprivs(uid);
88 if (editit())
89 putprivs(uid);
90 }
311ea057
KM
91 unlink(tmpfil);
92 exit(0);
93}
94
61184f42
KM
95getentry(name)
96 char *name;
311ea057 97{
61184f42
KM
98 struct passwd *pw;
99 int uid;
311ea057
KM
100
101 if (alldigits(name))
102 uid = atoi(name);
103 else if (pw = getpwnam(name))
104 uid = pw->pw_uid;
105 else {
61184f42 106 fprintf(stderr, "%s: no such user\n", name);
311ea057 107 sleep(1);
61184f42 108 return (-1);
311ea057 109 }
61184f42 110 return (uid);
311ea057
KM
111}
112
113editit()
114{
115 register pid, xpid;
8daa86a6 116 int stat, omask;
311ea057 117
8daa86a6
SL
118#define mask(s) (1<<((s)-1))
119 omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP));
311ea057
KM
120 top:
121 if ((pid = fork()) < 0) {
122 extern errno;
123
124 if (errno == EPROCLIM) {
125 fprintf(stderr, "You have too many processes\n");
126 return(0);
127 }
128 if (errno == EAGAIN) {
129 sleep(1);
130 goto top;
131 }
132 perror("fork");
133 return (0);
134 }
135 if (pid == 0) {
136 register char *ed;
137
8daa86a6 138 sigsetmask(omask);
311ea057
KM
139 setgid(getgid());
140 setuid(getuid());
311ea057
KM
141 if ((ed = getenv("EDITOR")) == (char *)0)
142 ed = DEFEDITOR;
143 execlp(ed, ed, tmpfil, 0);
144 perror(ed);
145 exit(1);
146 }
147 while ((xpid = wait(&stat)) >= 0)
148 if (xpid == pid)
149 break;
8daa86a6 150 sigsetmask(omask);
311ea057
KM
151 return (!stat);
152}
153
154getprivs(uid)
155 register uid;
156{
157 register i;
158 FILE *fd;
159
160 getdiscq(uid, dq, dqf);
161 for (i = 0; i < NMOUNT; i++) {
162 odq[i] = dq[i];
163 strcpy(odqf[i], dqf[i]);
164 }
165 if ((fd = fopen(tmpfil, "w")) == NULL) {
166 fprintf(stderr, "edquota: ");
167 perror(tmpfil);
168 exit(1);
169 }
170 for (i = 0; i < NMOUNT; i++) {
171 if (*dqf[i] == '\0')
172 continue;
173 fprintf(fd,
174"fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n"
175 , dqf[i]
285a6d40
JB
176 , dbtob(dq[i].dq_bsoftlimit) / 1024
177 , dbtob(dq[i].dq_bhardlimit) / 1024
311ea057
KM
178 , dq[i].dq_isoftlimit
179 , dq[i].dq_ihardlimit
180 );
181 }
182 fclose(fd);
183}
184
185putprivs(uid)
186 register uid;
187{
188 register i, j;
189 int n;
190 FILE *fd;
191 char line[BUFSIZ];
192
193 fd = fopen(tmpfil, "r");
194 if (fd == NULL) {
195 fprintf(stderr, "Can't re-read temp file!!\n");
196 return;
197 }
198 for (i = 0; i < NMOUNT; i++) {
199 char *cp, *dp, *next();
200
201 if (fgets(line, sizeof (line), fd) == NULL)
202 break;
203 cp = next(line, " \t");
204 if (cp == NULL)
205 break;
206 *cp++ = '\0';
207 while (*cp && *cp == '\t' && *cp == ' ')
208 cp++;
209 dp = cp, cp = next(cp, " \t");
210 if (cp == NULL)
211 break;
212 *cp++ = '\0';
213 while (*cp && *cp == '\t' && *cp == ' ')
214 cp++;
215 strcpy(dqf[i], dp);
216 n = sscanf(cp,
217"blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n"
218 , &dq[i].dq_bsoftlimit
219 , &dq[i].dq_bhardlimit
220 , &dq[i].dq_isoftlimit
221 , &dq[i].dq_ihardlimit
222 );
1cfb1c19
KM
223 if (n != 4) {
224 fprintf(stderr, "%s: bad format\n", cp);
225 continue;
226 }
285a6d40
JB
227 dq[i].dq_bsoftlimit = btodb(dq[i].dq_bsoftlimit * 1024);
228 dq[i].dq_bhardlimit = btodb(dq[i].dq_bhardlimit * 1024);
311ea057
KM
229 }
230 fclose(fd);
231 n = i;
232 for (i = 0; i < n; i++) {
233 if (*dqf[i] == '\0')
234 break;
235 for (j = 0; j < NMOUNT; j++) {
236 if (strcmp(dqf[i], odqf[j]) == 0)
237 break;
238 }
239 if (j >= NMOUNT)
240 continue;
241 *odqf[j] = '\0';
311ea057
KM
242 /*
243 * This isn't really good enough, it is quite likely
244 * to have changed while we have been away editing,
245 * but it's not important enough to worry about at
246 * the minute.
247 */
248 dq[i].dq_curblocks = odq[j].dq_curblocks;
249 dq[i].dq_curinodes = odq[j].dq_curinodes;
250 /*
251 * If we've upped the inode or disk block limits
252 * and the guy is out of warnings, reinitialize.
253 */
254 if (dq[i].dq_bsoftlimit > odq[j].dq_bsoftlimit &&
255 dq[i].dq_bwarn == 0)
256 dq[i].dq_bwarn = MAX_DQ_WARN;
257 if (dq[i].dq_isoftlimit > odq[j].dq_isoftlimit &&
258 dq[i].dq_iwarn == 0)
259 dq[i].dq_iwarn = MAX_IQ_WARN;
260 }
261 if (i < NMOUNT) {
262 for (j = 0; j < NMOUNT; j++) {
263 if (*odqf[j] == '\0')
264 continue;
265 strcpy(dqf[i], odqf[j]);
266 dq[i].dq_isoftlimit = 0;
267 dq[i].dq_ihardlimit = 0;
268 dq[i].dq_bsoftlimit = 0;
269 dq[i].dq_bhardlimit = 0;
270 /*
271 * Same applies as just above
272 * but matters not at all, as we are just
273 * turning quota'ing off for this filesys.
274 */
275 dq[i].dq_curblocks = odq[j].dq_curblocks;
276 dq[i].dq_curinodes = odq[j].dq_curinodes;
277 if (++i >= NMOUNT)
278 break;
279 }
280 }
281 if (*dqf[0])
282 putdiscq(uid, dq, dqf);
283}
284
285char *
286next(cp, match)
287 register char *cp;
288 char *match;
289{
290 register char *dp;
291
292 while (cp && *cp) {
293 for (dp = match; dp && *dp; dp++)
294 if (*dp == *cp)
295 return (cp);
296 cp++;
297 }
298 return ((char *)0);
299}
300
301alldigits(s)
302 register char *s;
303{
304 register c;
305
306 c = *s++;
307 do {
308 if (!isdigit(c))
309 return (0);
310 } while (c = *s++);
311 return (1);
312}
313
314getdiscq(uid, dq, dqf)
315 register uid;
316 register struct dquot *dq;
317 register char (*dqf)[MAXPATHLEN + 1];
318{
319 register struct fstab *fs;
1cfb1c19 320 char qfilename[MAXPATHLEN + 1];
1b102e0f
KM
321 struct stat statb;
322 struct dqblk dqblk;
323 dev_t fsdev;
324 int fd;
325 static int warned = 0;
326 extern int errno;
311ea057
KM
327
328 setfsent();
329 while (fs = getfsent()) {
311ea057
KM
330 if (stat(fs->fs_spec, &statb) < 0)
331 continue;
332 fsdev = statb.st_rdev;
1cfb1c19
KM
333 sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
334 if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
311ea057
KM
335 continue;
336 if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) {
1b102e0f
KM
337 if (errno == EINVAL && !warned) {
338 warned++;
339 fprintf(stderr, "Warning: %s\n",
340 "Quotas are not compiled into this kernel");
341 sleep(3);
342 }
343 fd = open(qfilename, O_RDONLY);
311ea057
KM
344 if (fd < 0)
345 continue;
6f999543 346 lseek(fd, (long)(uid * sizeof dqblk), L_SET);
a1d76d07
S
347 switch (read(fd, &dqblk, sizeof dqblk)) {
348 case 0: /* EOF */
349 /*
350 * Convert implicit 0 quota (EOF)
351 * into an explicit one (zero'ed dqblk)
352 */
353 bzero((caddr_t)&dqblk, sizeof dqblk);
354 break;
355
356 case sizeof dqblk: /* OK */
357 break;
358
359 default: /* ERROR */
360 fprintf(stderr, "edquota: read error in ");
361 perror(qfilename);
311ea057
KM
362 close(fd);
363 continue;
364 }
365 close(fd);
311ea057
KM
366 }
367 dq->dq_dqb = dqblk;
368 dq->dq_dev = fsdev;
369 strcpy(*dqf, fs->fs_file);
370 dq++, dqf++;
371 }
372 endfsent();
373 **dqf = '\0';
374}
375
376putdiscq(uid, dq, dqf)
377 register uid;
378 register struct dquot *dq;
379 register char (*dqf)[MAXPATHLEN + 1];
380{
381 register fd, cnt;
382 struct stat sb;
383 struct fstab *fs;
384
385 cnt = 0;
386 for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) {
387 fs = getfsfile(*dqf);
1cfb1c19
KM
388 if (fs == NULL) {
389 fprintf(stderr, "%s: not in /etc/fstab\n", *dqf);
390 continue;
391 }
392 strcat(*dqf, "/");
393 strcat(*dqf, qfname);
394 if (stat(*dqf, &sb) >= 0)
395 quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb);
396 if ((fd = open(*dqf, 1)) < 0) {
397 perror(*dqf);
398 } else {
311ea057
KM
399 lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0);
400 if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) !=
401 sizeof (struct dqblk)) {
402 fprintf(stderr, "edquota: ");
403 perror(*dqf);
404 }
405 close(fd);
406 }
311ea057
KM
407 }
408}