admin.c revision 32785
1/* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License as 6 * specified in the README file that comes with the CVS source distribution. 7 * 8 * Administration ("cvs admin") 9 * 10 */ 11 12#include "cvs.h" 13#ifdef CVS_ADMIN_GROUP 14#include <grp.h> 15#endif 16#include <assert.h> 17 18static Dtype admin_dirproc PROTO ((void *callerdat, char *dir, 19 char *repos, char *update_dir, 20 List *entries)); 21static int admin_fileproc PROTO ((void *callerdat, struct file_info *finfo)); 22 23static const char *const admin_usage[] = 24{ 25 "Usage: %s %s rcs-options files...\n", 26 "(Specify the --help global option for a list of other help options)\n", 27 NULL 28}; 29 30/* This structure is used to pass information through start_recursion. */ 31struct admin_data 32{ 33 /* Set default branch (-b). It is "-b" followed by the value 34 given, or NULL if not specified, or merely "-b" if -b is 35 specified without a value. */ 36 char *branch; 37 38 /* Set comment leader (-c). It is "-c" followed by the value 39 given, or NULL if not specified. The comment leader is 40 relevant only for old versions of RCS, but we let people set it 41 anyway. */ 42 char *comment; 43 44 /* Set strict locking (-L). */ 45 int set_strict; 46 47 /* Set nonstrict locking (-U). */ 48 int set_nonstrict; 49 50 /* Delete revisions (-o). It is "-o" followed by the value specified. */ 51 char *delete_revs; 52 53 /* Keyword substitution mode (-k), e.g. "-kb". */ 54 char *kflag; 55 56 /* Description (-t). See sanity.sh for various moanings about 57 files and stdin and such. "" if -t specified without an 58 argument. It is "-t" followed by the argument. */ 59 char *desc; 60 61 /* Interactive (-I). Problematic with client/server. */ 62 int interactive; 63 64 /* Quiet (-q). Not the same as the global -q option, which is a bit 65 on the confusing side, perhaps. */ 66 int quiet; 67 68 /* This is the cheesy part. It is a vector with the options which 69 we don't deal with above (e.g. "-afoo" "-abar,baz"). In the future 70 this presumably will be replaced by other variables which break 71 out the data in a more convenient fashion. AV as well as each of 72 the strings it points to is malloc'd. */ 73 int ac; 74 char **av; 75 int av_alloc; 76}; 77 78/* Add an argument. OPT is the option letter, e.g. 'a'. ARG is the 79 argument to that option, or NULL if omitted (whether NULL can actually 80 happen depends on whether the option was specified as optional to 81 getopt). */ 82static void 83arg_add (dat, opt, arg) 84 struct admin_data *dat; 85 int opt; 86 char *arg; 87{ 88 char *newelt = xmalloc ((arg == NULL ? 0 : strlen (arg)) + 3); 89 strcpy (newelt, "-"); 90 newelt[1] = opt; 91 if (arg == NULL) 92 newelt[2] = '\0'; 93 else 94 strcpy (newelt + 2, arg); 95 96 if (dat->av_alloc == 0) 97 { 98 dat->av_alloc = 1; 99 dat->av = (char **) xmalloc (dat->av_alloc * sizeof (*dat->av)); 100 } 101 else if (dat->ac >= dat->av_alloc) 102 { 103 dat->av_alloc *= 2; 104 dat->av = (char **) xrealloc (dat->av, 105 dat->av_alloc * sizeof (*dat->av)); 106 } 107 dat->av[dat->ac++] = newelt; 108} 109 110int 111admin (argc, argv) 112 int argc; 113 char **argv; 114{ 115 int err; 116#ifdef CVS_ADMIN_GROUP 117 struct group *grp; 118 struct group *getgrnam(); 119#endif 120 struct admin_data admin_data; 121 int c; 122 int i; 123 124 if (argc <= 1) 125 usage (admin_usage); 126 127#ifdef CVS_ADMIN_GROUP 128 grp = getgrnam(CVS_ADMIN_GROUP); 129 /* skip usage right check if group CVS_ADMIN_GROUP does not exist */ 130 if (grp != NULL) 131 { 132 char *me = getcaller(); 133 char **grnam = grp->gr_mem; 134 int denied = 1; 135 136 while (*grnam) 137 { 138 if (strcmp(*grnam, me) == 0) 139 { 140 denied = 0; 141 break; 142 } 143 grnam++; 144 } 145 146 if (denied) 147 error (1, 0, "usage is restricted to members of the group %s", 148 CVS_ADMIN_GROUP); 149 } 150#endif 151 152 wrap_setup (); 153 154 memset (&admin_data, 0, sizeof admin_data); 155 156 /* TODO: get rid of `-' switch notation in admin_data. For 157 example, admin_data->branch should be not `-bfoo' but simply `foo'. */ 158 159 optind = 0; 160 while ((c = getopt (argc, argv, 161 "+ib::c:a:A:e:l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1) 162 { 163 switch (c) 164 { 165 case 'i': 166 /* This has always been documented as useless in cvs.texinfo 167 and it really is--admin_fileproc silently does nothing 168 if vers->vn_user is NULL. */ 169 error (0, 0, "the -i option to admin is not supported"); 170 error (0, 0, "run add or import to create an RCS file"); 171 goto usage_error; 172 173 case 'b': 174 if (admin_data.branch != NULL) 175 { 176 error (0, 0, "duplicate 'b' option"); 177 goto usage_error; 178 } 179 if (optarg == NULL) 180 admin_data.branch = xstrdup ("-b"); 181 else 182 { 183 admin_data.branch = xmalloc (strlen (optarg) + 5); 184 strcpy (admin_data.branch, "-b"); 185 strcat (admin_data.branch, optarg); 186 } 187 break; 188 189 case 'c': 190 if (admin_data.comment != NULL) 191 { 192 error (0, 0, "duplicate 'c' option"); 193 goto usage_error; 194 } 195 admin_data.comment = xmalloc (strlen (optarg) + 5); 196 strcpy (admin_data.comment, "-c"); 197 strcat (admin_data.comment, optarg); 198 break; 199 200 case 'a': 201 arg_add (&admin_data, 'a', optarg); 202 break; 203 204 case 'A': 205 /* In the client/server case, this is cheesy because 206 we just pass along the name of the RCS file, which 207 then will want to exist on the server. This is 208 accidental; having the client specify a pathname on 209 the server is not a design feature of the protocol. */ 210 arg_add (&admin_data, 'A', optarg); 211 break; 212 213 case 'e': 214 arg_add (&admin_data, 'e', optarg); 215 break; 216 217 case 'l': 218 /* Note that multiple -l options are legal. */ 219 arg_add (&admin_data, 'l', optarg); 220 break; 221 222 case 'u': 223 /* Note that multiple -u options are legal. */ 224 arg_add (&admin_data, 'u', optarg); 225 break; 226 227 case 'L': 228 /* Probably could also complain if -L is specified multiple 229 times, although RCS doesn't and I suppose it is reasonable 230 just to have it mean the same as a single -L. */ 231 if (admin_data.set_nonstrict) 232 { 233 error (0, 0, "-U and -L are incompatible"); 234 goto usage_error; 235 } 236 admin_data.set_strict = 1; 237 break; 238 239 case 'U': 240 /* Probably could also complain if -U is specified multiple 241 times, although RCS doesn't and I suppose it is reasonable 242 just to have it mean the same as a single -U. */ 243 if (admin_data.set_strict) 244 { 245 error (0, 0, "-U and -L are incompatible"); 246 goto usage_error; 247 } 248 admin_data.set_nonstrict = 1; 249 break; 250 251 case 'n': 252 /* Mostly similar to cvs tag. Could also be parsing 253 the syntax of optarg, although for now we just pass 254 it to rcs as-is. Note that multiple -n options are 255 legal. */ 256 arg_add (&admin_data, 'n', optarg); 257 break; 258 259 case 'N': 260 /* Mostly similar to cvs tag. Could also be parsing 261 the syntax of optarg, although for now we just pass 262 it to rcs as-is. Note that multiple -N options are 263 legal. */ 264 arg_add (&admin_data, 'N', optarg); 265 break; 266 267 case 'm': 268 /* Change log message. Could also be parsing the syntax 269 of optarg, although for now we just pass it to rcs 270 as-is. Note that multiple -m options are legal. */ 271 arg_add (&admin_data, 'm', optarg); 272 break; 273 274 case 'o': 275 /* Delete revisions. Probably should also be parsing the 276 syntax of optarg, so that the client can give errors 277 rather than making the server take care of that. 278 Other than that I'm not sure whether it matters much 279 whether we parse it here or in admin_fileproc. 280 281 Note that multiple -o options are illegal, in RCS 282 as well as here. */ 283 284 if (admin_data.delete_revs != NULL) 285 { 286 error (0, 0, "duplicate '-o' option"); 287 goto usage_error; 288 } 289 admin_data.delete_revs = xmalloc (strlen (optarg) + 5); 290 strcpy (admin_data.delete_revs, "-o"); 291 strcat (admin_data.delete_revs, optarg); 292 break; 293 294 case 's': 295 /* Note that multiple -s options are legal. */ 296 arg_add (&admin_data, 's', optarg); 297 break; 298 299 case 't': 300 if (admin_data.desc != NULL) 301 { 302 error (0, 0, "duplicate 't' option"); 303 goto usage_error; 304 } 305 if (optarg == NULL) 306 admin_data.desc = xstrdup ("-t"); 307 else 308 { 309 admin_data.desc = xmalloc (strlen (optarg) + 5); 310 strcpy (admin_data.desc, "-t"); 311 strcat (admin_data.desc, optarg); 312 } 313 break; 314 315 case 'I': 316 /* At least in RCS this can be specified several times, 317 with the same meaning as being specified once. */ 318 admin_data.interactive = 1; 319 break; 320 321 case 'q': 322 admin_data.quiet = 1; 323 break; 324 325 case 'x': 326 error (0, 0, "the -x option has never done anything useful"); 327 error (0, 0, "RCS files in CVS always end in ,v"); 328 goto usage_error; 329 330 case 'V': 331 /* No longer supported. */ 332 error (0, 0, "the `-V' option is obsolete"); 333 break; 334 335 case 'k': 336 if (admin_data.kflag != NULL) 337 { 338 error (0, 0, "duplicate '-k' option"); 339 goto usage_error; 340 } 341 admin_data.kflag = RCS_check_kflag (optarg); 342 break; 343 default: 344 case '?': 345 /* getopt will have printed an error message. */ 346 347 usage_error: 348 /* Don't use command_name; it might be "server". */ 349 error (1, 0, "specify %s -H admin for usage information", 350 program_name); 351 } 352 } 353 argc -= optind; 354 argv += optind; 355 356 for (i = 0; i < admin_data.ac; ++i) 357 { 358 assert (admin_data.av[i][0] == '-'); 359 switch (admin_data.av[i][1]) 360 { 361 case 'm': 362 case 'l': 363 case 'u': 364 check_numeric (&admin_data.av[i][2], argc, argv); 365 break; 366 default: 367 break; 368 } 369 } 370 if (admin_data.branch != NULL) 371 check_numeric (admin_data.branch + 2, argc, argv); 372 if (admin_data.delete_revs != NULL) 373 { 374 char *p; 375 376 check_numeric (admin_data.delete_revs + 2, argc, argv); 377 p = strchr (admin_data.delete_revs + 2, ':'); 378 if (p != NULL && isdigit (p[1])) 379 check_numeric (p + 1, argc, argv); 380 else if (p != NULL && p[1] == ':' && isdigit(p[2])) 381 check_numeric (p + 2, argc, argv); 382 } 383 384#ifdef CLIENT_SUPPORT 385 if (client_active) 386 { 387 /* We're the client side. Fire up the remote server. */ 388 start_server (); 389 390 ign_setup (); 391 392 /* Note that option_with_arg does not work for us, because some 393 of the options must be sent without a space between the option 394 and its argument. */ 395 if (admin_data.interactive) 396 error (1, 0, "-I option not useful with client/server"); 397 if (admin_data.branch != NULL) 398 send_arg (admin_data.branch); 399 if (admin_data.comment != NULL) 400 send_arg (admin_data.comment); 401 if (admin_data.set_strict) 402 send_arg ("-L"); 403 if (admin_data.set_nonstrict) 404 send_arg ("-U"); 405 if (admin_data.delete_revs != NULL) 406 send_arg (admin_data.delete_revs); 407 if (admin_data.desc != NULL) 408 send_arg (admin_data.desc); 409 if (admin_data.quiet) 410 send_arg ("-q"); 411 if (admin_data.kflag != NULL) 412 send_arg (admin_data.kflag); 413 414 for (i = 0; i < admin_data.ac; ++i) 415 send_arg (admin_data.av[i]); 416 417 send_file_names (argc, argv, SEND_EXPAND_WILD); 418 send_files (argc, argv, 0, 0, SEND_NO_CONTENTS); 419 send_to_server ("admin\012", 0); 420 err = get_responses_and_close (); 421 goto return_it; 422 } 423#endif /* CLIENT_SUPPORT */ 424 425 lock_tree_for_write (argc, argv, 0, 0); 426 427 err = start_recursion (admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc, 428 (DIRLEAVEPROC) NULL, (void *)&admin_data, 429 argc, argv, 0, 430 W_LOCAL, 0, 0, (char *) NULL, 1); 431 Lock_Cleanup (); 432 433 return_it: 434 if (admin_data.branch != NULL) 435 free (admin_data.branch); 436 if (admin_data.comment != NULL) 437 free (admin_data.comment); 438 if (admin_data.delete_revs != NULL) 439 free (admin_data.delete_revs); 440 if (admin_data.kflag != NULL) 441 free (admin_data.kflag); 442 if (admin_data.desc != NULL) 443 free (admin_data.desc); 444 for (i = 0; i < admin_data.ac; ++i) 445 free (admin_data.av[i]); 446 if (admin_data.av != NULL) 447 free (admin_data.av); 448 449 return (err); 450} 451 452/* 453 * Called to run "rcs" on a particular file. 454 */ 455/* ARGSUSED */ 456static int 457admin_fileproc (callerdat, finfo) 458 void *callerdat; 459 struct file_info *finfo; 460{ 461 struct admin_data *admin_data = (struct admin_data *) callerdat; 462 Vers_TS *vers; 463 char *version; 464 int i; 465 int status = 0; 466 RCSNode *rcs, *rcs2; 467 468 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); 469 470 version = vers->vn_user; 471 if (version == NULL) 472 goto exitfunc; 473 else if (strcmp (version, "0") == 0) 474 { 475 error (0, 0, "cannot admin newly added file `%s'", finfo->file); 476 goto exitfunc; 477 } 478 479 rcs = vers->srcfile; 480 if (rcs->flags & PARTIAL) 481 RCS_reparsercsfile (rcs, NULL); 482 483 status = 0; 484 485 if (!admin_data->quiet) 486 { 487 cvs_output ("RCS file: ", 0); 488 cvs_output (rcs->path, 0); 489 cvs_output ("\n", 1); 490 } 491 492 if (admin_data->branch != NULL) 493 RCS_setbranch (rcs, (admin_data->branch[2] == '\0' 494 ? NULL 495 : admin_data->branch + 2)); 496 if (admin_data->comment != NULL) 497 { 498 if (rcs->comment != NULL) 499 free (rcs->comment); 500 rcs->comment = xstrdup (admin_data->comment + 2); 501 } 502 if (admin_data->set_strict) 503 rcs->strict_locks = 1; 504 if (admin_data->set_nonstrict) 505 rcs->strict_locks = 0; 506 if (admin_data->delete_revs != NULL) 507 { 508 char *s, *t, *rev1, *rev2; 509 /* Set for :, clear for ::. */ 510 int inclusive; 511 char *t2; 512 513 s = admin_data->delete_revs + 2; 514 inclusive = 1; 515 t = strchr (s, ':'); 516 if (t != NULL) 517 { 518 if (t[1] == ':') 519 { 520 inclusive = 0; 521 t2 = t + 2; 522 } 523 else 524 t2 = t + 1; 525 } 526 527 /* Note that we don't support '-' for ranges. RCS considers it 528 obsolete and it is problematic with tags containing '-'. "cvs log" 529 has made the same decision. */ 530 531 if (t == NULL) 532 { 533 /* -orev */ 534 rev1 = xstrdup (s); 535 rev2 = xstrdup (s); 536 } 537 else if (t == s) 538 { 539 /* -o:rev2 */ 540 rev1 = NULL; 541 rev2 = xstrdup (t2); 542 } 543 else 544 { 545 *t = '\0'; 546 rev1 = xstrdup (s); 547 *t = ':'; /* probably unnecessary */ 548 if (*t2 == '\0') 549 /* -orev1: */ 550 rev2 = NULL; 551 else 552 /* -orev1:rev2 */ 553 rev2 = xstrdup (t2); 554 } 555 556 if (rev1 == NULL && rev2 == NULL) 557 { 558 /* RCS segfaults if `-o:' is given */ 559 error (0, 0, "no valid revisions specified in `%s' option", 560 admin_data->delete_revs); 561 status = 1; 562 } 563 else 564 { 565 status |= RCS_delete_revs (rcs, rev1, rev2, inclusive); 566 if (rev1) 567 free (rev1); 568 if (rev2) 569 free (rev2); 570 } 571 } 572 if (admin_data->desc != NULL) 573 { 574 free (rcs->desc); 575 rcs->desc = NULL; 576 if (admin_data->desc[2] == '-') 577 rcs->desc = xstrdup (admin_data->desc + 3); 578 else 579 { 580 char *descfile = admin_data->desc + 2; 581 size_t bufsize = 0; 582 size_t len; 583 584 /* If -t specified with no argument, read from stdin. */ 585 if (*descfile == '\0') 586 descfile = NULL; 587 get_file (descfile, descfile, "r", &rcs->desc, &bufsize, &len); 588 } 589 } 590 if (admin_data->kflag != NULL) 591 { 592 char *kflag = admin_data->kflag + 2; 593 if (!rcs->expand || strcmp (rcs->expand, kflag) != 0) 594 { 595 if (rcs->expand) 596 free (rcs->expand); 597 rcs->expand = xstrdup (kflag); 598 } 599 } 600 601 /* Handle miscellaneous options. TODO: decide whether any or all 602 of these should have their own fields in the admin_data 603 structure. */ 604 for (i = 0; i < admin_data->ac; ++i) 605 { 606 char *arg; 607 char *p, *rev, *revnum, *tag, *msg; 608 char **users; 609 int argc, u; 610 Node *n; 611 RCSVers *delta; 612 613 arg = admin_data->av[i]; 614 switch (arg[1]) 615 { 616 case 'a': /* fall through */ 617 case 'e': 618 line2argv (&argc, &users, arg + 2, " ,\t\n"); 619 if (arg[1] == 'a') 620 for (u = 0; u < argc; ++u) 621 RCS_addaccess (rcs, users[u]); 622 else 623 for (u = 0; u < argc; ++u) 624 RCS_delaccess (rcs, users[u]); 625 free_names (&argc, users); 626 break; 627 case 'A': 628 629 /* See admin-19a-admin and friends in sanity.sh for 630 relative pathnames. It makes sense to think in 631 terms of a syntax which give pathnames relative to 632 the repository or repository corresponding to the 633 current directory or some such (and perhaps don't 634 include ,v), but trying to worry about such things 635 is a little pointless unless you first worry about 636 whether "cvs admin -A" as a whole makes any sense 637 (currently probably not, as access lists don't 638 affect the behavior of CVS). */ 639 640 rcs2 = RCS_parsercsfile (arg + 2); 641 if (rcs2 == NULL) 642 error (1, 0, "cannot continue"); 643 644 p = xstrdup (RCS_getaccess (rcs2)); 645 line2argv (&argc, &users, p, " \t\n"); 646 free (p); 647 freercsnode (&rcs2); 648 649 for (u = 0; u < argc; ++u) 650 RCS_addaccess (rcs, users[u]); 651 free_names (&argc, users); 652 break; 653 case 'n': /* fall through */ 654 case 'N': 655 if (arg[2] == '\0') 656 { 657 cvs_outerr ("missing symbolic name after ", 0); 658 cvs_outerr (arg, 0); 659 cvs_outerr ("\n", 1); 660 break; 661 } 662 p = strchr (arg, ':'); 663 if (p == NULL) 664 { 665 if (RCS_deltag (rcs, arg + 2) != 0) 666 { 667 error (0, 0, "%s: Symbolic name %s is undefined.", 668 rcs->path, 669 arg + 2); 670 status = 1; 671 continue; 672 } 673 break; 674 } 675 *p = '\0'; 676 tag = xstrdup (arg + 2); 677 *p++ = ':'; 678 679 /* Option `n' signals an error if this tag is already bound. */ 680 if (arg[1] == 'n') 681 { 682 n = findnode (RCS_symbols (rcs), tag); 683 if (n != NULL) 684 { 685 error (0, 0, 686 "%s: symbolic name %s already bound to %s", 687 rcs->path, 688 tag, n->data); 689 status = 1; 690 continue; 691 } 692 } 693 694 /* Expand rev if necessary. */ 695 rev = RCS_gettag (rcs, p, 0, NULL); 696 RCS_settag (rcs, tag, rev); 697 if (rev != NULL) 698 free (rev); 699 free (tag); 700 break; 701 case 's': 702 p = strchr (arg, ':'); 703 if (p == NULL) 704 { 705 tag = xstrdup (arg + 2); 706 rev = RCS_head (rcs); 707 } 708 else 709 { 710 *p = '\0'; 711 tag = xstrdup (arg + 2); 712 *p++ = ':'; 713 rev = xstrdup (p); 714 } 715 revnum = RCS_gettag (rcs, rev, 0, NULL); 716 free (rev); 717 if (revnum != NULL) 718 n = findnode (rcs->versions, revnum); 719 if (revnum == NULL || n == NULL) 720 { 721 error (0, 0, 722 "%s: can't set state of nonexisting revision %s", 723 rcs->path, 724 rev); 725 if (revnum != NULL) 726 free (revnum); 727 status = 1; 728 continue; 729 } 730 delta = (RCSVers *) n->data; 731 free (delta->state); 732 delta->state = tag; 733 break; 734 735 case 'm': 736 p = strchr (arg, ':'); 737 if (p == NULL) 738 { 739 error (0, 0, "%s: -m option lacks revision number", 740 rcs->path); 741 status = 1; 742 continue; 743 } 744 *p = '\0'; 745 rev = RCS_gettag (rcs, arg + 2, 0, NULL); 746 if (rev == NULL) 747 { 748 error (0, 0, "%s: no such revision %s", rcs->path, rev); 749 status = 1; 750 continue; 751 } 752 *p++ = ':'; 753 msg = p; 754 755 n = findnode (rcs->versions, rev); 756 delta = (RCSVers *) n->data; 757 if (delta->text == NULL) 758 { 759 delta->text = (Deltatext *) xmalloc (sizeof (Deltatext)); 760 memset ((void *) delta->text, 0, sizeof (Deltatext)); 761 } 762 delta->text->version = xstrdup (delta->version); 763 delta->text->log = make_message_rcslegal (msg); 764 break; 765 766 case 'l': 767 status |= RCS_lock (rcs, arg[2] ? arg + 2 : NULL, 0); 768 break; 769 case 'u': 770 status |= RCS_unlock (rcs, arg[2] ? arg + 2 : NULL, 0); 771 break; 772 default: assert(0); /* can't happen */ 773 } 774 } 775 776 /* TODO: reconcile the weird discrepancies between 777 admin_data->quiet and quiet. */ 778 if (status == 0) 779 { 780 RCS_rewrite (rcs, NULL, NULL); 781 if (!admin_data->quiet) 782 cvs_output ("done\n", 5); 783 } 784 else 785 { 786 /* Note that this message should only occur after another 787 message has given a more specific error. The point of this 788 additional message is to make it clear that the previous problems 789 caused CVS to forget about the idea of modifying the RCS file. */ 790 error (0, 0, "cannot modify RCS file for `%s'", finfo->file); 791 792 /* Upon failure, we want to abandon any changes made to the 793 RCS data structure. Forcing a reparse does the trick, 794 but leaks memory and is kludgey. Should we export 795 free_rcsnode_contents for this purpose? */ 796 RCS_reparsercsfile (rcs, NULL); 797 } 798 799 exitfunc: 800 freevers_ts (&vers); 801 return status; 802} 803 804/* 805 * Print a warm fuzzy message 806 */ 807/* ARGSUSED */ 808static Dtype 809admin_dirproc (callerdat, dir, repos, update_dir, entries) 810 void *callerdat; 811 char *dir; 812 char *repos; 813 char *update_dir; 814 List *entries; 815{ 816 if (!quiet) 817 error (0, 0, "Administrating %s", update_dir); 818 return (R_PROCESS); 819} 820