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