quotarestore.c revision 1.2.4.3 1 1.2.4.3 yamt /* $NetBSD: quotarestore.c,v 1.2.4.3 2012/10/30 19:00:51 yamt Exp $ */
2 1.2.4.2 yamt /*-
3 1.2.4.2 yamt * Copyright (c) 2012 The NetBSD Foundation, Inc.
4 1.2.4.2 yamt * All rights reserved.
5 1.2.4.2 yamt *
6 1.2.4.2 yamt * This code is derived from software contributed to The NetBSD Foundation
7 1.2.4.2 yamt * by David A. Holland.
8 1.2.4.2 yamt *
9 1.2.4.2 yamt * Redistribution and use in source and binary forms, with or without
10 1.2.4.2 yamt * modification, are permitted provided that the following conditions
11 1.2.4.2 yamt * are met:
12 1.2.4.2 yamt * 1. Redistributions of source code must retain the above copyright
13 1.2.4.2 yamt * notice, this list of conditions and the following disclaimer.
14 1.2.4.2 yamt * 2. Redistributions in binary form must reproduce the above copyright
15 1.2.4.2 yamt * notice, this list of conditions and the following disclaimer in the
16 1.2.4.2 yamt * documentation and/or other materials provided with the distribution.
17 1.2.4.2 yamt *
18 1.2.4.2 yamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 1.2.4.2 yamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 1.2.4.2 yamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 1.2.4.2 yamt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 1.2.4.2 yamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 1.2.4.2 yamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 1.2.4.2 yamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 1.2.4.2 yamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 1.2.4.2 yamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 1.2.4.2 yamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 1.2.4.2 yamt * POSSIBILITY OF SUCH DAMAGE.
29 1.2.4.2 yamt */
30 1.2.4.2 yamt
31 1.2.4.2 yamt #include <sys/cdefs.h>
32 1.2.4.3 yamt __RCSID("$NetBSD: quotarestore.c,v 1.2.4.3 2012/10/30 19:00:51 yamt Exp $");
33 1.2.4.2 yamt
34 1.2.4.2 yamt #include <stdio.h>
35 1.2.4.2 yamt #include <stdlib.h>
36 1.2.4.2 yamt #include <string.h>
37 1.2.4.2 yamt #include <assert.h>
38 1.2.4.2 yamt #include <getopt.h>
39 1.2.4.2 yamt #include <limits.h>
40 1.2.4.2 yamt #include <errno.h>
41 1.2.4.2 yamt #include <err.h>
42 1.2.4.2 yamt
43 1.2.4.2 yamt #include <quota.h>
44 1.2.4.2 yamt
45 1.2.4.3 yamt static const char ws[] = " \t\r\n";
46 1.2.4.2 yamt
47 1.2.4.2 yamt static char **idtypenames;
48 1.2.4.2 yamt static unsigned numidtypes;
49 1.2.4.2 yamt
50 1.2.4.2 yamt static char **objtypenames;
51 1.2.4.2 yamt static unsigned numobjtypes;
52 1.2.4.2 yamt
53 1.2.4.2 yamt ////////////////////////////////////////////////////////////
54 1.2.4.2 yamt // table of quota keys
55 1.2.4.2 yamt
56 1.2.4.2 yamt struct qklist {
57 1.2.4.2 yamt struct quotakey *keys;
58 1.2.4.2 yamt unsigned num, max;
59 1.2.4.2 yamt };
60 1.2.4.2 yamt
61 1.2.4.2 yamt static struct qklist *
62 1.2.4.2 yamt qklist_create(void)
63 1.2.4.2 yamt {
64 1.2.4.2 yamt struct qklist *l;
65 1.2.4.2 yamt
66 1.2.4.2 yamt l = malloc(sizeof(*l));
67 1.2.4.2 yamt if (l == NULL) {
68 1.2.4.2 yamt err(EXIT_FAILURE, "malloc");
69 1.2.4.2 yamt }
70 1.2.4.2 yamt l->keys = 0;
71 1.2.4.2 yamt l->num = 0;
72 1.2.4.2 yamt l->max = 0;
73 1.2.4.2 yamt return l;
74 1.2.4.2 yamt }
75 1.2.4.2 yamt
76 1.2.4.2 yamt static void
77 1.2.4.2 yamt qklist_destroy(struct qklist *l)
78 1.2.4.2 yamt {
79 1.2.4.2 yamt free(l->keys);
80 1.2.4.2 yamt free(l);
81 1.2.4.2 yamt }
82 1.2.4.2 yamt
83 1.2.4.2 yamt static void
84 1.2.4.2 yamt qklist_truncate(struct qklist *l)
85 1.2.4.2 yamt {
86 1.2.4.2 yamt l->num = 0;
87 1.2.4.2 yamt }
88 1.2.4.2 yamt
89 1.2.4.2 yamt static void
90 1.2.4.2 yamt qklist_add(struct qklist *l, const struct quotakey *qk)
91 1.2.4.2 yamt {
92 1.2.4.2 yamt assert(l->num <= l->max);
93 1.2.4.2 yamt if (l->num == l->max) {
94 1.2.4.2 yamt l->max = l->max ? l->max * 2 : 4;
95 1.2.4.2 yamt l->keys = realloc(l->keys, l->max * sizeof(l->keys[0]));
96 1.2.4.2 yamt if (l->keys == NULL) {
97 1.2.4.2 yamt err(EXIT_FAILURE, "realloc");
98 1.2.4.2 yamt }
99 1.2.4.2 yamt }
100 1.2.4.2 yamt l->keys[l->num++] = *qk;
101 1.2.4.2 yamt }
102 1.2.4.2 yamt
103 1.2.4.2 yamt static int
104 1.2.4.2 yamt qk_compare(const void *av, const void *bv)
105 1.2.4.2 yamt {
106 1.2.4.2 yamt const struct quotakey *a = av;
107 1.2.4.2 yamt const struct quotakey *b = bv;
108 1.2.4.2 yamt
109 1.2.4.2 yamt if (a->qk_idtype < b->qk_idtype) {
110 1.2.4.2 yamt return -1;
111 1.2.4.2 yamt }
112 1.2.4.2 yamt if (a->qk_idtype > b->qk_idtype) {
113 1.2.4.2 yamt return 1;
114 1.2.4.2 yamt }
115 1.2.4.2 yamt
116 1.2.4.2 yamt if (a->qk_id < b->qk_id) {
117 1.2.4.2 yamt return -1;
118 1.2.4.2 yamt }
119 1.2.4.2 yamt if (a->qk_id > b->qk_id) {
120 1.2.4.2 yamt return 1;
121 1.2.4.2 yamt }
122 1.2.4.2 yamt
123 1.2.4.2 yamt if (a->qk_objtype < b->qk_objtype) {
124 1.2.4.2 yamt return -1;
125 1.2.4.2 yamt }
126 1.2.4.2 yamt if (a->qk_objtype > b->qk_objtype) {
127 1.2.4.2 yamt return 1;
128 1.2.4.2 yamt }
129 1.2.4.2 yamt
130 1.2.4.2 yamt return 0;
131 1.2.4.2 yamt }
132 1.2.4.2 yamt
133 1.2.4.2 yamt static void
134 1.2.4.2 yamt qklist_sort(struct qklist *l)
135 1.2.4.2 yamt {
136 1.2.4.2 yamt qsort(l->keys, l->num, sizeof(l->keys[0]), qk_compare);
137 1.2.4.2 yamt }
138 1.2.4.2 yamt
139 1.2.4.2 yamt static int
140 1.2.4.2 yamt qklist_present(struct qklist *l, const struct quotakey *key)
141 1.2.4.2 yamt {
142 1.2.4.2 yamt void *p;
143 1.2.4.2 yamt
144 1.2.4.2 yamt p = bsearch(key, l->keys, l->num, sizeof(l->keys[0]), qk_compare);
145 1.2.4.2 yamt return p != NULL;
146 1.2.4.2 yamt }
147 1.2.4.2 yamt
148 1.2.4.2 yamt ////////////////////////////////////////////////////////////
149 1.2.4.2 yamt // name tables and string conversion
150 1.2.4.2 yamt
151 1.2.4.2 yamt static void
152 1.2.4.2 yamt maketables(struct quotahandle *qh)
153 1.2.4.2 yamt {
154 1.2.4.2 yamt unsigned i;
155 1.2.4.2 yamt
156 1.2.4.2 yamt numidtypes = quota_getnumidtypes(qh);
157 1.2.4.2 yamt idtypenames = malloc(numidtypes * sizeof(idtypenames[0]));
158 1.2.4.2 yamt if (idtypenames == NULL) {
159 1.2.4.2 yamt err(EXIT_FAILURE, "malloc");
160 1.2.4.2 yamt }
161 1.2.4.2 yamt
162 1.2.4.2 yamt for (i=0; i<numidtypes; i++) {
163 1.2.4.2 yamt idtypenames[i] = strdup(quota_idtype_getname(qh, i));
164 1.2.4.2 yamt if (idtypenames[i] == NULL) {
165 1.2.4.2 yamt err(EXIT_FAILURE, "strdup");
166 1.2.4.2 yamt }
167 1.2.4.2 yamt }
168 1.2.4.2 yamt
169 1.2.4.2 yamt numobjtypes = quota_getnumobjtypes(qh);
170 1.2.4.2 yamt objtypenames = malloc(numobjtypes * sizeof(objtypenames[0]));
171 1.2.4.2 yamt if (objtypenames == NULL) {
172 1.2.4.2 yamt err(EXIT_FAILURE, "malloc");
173 1.2.4.2 yamt }
174 1.2.4.2 yamt
175 1.2.4.2 yamt for (i=0; i<numobjtypes; i++) {
176 1.2.4.2 yamt objtypenames[i] = strdup(quota_objtype_getname(qh, i));
177 1.2.4.2 yamt if (objtypenames[i] == NULL) {
178 1.2.4.2 yamt err(EXIT_FAILURE, "strdup");
179 1.2.4.2 yamt }
180 1.2.4.2 yamt }
181 1.2.4.2 yamt }
182 1.2.4.2 yamt
183 1.2.4.2 yamt static int
184 1.2.4.2 yamt getidtype(const char *name, int *ret)
185 1.2.4.2 yamt {
186 1.2.4.2 yamt unsigned i;
187 1.2.4.2 yamt
188 1.2.4.2 yamt for (i=0; i<numidtypes; i++) {
189 1.2.4.2 yamt if (!strcmp(name, idtypenames[i])) {
190 1.2.4.2 yamt *ret = i;
191 1.2.4.2 yamt return 0;
192 1.2.4.2 yamt }
193 1.2.4.2 yamt }
194 1.2.4.2 yamt return -1;
195 1.2.4.2 yamt }
196 1.2.4.2 yamt
197 1.2.4.2 yamt static int
198 1.2.4.2 yamt getid(const char *name, int idtype, id_t *ret)
199 1.2.4.2 yamt {
200 1.2.4.2 yamt unsigned long val;
201 1.2.4.2 yamt char *s;
202 1.2.4.2 yamt
203 1.2.4.2 yamt if (!strcmp(name, "default")) {
204 1.2.4.2 yamt *ret = QUOTA_DEFAULTID;
205 1.2.4.2 yamt return 0;
206 1.2.4.2 yamt }
207 1.2.4.2 yamt errno = 0;
208 1.2.4.2 yamt val = strtoul(name, &s, 10);
209 1.2.4.2 yamt if (errno || *s != 0) {
210 1.2.4.2 yamt return -1;
211 1.2.4.2 yamt }
212 1.2.4.2 yamt if (idtype == QUOTA_IDTYPE_USER && val > UID_MAX) {
213 1.2.4.2 yamt return -1;
214 1.2.4.2 yamt }
215 1.2.4.2 yamt if (idtype == QUOTA_IDTYPE_GROUP && val > GID_MAX) {
216 1.2.4.2 yamt return -1;
217 1.2.4.2 yamt }
218 1.2.4.2 yamt *ret = val;
219 1.2.4.2 yamt return 0;
220 1.2.4.2 yamt }
221 1.2.4.2 yamt
222 1.2.4.2 yamt static int
223 1.2.4.2 yamt getobjtype(const char *name, int *ret)
224 1.2.4.2 yamt {
225 1.2.4.2 yamt unsigned i;
226 1.2.4.2 yamt size_t len;
227 1.2.4.2 yamt
228 1.2.4.2 yamt for (i=0; i<numobjtypes; i++) {
229 1.2.4.2 yamt if (!strcmp(name, objtypenames[i])) {
230 1.2.4.2 yamt *ret = i;
231 1.2.4.2 yamt return 0;
232 1.2.4.2 yamt }
233 1.2.4.2 yamt }
234 1.2.4.2 yamt
235 1.2.4.2 yamt /*
236 1.2.4.2 yamt * Sigh. Some early committed versions of quotadump used
237 1.2.4.2 yamt * "blocks" and "files" instead of "block" and "file".
238 1.2.4.2 yamt */
239 1.2.4.2 yamt len = strlen(name);
240 1.2.4.2 yamt if (len == 0) {
241 1.2.4.2 yamt return -1;
242 1.2.4.2 yamt }
243 1.2.4.2 yamt for (i=0; i<numobjtypes; i++) {
244 1.2.4.2 yamt if (name[len-1] == 's' &&
245 1.2.4.2 yamt !strncmp(name, objtypenames[i], len-1)) {
246 1.2.4.2 yamt *ret = i;
247 1.2.4.2 yamt return 0;
248 1.2.4.2 yamt }
249 1.2.4.2 yamt }
250 1.2.4.2 yamt return -1;
251 1.2.4.2 yamt }
252 1.2.4.2 yamt
253 1.2.4.2 yamt static int
254 1.2.4.2 yamt getlimit(const char *name, uint64_t *ret)
255 1.2.4.2 yamt {
256 1.2.4.2 yamt unsigned long long val;
257 1.2.4.2 yamt char *s;
258 1.2.4.2 yamt
259 1.2.4.2 yamt if (!strcmp(name, "-")) {
260 1.2.4.2 yamt *ret = QUOTA_NOLIMIT;
261 1.2.4.2 yamt return 0;
262 1.2.4.2 yamt }
263 1.2.4.2 yamt errno = 0;
264 1.2.4.2 yamt val = strtoull(name, &s, 10);
265 1.2.4.2 yamt if (errno || *s != 0) {
266 1.2.4.2 yamt return -1;
267 1.2.4.2 yamt }
268 1.2.4.2 yamt *ret = val;
269 1.2.4.2 yamt return 0;
270 1.2.4.2 yamt }
271 1.2.4.2 yamt
272 1.2.4.2 yamt static int
273 1.2.4.2 yamt gettime(const char *name, int64_t *ret)
274 1.2.4.2 yamt {
275 1.2.4.2 yamt long long val;
276 1.2.4.2 yamt char *s;
277 1.2.4.2 yamt
278 1.2.4.2 yamt if (!strcmp(name, "-")) {
279 1.2.4.2 yamt *ret = QUOTA_NOTIME;
280 1.2.4.2 yamt return 0;
281 1.2.4.2 yamt }
282 1.2.4.2 yamt errno = 0;
283 1.2.4.2 yamt val = strtoll(name, &s, 10);
284 1.2.4.2 yamt if (errno || *s != 0 || val < 0) {
285 1.2.4.2 yamt return -1;
286 1.2.4.2 yamt }
287 1.2.4.2 yamt *ret = val;
288 1.2.4.2 yamt return 0;
289 1.2.4.2 yamt }
290 1.2.4.2 yamt
291 1.2.4.2 yamt ////////////////////////////////////////////////////////////
292 1.2.4.2 yamt // parsing tools
293 1.2.4.2 yamt
294 1.2.4.2 yamt static int
295 1.2.4.2 yamt isws(int ch)
296 1.2.4.2 yamt {
297 1.2.4.2 yamt return ch != '\0' && strchr(ws, ch) != NULL;
298 1.2.4.2 yamt }
299 1.2.4.2 yamt
300 1.2.4.2 yamt static char *
301 1.2.4.2 yamt skipws(char *s)
302 1.2.4.2 yamt {
303 1.2.4.2 yamt while (isws(*s)) {
304 1.2.4.2 yamt s++;
305 1.2.4.2 yamt }
306 1.2.4.2 yamt return s;
307 1.2.4.2 yamt }
308 1.2.4.2 yamt
309 1.2.4.2 yamt ////////////////////////////////////////////////////////////
310 1.2.4.2 yamt // deletion of extra records
311 1.2.4.2 yamt
312 1.2.4.2 yamt static void
313 1.2.4.2 yamt scankeys(struct quotahandle *qh, struct qklist *seenkeys,
314 1.2.4.2 yamt struct qklist *dropkeys)
315 1.2.4.2 yamt {
316 1.2.4.2 yamt struct quotacursor *qc;
317 1.2.4.2 yamt #define MAX 8
318 1.2.4.2 yamt struct quotakey keys[MAX];
319 1.2.4.2 yamt struct quotaval vals[MAX];
320 1.2.4.2 yamt int num, i;
321 1.2.4.2 yamt
322 1.2.4.2 yamt qc = quota_opencursor(qh);
323 1.2.4.2 yamt if (qc == NULL) {
324 1.2.4.2 yamt err(EXIT_FAILURE, "quota_opencursor");
325 1.2.4.2 yamt }
326 1.2.4.2 yamt
327 1.2.4.2 yamt while (quotacursor_atend(qc) == 0) {
328 1.2.4.2 yamt num = quotacursor_getn(qc, keys, vals, MAX);
329 1.2.4.2 yamt if (num < 0) {
330 1.2.4.2 yamt if (errno == EDEADLK) {
331 1.2.4.2 yamt quotacursor_rewind(qc);
332 1.2.4.2 yamt qklist_truncate(dropkeys);
333 1.2.4.2 yamt continue;
334 1.2.4.2 yamt }
335 1.2.4.2 yamt err(EXIT_FAILURE, "quotacursor_getn");
336 1.2.4.2 yamt }
337 1.2.4.2 yamt for (i=0; i<num; i++) {
338 1.2.4.2 yamt if (qklist_present(seenkeys, &keys[i]) == 0) {
339 1.2.4.2 yamt qklist_add(dropkeys, &keys[i]);
340 1.2.4.2 yamt }
341 1.2.4.2 yamt }
342 1.2.4.2 yamt }
343 1.2.4.2 yamt
344 1.2.4.2 yamt quotacursor_close(qc);
345 1.2.4.2 yamt }
346 1.2.4.2 yamt
347 1.2.4.2 yamt static void
348 1.2.4.2 yamt purge(struct quotahandle *qh, struct qklist *dropkeys)
349 1.2.4.2 yamt {
350 1.2.4.2 yamt unsigned i;
351 1.2.4.2 yamt
352 1.2.4.2 yamt for (i=0; i<dropkeys->num; i++) {
353 1.2.4.2 yamt if (quota_delete(qh, &dropkeys->keys[i])) {
354 1.2.4.2 yamt err(EXIT_FAILURE, "quota_delete");
355 1.2.4.2 yamt }
356 1.2.4.2 yamt }
357 1.2.4.2 yamt }
358 1.2.4.2 yamt
359 1.2.4.2 yamt ////////////////////////////////////////////////////////////
360 1.2.4.2 yamt // dumpfile reader
361 1.2.4.2 yamt
362 1.2.4.2 yamt static void
363 1.2.4.2 yamt readdumpfile(struct quotahandle *qh, FILE *f, const char *path,
364 1.2.4.2 yamt struct qklist *seenkeys)
365 1.2.4.2 yamt {
366 1.2.4.2 yamt char buf[128];
367 1.2.4.2 yamt unsigned lineno;
368 1.2.4.2 yamt unsigned long version;
369 1.2.4.2 yamt char *s;
370 1.2.4.2 yamt char *fields[8];
371 1.2.4.2 yamt unsigned num;
372 1.2.4.2 yamt char *x;
373 1.2.4.2 yamt struct quotakey key;
374 1.2.4.2 yamt struct quotaval val;
375 1.2.4.2 yamt int ch;
376 1.2.4.2 yamt
377 1.2.4.2 yamt lineno = 0;
378 1.2.4.2 yamt if (fgets(buf, sizeof(buf), f) == NULL) {
379 1.2.4.2 yamt errx(EXIT_FAILURE, "%s: EOF before quotadump header", path);
380 1.2.4.2 yamt }
381 1.2.4.2 yamt lineno++;
382 1.2.4.2 yamt if (strncmp(buf, "@format netbsd-quota-dump v", 27) != 0) {
383 1.2.4.2 yamt errx(EXIT_FAILURE, "%s: Missing quotadump header", path);
384 1.2.4.2 yamt }
385 1.2.4.2 yamt s = buf+27;
386 1.2.4.2 yamt errno = 0;
387 1.2.4.2 yamt version = strtoul(s, &s, 10);
388 1.2.4.2 yamt if (errno) {
389 1.2.4.2 yamt errx(EXIT_FAILURE, "%s: Corrupted quotadump header", path);
390 1.2.4.2 yamt }
391 1.2.4.2 yamt s = skipws(s);
392 1.2.4.2 yamt if (*s != '\0') {
393 1.2.4.2 yamt errx(EXIT_FAILURE, "%s: Trash after quotadump header", path);
394 1.2.4.2 yamt }
395 1.2.4.2 yamt
396 1.2.4.2 yamt switch (version) {
397 1.2.4.2 yamt case 1: break;
398 1.2.4.2 yamt default:
399 1.2.4.2 yamt errx(EXIT_FAILURE, "%s: Unsupported quotadump version %lu",
400 1.2.4.2 yamt path, version);
401 1.2.4.2 yamt }
402 1.2.4.2 yamt
403 1.2.4.2 yamt while (fgets(buf, sizeof(buf), f)) {
404 1.2.4.2 yamt lineno++;
405 1.2.4.2 yamt if (buf[0] == '#') {
406 1.2.4.2 yamt continue;
407 1.2.4.2 yamt }
408 1.2.4.2 yamt if (!strncmp(buf, "@end", 4)) {
409 1.2.4.2 yamt s = skipws(buf+4);
410 1.2.4.2 yamt if (*s != '\0') {
411 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid @end tag",
412 1.2.4.2 yamt path, lineno);
413 1.2.4.2 yamt }
414 1.2.4.2 yamt break;
415 1.2.4.2 yamt }
416 1.2.4.2 yamt
417 1.2.4.2 yamt num = 0;
418 1.2.4.2 yamt for (s = strtok_r(buf, ws, &x);
419 1.2.4.2 yamt s != NULL;
420 1.2.4.2 yamt s = strtok_r(NULL, ws, &x)) {
421 1.2.4.2 yamt if (num < 8) {
422 1.2.4.2 yamt fields[num++] = s;
423 1.2.4.2 yamt } else {
424 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Too many fields",
425 1.2.4.2 yamt path, lineno);
426 1.2.4.2 yamt }
427 1.2.4.2 yamt }
428 1.2.4.2 yamt if (num < 8) {
429 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Not enough fields",
430 1.2.4.2 yamt path, lineno);
431 1.2.4.2 yamt }
432 1.2.4.2 yamt
433 1.2.4.2 yamt if (getidtype(fields[0], &key.qk_idtype)) {
434 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid/unknown ID type %s",
435 1.2.4.2 yamt path, lineno, fields[0]);
436 1.2.4.2 yamt }
437 1.2.4.2 yamt if (getid(fields[1], key.qk_idtype, &key.qk_id)) {
438 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid ID number %s",
439 1.2.4.2 yamt path, lineno, fields[1]);
440 1.2.4.2 yamt }
441 1.2.4.2 yamt if (getobjtype(fields[2], &key.qk_objtype)) {
442 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid/unknown object "
443 1.2.4.2 yamt "type %s",
444 1.2.4.2 yamt path, lineno, fields[2]);
445 1.2.4.2 yamt }
446 1.2.4.2 yamt
447 1.2.4.2 yamt if (getlimit(fields[3], &val.qv_hardlimit)) {
448 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid hard limit %s",
449 1.2.4.2 yamt path, lineno, fields[3]);
450 1.2.4.2 yamt }
451 1.2.4.2 yamt if (getlimit(fields[4], &val.qv_softlimit)) {
452 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid soft limit %s",
453 1.2.4.2 yamt path, lineno, fields[4]);
454 1.2.4.2 yamt }
455 1.2.4.2 yamt if (getlimit(fields[5], &val.qv_usage)) {
456 1.2.4.2 yamt /*
457 1.2.4.2 yamt * Make this nonfatal as it'll be ignored by
458 1.2.4.2 yamt * quota_put() anyway.
459 1.2.4.2 yamt */
460 1.2.4.2 yamt warnx("%s:%u: Invalid current usage %s",
461 1.2.4.2 yamt path, lineno, fields[5]);
462 1.2.4.2 yamt val.qv_usage = 0;
463 1.2.4.2 yamt }
464 1.2.4.2 yamt if (gettime(fields[6], &val.qv_expiretime)) {
465 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid expire time %s",
466 1.2.4.2 yamt path, lineno, fields[6]);
467 1.2.4.2 yamt }
468 1.2.4.2 yamt if (gettime(fields[7], &val.qv_grace)) {
469 1.2.4.2 yamt errx(EXIT_FAILURE, "%s:%u: Invalid grace period %s",
470 1.2.4.2 yamt path, lineno, fields[7]);
471 1.2.4.2 yamt }
472 1.2.4.2 yamt
473 1.2.4.2 yamt if (quota_put(qh, &key, &val)) {
474 1.2.4.2 yamt err(EXIT_FAILURE, "%s:%u: quota_put", path, lineno);
475 1.2.4.2 yamt }
476 1.2.4.2 yamt
477 1.2.4.2 yamt if (seenkeys != NULL) {
478 1.2.4.2 yamt qklist_add(seenkeys, &key);
479 1.2.4.2 yamt }
480 1.2.4.2 yamt }
481 1.2.4.2 yamt if (feof(f)) {
482 1.2.4.2 yamt return;
483 1.2.4.2 yamt }
484 1.2.4.2 yamt if (ferror(f)) {
485 1.2.4.2 yamt errx(EXIT_FAILURE, "%s: Read error", path);
486 1.2.4.2 yamt }
487 1.2.4.2 yamt /* not at EOF, not an error... what's left? */
488 1.2.4.2 yamt while (1) {
489 1.2.4.2 yamt ch = fgetc(f);
490 1.2.4.2 yamt if (ch == EOF)
491 1.2.4.2 yamt break;
492 1.2.4.2 yamt if (isws(ch)) {
493 1.2.4.2 yamt continue;
494 1.2.4.2 yamt }
495 1.2.4.2 yamt warnx("%s:%u: Trash after @end tag", path, lineno);
496 1.2.4.2 yamt }
497 1.2.4.2 yamt }
498 1.2.4.2 yamt
499 1.2.4.2 yamt ////////////////////////////////////////////////////////////
500 1.2.4.2 yamt // top level control logic
501 1.2.4.2 yamt
502 1.2.4.2 yamt __dead static void
503 1.2.4.2 yamt usage(void)
504 1.2.4.2 yamt {
505 1.2.4.2 yamt fprintf(stderr, "usage: %s [-d] volume [dump-file]\n",
506 1.2.4.2 yamt getprogname());
507 1.2.4.2 yamt exit(EXIT_FAILURE);
508 1.2.4.2 yamt }
509 1.2.4.2 yamt
510 1.2.4.2 yamt int
511 1.2.4.2 yamt main(int argc, char *argv[])
512 1.2.4.2 yamt {
513 1.2.4.2 yamt int ch;
514 1.2.4.2 yamt FILE *f;
515 1.2.4.2 yamt struct quotahandle *qh;
516 1.2.4.2 yamt
517 1.2.4.2 yamt int dflag = 0;
518 1.2.4.2 yamt const char *volume = NULL;
519 1.2.4.2 yamt const char *dumpfile = NULL;
520 1.2.4.2 yamt
521 1.2.4.2 yamt while ((ch = getopt(argc, argv, "d")) != -1) {
522 1.2.4.2 yamt switch (ch) {
523 1.2.4.2 yamt case 'd': dflag = 1; break;
524 1.2.4.2 yamt default: usage(); break;
525 1.2.4.2 yamt }
526 1.2.4.2 yamt }
527 1.2.4.2 yamt
528 1.2.4.2 yamt if (optind >= argc) {
529 1.2.4.2 yamt usage();
530 1.2.4.2 yamt }
531 1.2.4.2 yamt volume = argv[optind++];
532 1.2.4.2 yamt if (optind < argc) {
533 1.2.4.2 yamt dumpfile = argv[optind++];
534 1.2.4.2 yamt }
535 1.2.4.2 yamt if (optind < argc) {
536 1.2.4.2 yamt usage();
537 1.2.4.2 yamt }
538 1.2.4.2 yamt
539 1.2.4.2 yamt qh = quota_open(volume);
540 1.2.4.2 yamt if (qh == NULL) {
541 1.2.4.2 yamt err(EXIT_FAILURE, "quota_open: %s", volume);
542 1.2.4.2 yamt }
543 1.2.4.2 yamt if (dumpfile != NULL) {
544 1.2.4.2 yamt f = fopen(dumpfile, "r");
545 1.2.4.2 yamt if (f == NULL) {
546 1.2.4.2 yamt err(EXIT_FAILURE, "%s", dumpfile);
547 1.2.4.2 yamt }
548 1.2.4.2 yamt } else {
549 1.2.4.2 yamt f = stdin;
550 1.2.4.2 yamt dumpfile = "<stdin>";
551 1.2.4.2 yamt }
552 1.2.4.2 yamt
553 1.2.4.2 yamt maketables(qh);
554 1.2.4.2 yamt
555 1.2.4.2 yamt if (dflag) {
556 1.2.4.2 yamt struct qklist *seenkeys, *dropkeys;
557 1.2.4.2 yamt
558 1.2.4.2 yamt seenkeys = qklist_create();
559 1.2.4.2 yamt dropkeys = qklist_create();
560 1.2.4.2 yamt
561 1.2.4.2 yamt readdumpfile(qh, f, dumpfile, seenkeys);
562 1.2.4.2 yamt qklist_sort(seenkeys);
563 1.2.4.2 yamt scankeys(qh, seenkeys, dropkeys);
564 1.2.4.2 yamt purge(qh, dropkeys);
565 1.2.4.2 yamt
566 1.2.4.2 yamt qklist_destroy(dropkeys);
567 1.2.4.2 yamt qklist_destroy(seenkeys);
568 1.2.4.2 yamt } else {
569 1.2.4.2 yamt readdumpfile(qh, f, dumpfile, NULL);
570 1.2.4.2 yamt }
571 1.2.4.2 yamt
572 1.2.4.2 yamt if (f != stdin) {
573 1.2.4.2 yamt fclose(f);
574 1.2.4.2 yamt }
575 1.2.4.2 yamt quota_close(qh);
576 1.2.4.2 yamt return EXIT_SUCCESS;
577 1.2.4.2 yamt }
578