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