fixed error messages
[unix-history] / usr / src / usr.sbin / edquota / edquota.c
CommitLineData
311ea057 1#ifndef lint
8daa86a6 2static char sccsid[] = "@(#)edquota.c 4.5 (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>
311ea057
KM
16#include <sys/stat.h>
17#include <sys/file.h>
61184f42 18#include <sys/quota.h>
311ea057 19
311ea057 20#define DEFEDITOR "/usr/ucb/vi"
311ea057
KM
21
22struct dquot dq[NMOUNT];
23struct dquot odq[NMOUNT];
24char dqf[NMOUNT][MAXPATHLEN + 1];
25char odqf[NMOUNT][MAXPATHLEN + 1];
26
27char tmpfil[] = "/tmp/EdP.aXXXXX";
1cfb1c19 28char *qfname = "quotas";
311ea057
KM
29char *getenv();
30
31main(argc, argv)
32 char **argv;
33{
61184f42
KM
34 int uid;
35 char *arg0;
311ea057
KM
36
37 mktemp(tmpfil);
38 close(creat(tmpfil, 0600));
39 chown(tmpfil, getuid(), getgid());
40 arg0 = *argv++;
41 if (argc < 2) {
61184f42 42 fprintf(stderr, "Usage: %s [-p username] username ...\n", arg0);
311ea057
KM
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 }
61184f42
KM
52 if (argc > 2 && strcmp(*argv, "-p") == 0) {
53 argc--, argv++;
54 uid = getentry(*argv++);
55 if (uid < 0) {
56 unlink(tmpfil);
57 exit(1);
58 }
59 getprivs(uid);
60 argc--;
61 while (argc-- > 0) {
62 uid = getentry(*argv++);
63 if (uid < 0)
64 continue;
65 getdiscq(uid, odq, odqf);
66 putprivs(uid);
67 }
68 unlink(tmpfil);
69 exit(0);
70 }
71 while (--argc >= 0) {
72 uid = getentry(*argv++);
73 if (uid < 0)
74 continue;
75 getprivs(uid);
76 if (editit())
77 putprivs(uid);
78 }
311ea057
KM
79 unlink(tmpfil);
80 exit(0);
81}
82
61184f42
KM
83getentry(name)
84 char *name;
311ea057 85{
61184f42
KM
86 struct passwd *pw;
87 int uid;
311ea057
KM
88
89 if (alldigits(name))
90 uid = atoi(name);
91 else if (pw = getpwnam(name))
92 uid = pw->pw_uid;
93 else {
61184f42 94 fprintf(stderr, "%s: no such user\n", name);
311ea057 95 sleep(1);
61184f42 96 return (-1);
311ea057 97 }
61184f42 98 return (uid);
311ea057
KM
99}
100
101editit()
102{
103 register pid, xpid;
8daa86a6 104 int stat, omask;
311ea057 105
8daa86a6
SL
106#define mask(s) (1<<((s)-1))
107 omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGHUP));
311ea057
KM
108 top:
109 if ((pid = fork()) < 0) {
110 extern errno;
111
112 if (errno == EPROCLIM) {
113 fprintf(stderr, "You have too many processes\n");
114 return(0);
115 }
116 if (errno == EAGAIN) {
117 sleep(1);
118 goto top;
119 }
120 perror("fork");
121 return (0);
122 }
123 if (pid == 0) {
124 register char *ed;
125
8daa86a6 126 sigsetmask(omask);
311ea057
KM
127 setgid(getgid());
128 setuid(getuid());
311ea057
KM
129 if ((ed = getenv("EDITOR")) == (char *)0)
130 ed = DEFEDITOR;
131 execlp(ed, ed, tmpfil, 0);
132 perror(ed);
133 exit(1);
134 }
135 while ((xpid = wait(&stat)) >= 0)
136 if (xpid == pid)
137 break;
8daa86a6 138 sigsetmask(omask);
311ea057
KM
139 return (!stat);
140}
141
142getprivs(uid)
143 register uid;
144{
145 register i;
146 FILE *fd;
147
148 getdiscq(uid, dq, dqf);
149 for (i = 0; i < NMOUNT; i++) {
150 odq[i] = dq[i];
151 strcpy(odqf[i], dqf[i]);
152 }
153 if ((fd = fopen(tmpfil, "w")) == NULL) {
154 fprintf(stderr, "edquota: ");
155 perror(tmpfil);
156 exit(1);
157 }
158 for (i = 0; i < NMOUNT; i++) {
159 if (*dqf[i] == '\0')
160 continue;
161 fprintf(fd,
162"fs %s blocks (soft = %d, hard = %d) inodes (soft = %d, hard = %d)\n"
163 , dqf[i]
1cfb1c19
KM
164 , dq[i].dq_bsoftlimit / btodb(1024)
165 , dq[i].dq_bhardlimit / btodb(1024)
311ea057
KM
166 , dq[i].dq_isoftlimit
167 , dq[i].dq_ihardlimit
168 );
169 }
170 fclose(fd);
171}
172
173putprivs(uid)
174 register uid;
175{
176 register i, j;
177 int n;
178 FILE *fd;
179 char line[BUFSIZ];
180
181 fd = fopen(tmpfil, "r");
182 if (fd == NULL) {
183 fprintf(stderr, "Can't re-read temp file!!\n");
184 return;
185 }
186 for (i = 0; i < NMOUNT; i++) {
187 char *cp, *dp, *next();
188
189 if (fgets(line, sizeof (line), fd) == NULL)
190 break;
191 cp = next(line, " \t");
192 if (cp == NULL)
193 break;
194 *cp++ = '\0';
195 while (*cp && *cp == '\t' && *cp == ' ')
196 cp++;
197 dp = cp, cp = next(cp, " \t");
198 if (cp == NULL)
199 break;
200 *cp++ = '\0';
201 while (*cp && *cp == '\t' && *cp == ' ')
202 cp++;
203 strcpy(dqf[i], dp);
204 n = sscanf(cp,
205"blocks (soft = %d, hard = %d) inodes (soft = %hd, hard = %hd)\n"
206 , &dq[i].dq_bsoftlimit
207 , &dq[i].dq_bhardlimit
208 , &dq[i].dq_isoftlimit
209 , &dq[i].dq_ihardlimit
210 );
1cfb1c19
KM
211 if (n != 4) {
212 fprintf(stderr, "%s: bad format\n", cp);
213 continue;
214 }
215 dq[i].dq_bsoftlimit *= btodb(1024);
216 dq[i].dq_bhardlimit *= btodb(1024);
311ea057
KM
217 }
218 fclose(fd);
219 n = i;
220 for (i = 0; i < n; i++) {
221 if (*dqf[i] == '\0')
222 break;
223 for (j = 0; j < NMOUNT; j++) {
224 if (strcmp(dqf[i], odqf[j]) == 0)
225 break;
226 }
227 if (j >= NMOUNT)
228 continue;
229 *odqf[j] = '\0';
230 if (dq[i].dq_isoftlimit == odq[j].dq_isoftlimit &&
231 dq[i].dq_ihardlimit == odq[j].dq_ihardlimit &&
232 dq[i].dq_bsoftlimit == odq[j].dq_bsoftlimit &&
233 dq[i].dq_bhardlimit == odq[j].dq_bhardlimit) {
1cfb1c19 234 for (j = i; j < NMOUNT; j++) {
311ea057
KM
235 dq[j] = dq[j+1];
236 strcpy(dqf[j], dqf[j+1]);
237 }
238 *dqf[j] = '\0';
239 i--;
240 continue;
241 }
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];
311ea057
KM
321
322 setfsent();
323 while (fs = getfsent()) {
324 struct stat statb;
325 struct dqblk dqblk;
326 dev_t fsdev;
327
328 if (stat(fs->fs_spec, &statb) < 0)
329 continue;
330 fsdev = statb.st_rdev;
1cfb1c19
KM
331 sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
332 if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
311ea057
KM
333 continue;
334 if (quota(Q_GETDLIM, uid, fsdev, &dqblk) != 0) {
6f999543 335 register fd = open(qfilename, O_RDONLY);
311ea057
KM
336
337 if (fd < 0)
338 continue;
6f999543 339 lseek(fd, (long)(uid * sizeof dqblk), L_SET);
311ea057
KM
340 if (read(fd, &dqblk, sizeof dqblk) != sizeof (dqblk)) {
341 close(fd);
342 continue;
343 }
344 close(fd);
311ea057
KM
345 }
346 dq->dq_dqb = dqblk;
347 dq->dq_dev = fsdev;
348 strcpy(*dqf, fs->fs_file);
349 dq++, dqf++;
350 }
351 endfsent();
352 **dqf = '\0';
353}
354
355putdiscq(uid, dq, dqf)
356 register uid;
357 register struct dquot *dq;
358 register char (*dqf)[MAXPATHLEN + 1];
359{
360 register fd, cnt;
361 struct stat sb;
362 struct fstab *fs;
363
364 cnt = 0;
365 for (cnt = 0; ++cnt <= NMOUNT && **dqf; dq++, dqf++) {
366 fs = getfsfile(*dqf);
1cfb1c19
KM
367 if (fs == NULL) {
368 fprintf(stderr, "%s: not in /etc/fstab\n", *dqf);
369 continue;
370 }
371 strcat(*dqf, "/");
372 strcat(*dqf, qfname);
373 if (stat(*dqf, &sb) >= 0)
374 quota(Q_SETDLIM, uid, sb.st_dev, &dq->dq_dqb);
375 if ((fd = open(*dqf, 1)) < 0) {
376 perror(*dqf);
377 } else {
311ea057
KM
378 lseek(fd, (long)uid * (long)sizeof (struct dqblk), 0);
379 if (write(fd, &dq->dq_dqb, sizeof (struct dqblk)) !=
380 sizeof (struct dqblk)) {
381 fprintf(stderr, "edquota: ");
382 perror(*dqf);
383 }
384 close(fd);
385 }
311ea057
KM
386 }
387}