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