Unused variable warning fixes
[openafs.git] / src / venus / fs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <ctype.h>
17
18 #include <afs/afs_consts.h>
19 #include <afs/afs_args.h>
20 #include <rx/xdr.h>
21 #include <afs/vice.h>
22 #include <afs/venus.h>
23 #include <afs/com_err.h>
24 #include <afs/afs_consts.h>
25
26 #undef VIRTUE
27 #undef VICE
28 #include "afs/prs_fs.h"
29 #include <afs/afsint.h>
30 #include <afs/cellconfig.h>
31 #include <ubik.h>
32 #include <rx/rxkad.h>
33 #include <rx/rx_globals.h>
34 #include <afs/vldbint.h>
35 #include <afs/volser.h>
36 #include <afs/vlserver.h>
37 #include <afs/cmd.h>
38 #include <afs/com_err.h>
39 #include <afs/ptclient.h>
40 #include <afs/ptuser.h>
41 #include <afs/afsutil.h>
42 #include <afs/sys_prototypes.h>
43
44 #define MAXNAME 100
45 #define MAXINSIZE 1300          /* pioctl complains if data is larger than this */
46 #define VMSGSIZE 128            /* size of msg buf in volume hdr */
47
48 static char space[AFS_PIOCTL_MAXSIZE];
49 static char tspace[1024];
50 static struct ubik_client *uclient;
51
52 static int GetClientAddrsCmd(struct cmd_syndesc *, void *);
53 static int SetClientAddrsCmd(struct cmd_syndesc *, void *);
54 static int FlushMountCmd(struct cmd_syndesc *, void *);
55 static int RxStatProcCmd(struct cmd_syndesc *, void *);
56 static int RxStatPeerCmd(struct cmd_syndesc *, void *);
57 static int GetFidCmd(struct cmd_syndesc *, void *);
58 static int UuidCmd(struct cmd_syndesc *, void *);
59
60 static char pn[] = "fs";
61 static int rxInitDone = 0;
62
63 struct AclEntry;
64 struct Acl;
65 static void ZapList(struct AclEntry *);
66 static int PruneList(struct AclEntry **, int);
67 static int CleanAcl(struct Acl *, char *);
68 static int SetVolCmd(struct cmd_syndesc *as, void *arock);
69 static int GetCellName(char *, struct afsconf_cell *);
70 static int VLDBInit(int, struct afsconf_cell *);
71 static void Die(int, char *);
72
73 /*
74  * Character to use between name and rights in printed representation for
75  * DFS ACL's.
76  */
77 #define DFS_SEPARATOR   ' '
78
79 typedef char sec_rgy_name_t[1025];      /* A DCE definition */
80
81 struct Acl {
82     int dfs;                    /* Originally true if a dfs acl; now also the type
83                                  * of the acl (1, 2, or 3, corresponding to object,
84                                  * initial dir, or initial object). */
85     sec_rgy_name_t cell;        /* DFS cell name */
86     int nplus;
87     int nminus;
88     struct AclEntry *pluslist;
89     struct AclEntry *minuslist;
90 };
91
92 struct AclEntry {
93     struct AclEntry *next;
94     char name[MAXNAME];
95     afs_int32 rights;
96 };
97
98 struct vcxstat2 {
99     afs_int32 callerAccess;
100     afs_int32 cbExpires;
101     afs_int32 anyAccess;
102     char mvstat;
103 };
104
105 static void
106 ZapAcl(struct Acl *acl)
107 {
108     if (!acl)
109         return;
110     ZapList(acl->pluslist);
111     ZapList(acl->minuslist);
112     free(acl);
113 }
114
115 static int
116 foldcmp(char *a, char *b)
117 {
118     char t, u;
119     while (1) {
120         t = *a++;
121         u = *b++;
122         if (t >= 'A' && t <= 'Z')
123             t += 0x20;
124         if (u >= 'A' && u <= 'Z')
125             u += 0x20;
126         if (t != u)
127             return 1;
128         if (t == 0)
129             return 0;
130     }
131 }
132
133 /*
134  * Mods for the AFS/DFS protocol translator.
135  *
136  * DFS rights. It's ugly to put these definitions here, but they
137  * *cannot* change, because they're part of the wire protocol.
138  * In any event, the protocol translator will guarantee these
139  * assignments for AFS cache managers.
140  */
141 #define DFS_READ          0x01
142 #define DFS_WRITE         0x02
143 #define DFS_EXECUTE       0x04
144 #define DFS_CONTROL       0x08
145 #define DFS_INSERT        0x10
146 #define DFS_DELETE        0x20
147
148 /* the application definable ones (backwards from AFS) */
149 #define DFS_USR0 0x80000000     /* "A" bit */
150 #define DFS_USR1 0x40000000     /* "B" bit */
151 #define DFS_USR2 0x20000000     /* "C" bit */
152 #define DFS_USR3 0x10000000     /* "D" bit */
153 #define DFS_USR4 0x08000000     /* "E" bit */
154 #define DFS_USR5 0x04000000     /* "F" bit */
155 #define DFS_USR6 0x02000000     /* "G" bit */
156 #define DFS_USR7 0x01000000     /* "H" bit */
157 #define DFS_USRALL      (DFS_USR0 | DFS_USR1 | DFS_USR2 | DFS_USR3 |\
158                          DFS_USR4 | DFS_USR5 | DFS_USR6 | DFS_USR7)
159
160 /*
161  * Offset of -id switch in command structure for various commands.
162  * The -if switch is the next switch always.
163  */
164 static int parm_setacl_id, parm_copyacl_id, parm_listacl_id;
165
166 /*
167  * Determine whether either the -id or -if switches are present, and
168  * return 0, 1 or 2, as appropriate. Abort if both switches are present.
169  */
170 /*    int id;   Offset of -id switch; -if is next switch */
171 static int
172 getidf(struct cmd_syndesc *as, int id)
173 {
174     int idf = 0;
175
176     if (as->parms[id].items) {
177         idf |= 1;
178     }
179     if (as->parms[id + 1].items) {
180         idf |= 2;
181     }
182     if (idf == 3) {
183         fprintf(stderr,
184                 "%s: you may specify either -id or -if, but not both switches\n",
185                 pn);
186         exit(1);
187     }
188     return idf;
189 }
190
191 static int
192 PRights(afs_int32 arights, int dfs)
193 {
194     if (!dfs) {
195         if (arights & PRSFS_READ)
196             printf("r");
197         if (arights & PRSFS_LOOKUP)
198             printf("l");
199         if (arights & PRSFS_INSERT)
200             printf("i");
201         if (arights & PRSFS_DELETE)
202             printf("d");
203         if (arights & PRSFS_WRITE)
204             printf("w");
205         if (arights & PRSFS_LOCK)
206             printf("k");
207         if (arights & PRSFS_ADMINISTER)
208             printf("a");
209         if (arights & PRSFS_USR0)
210             printf("A");
211         if (arights & PRSFS_USR1)
212             printf("B");
213         if (arights & PRSFS_USR2)
214             printf("C");
215         if (arights & PRSFS_USR3)
216             printf("D");
217         if (arights & PRSFS_USR4)
218             printf("E");
219         if (arights & PRSFS_USR5)
220             printf("F");
221         if (arights & PRSFS_USR6)
222             printf("G");
223         if (arights & PRSFS_USR7)
224             printf("H");
225     } else {
226         if (arights & DFS_READ)
227             printf("r");
228         else
229             printf("-");
230         if (arights & DFS_WRITE)
231             printf("w");
232         else
233             printf("-");
234         if (arights & DFS_EXECUTE)
235             printf("x");
236         else
237             printf("-");
238         if (arights & DFS_CONTROL)
239             printf("c");
240         else
241             printf("-");
242         if (arights & DFS_INSERT)
243             printf("i");
244         else
245             printf("-");
246         if (arights & DFS_DELETE)
247             printf("d");
248         else
249             printf("-");
250         if (arights & (DFS_USRALL))
251             printf("+");
252         if (arights & DFS_USR0)
253             printf("A");
254         if (arights & DFS_USR1)
255             printf("B");
256         if (arights & DFS_USR2)
257             printf("C");
258         if (arights & DFS_USR3)
259             printf("D");
260         if (arights & DFS_USR4)
261             printf("E");
262         if (arights & DFS_USR5)
263             printf("F");
264         if (arights & DFS_USR6)
265             printf("G");
266         if (arights & DFS_USR7)
267             printf("H");
268     }
269     return 0;
270 }
271
272 /* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */
273 static int
274 InAFS(char *apath)
275 {
276     struct ViceIoctl blob;
277     afs_int32 code;
278
279     blob.in_size = 0;
280     blob.out_size = AFS_PIOCTL_MAXSIZE;
281     blob.out = space;
282
283     code = pioctl(apath, VIOC_FILE_CELL_NAME, &blob, 1);
284     if (code) {
285         if ((errno == EINVAL) || (errno == ENOENT))
286             return 0;
287     }
288     return 1;
289 }
290
291 /* return a static pointer to a buffer */
292 static char *
293 Parent(char *apath)
294 {
295     char *tp;
296     strlcpy(tspace, apath, sizeof(tspace));
297     tp = strrchr(tspace, '/');
298     if (tp == (char *)tspace)
299         tp++;
300     else if (tp == (char *)NULL) {
301         tp      = (char *)tspace;
302         *(tp++) = '.';
303     }
304     *tp = '\0';
305     return tspace;
306 }
307
308 enum rtype { add, destroy, deny };
309
310 static afs_int32
311 Convert(char *arights, int dfs, enum rtype *rtypep)
312 {
313     int i, len;
314     afs_int32 mode;
315     char tc;
316
317     *rtypep = add;              /* add rights, by default */
318
319     if (dfs) {
320         if (!strcmp(arights, "null")) {
321             *rtypep = deny;
322             return 0;
323         }
324         if (!strcmp(arights, "read"))
325             return DFS_READ | DFS_EXECUTE;
326         if (!strcmp(arights, "write"))
327             return DFS_READ | DFS_EXECUTE | DFS_INSERT | DFS_DELETE |
328                 DFS_WRITE;
329         if (!strcmp(arights, "all"))
330             return DFS_READ | DFS_EXECUTE | DFS_INSERT | DFS_DELETE |
331                 DFS_WRITE | DFS_CONTROL;
332     } else {
333         if (!strcmp(arights, "read"))
334             return PRSFS_READ | PRSFS_LOOKUP;
335         if (!strcmp(arights, "write"))
336             return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
337                 PRSFS_WRITE | PRSFS_LOCK;
338         if (!strcmp(arights, "mail"))
339             return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
340         if (!strcmp(arights, "all"))
341             return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
342                 PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
343     }
344     if (!strcmp(arights, "none")) {
345         *rtypep = destroy;      /* Remove entire entry */
346         return 0;
347     }
348     len = strlen(arights);
349     mode = 0;
350     for (i = 0; i < len; i++) {
351         tc = *arights++;
352         if (dfs) {
353             if (tc == '-')
354                 continue;
355             else if (tc == 'r')
356                 mode |= DFS_READ;
357             else if (tc == 'w')
358                 mode |= DFS_WRITE;
359             else if (tc == 'x')
360                 mode |= DFS_EXECUTE;
361             else if (tc == 'c')
362                 mode |= DFS_CONTROL;
363             else if (tc == 'i')
364                 mode |= DFS_INSERT;
365             else if (tc == 'd')
366                 mode |= DFS_DELETE;
367             else if (tc == 'A')
368                 mode |= DFS_USR0;
369             else if (tc == 'B')
370                 mode |= DFS_USR1;
371             else if (tc == 'C')
372                 mode |= DFS_USR2;
373             else if (tc == 'D')
374                 mode |= DFS_USR3;
375             else if (tc == 'E')
376                 mode |= DFS_USR4;
377             else if (tc == 'F')
378                 mode |= DFS_USR5;
379             else if (tc == 'G')
380                 mode |= DFS_USR6;
381             else if (tc == 'H')
382                 mode |= DFS_USR7;
383             else {
384                 fprintf(stderr, "%s: illegal DFS rights character '%c'.\n",
385                         pn, tc);
386                 exit(1);
387             }
388         } else {
389             if (tc == 'r')
390                 mode |= PRSFS_READ;
391             else if (tc == 'l')
392                 mode |= PRSFS_LOOKUP;
393             else if (tc == 'i')
394                 mode |= PRSFS_INSERT;
395             else if (tc == 'd')
396                 mode |= PRSFS_DELETE;
397             else if (tc == 'w')
398                 mode |= PRSFS_WRITE;
399             else if (tc == 'k')
400                 mode |= PRSFS_LOCK;
401             else if (tc == 'a')
402                 mode |= PRSFS_ADMINISTER;
403             else if (tc == 'A')
404                 mode |= PRSFS_USR0;
405             else if (tc == 'B')
406                 mode |= PRSFS_USR1;
407             else if (tc == 'C')
408                 mode |= PRSFS_USR2;
409             else if (tc == 'D')
410                 mode |= PRSFS_USR3;
411             else if (tc == 'E')
412                 mode |= PRSFS_USR4;
413             else if (tc == 'F')
414                 mode |= PRSFS_USR5;
415             else if (tc == 'G')
416                 mode |= PRSFS_USR6;
417             else if (tc == 'H')
418                 mode |= PRSFS_USR7;
419             else {
420                 fprintf(stderr, "%s: illegal rights character '%c'.\n", pn,
421                         tc);
422                 exit(1);
423             }
424         }
425     }
426     return mode;
427 }
428
429 static struct AclEntry *
430 FindList(struct AclEntry *alist, char *aname)
431 {
432     while (alist) {
433         if (!foldcmp(alist->name, aname))
434             return alist;
435         alist = alist->next;
436     }
437     return 0;
438 }
439
440 /* if no parm specified in a particular slot, set parm to be "." instead */
441 static void
442 SetDotDefault(struct cmd_item **aitemp)
443 {
444     struct cmd_item *ti;
445     if (*aitemp)
446         return;                 /* already has value */
447     /* otherwise, allocate an item representing "." */
448     ti = (struct cmd_item *)malloc(sizeof(struct cmd_item));
449     assert(ti);
450     ti->next = (struct cmd_item *)0;
451     ti->data = (char *)malloc(2);
452     assert(ti->data);
453     strcpy(ti->data, ".");
454     *aitemp = ti;
455 }
456
457 static void
458 ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights)
459 {
460     struct AclEntry *tlist;
461     tlist = (plus ? al->pluslist : al->minuslist);
462     tlist = FindList(tlist, aname);
463     if (tlist) {
464         /* Found the item already in the list. */
465         tlist->rights = arights;
466         if (plus)
467             al->nplus -= PruneList(&al->pluslist, al->dfs);
468         else
469             al->nminus -= PruneList(&al->minuslist, al->dfs);
470         return;
471     }
472     /* Otherwise we make a new item and plug in the new data. */
473     tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
474     assert(tlist);
475     strcpy(tlist->name, aname);
476     tlist->rights = arights;
477     if (plus) {
478         tlist->next = al->pluslist;
479         al->pluslist = tlist;
480         al->nplus++;
481         if (arights == 0 || arights == -1)
482             al->nplus -= PruneList(&al->pluslist, al->dfs);
483     } else {
484         tlist->next = al->minuslist;
485         al->minuslist = tlist;
486         al->nminus++;
487         if (arights == 0)
488             al->nminus -= PruneList(&al->minuslist, al->dfs);
489     }
490 }
491
492 static void
493 ZapList(struct AclEntry *alist)
494 {
495     struct AclEntry *tp, *np;
496     for (tp = alist; tp; tp = np) {
497         np = tp->next;
498         free(tp);
499     }
500 }
501
502 static int
503 PruneList(struct AclEntry **ae, int dfs)
504 {
505     struct AclEntry **lp;
506     struct AclEntry *te, *ne;
507     afs_int32 ctr;
508     ctr = 0;
509     lp = ae;
510     for (te = *ae; te; te = ne) {
511         if ((!dfs && te->rights == 0) || te->rights == -1) {
512             *lp = te->next;
513             ne = te->next;
514             free(te);
515             ctr++;
516         } else {
517             ne = te->next;
518             lp = &te->next;
519         }
520     }
521     return ctr;
522 }
523
524 static char *
525 SkipLine(char *astr)
526 {
527     while (*astr != '\n')
528         astr++;
529     astr++;
530     return astr;
531 }
532
533 /*
534  * Create an empty acl, taking into account whether the acl pointed
535  * to by astr is an AFS or DFS acl. Only parse this minimally, so we
536  * can recover from problems caused by bogus ACL's (in that case, always
537  * assume that the acl is AFS: for DFS, the user can always resort to
538  * acl_edit, but for AFS there may be no other way out).
539  */
540 static struct Acl *
541 EmptyAcl(char *astr)
542 {
543     struct Acl *tp;
544     int junk;
545
546     tp = (struct Acl *)malloc(sizeof(struct Acl));
547     assert(tp);
548     tp->nplus = tp->nminus = 0;
549     tp->pluslist = tp->minuslist = 0;
550     tp->dfs = 0;
551     sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell);
552     return tp;
553 }
554
555 static struct Acl *
556 ParseAcl(char *astr)
557 {
558     int nplus, nminus, i, trights;
559     char tname[MAXNAME];
560     struct AclEntry *first, *last, *tl;
561     struct Acl *ta;
562
563     ta = (struct Acl *)malloc(sizeof(struct Acl));
564     assert(ta);
565     ta->dfs = 0;
566     sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
567     astr = SkipLine(astr);
568     sscanf(astr, "%d", &ta->nminus);
569     astr = SkipLine(astr);
570
571     nplus = ta->nplus;
572     nminus = ta->nminus;
573
574     last = 0;
575     first = 0;
576     for (i = 0; i < nplus; i++) {
577         sscanf(astr, "%100s %d", tname, &trights);
578         astr = SkipLine(astr);
579         tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
580         assert(tl);
581         if (!first)
582             first = tl;
583         strcpy(tl->name, tname);
584         tl->rights = trights;
585         tl->next = 0;
586         if (last)
587             last->next = tl;
588         last = tl;
589     }
590     ta->pluslist = first;
591
592     last = 0;
593     first = 0;
594     for (i = 0; i < nminus; i++) {
595         sscanf(astr, "%100s %d", tname, &trights);
596         astr = SkipLine(astr);
597         tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
598         assert(tl);
599         if (!first)
600             first = tl;
601         strcpy(tl->name, tname);
602         tl->rights = trights;
603         tl->next = 0;
604         if (last)
605             last->next = tl;
606         last = tl;
607     }
608     ta->minuslist = first;
609
610     return ta;
611 }
612
613 static int
614 PrintStatus(VolumeStatus * status, char *name, char *offmsg)
615 {
616     printf("Volume status for vid = %u named %s\n", status->Vid, name);
617     if (*offmsg != 0)
618         printf("Current offline message is %s\n", offmsg);
619     printf("Current disk quota is ");
620     if (status->MaxQuota != 0)
621         printf("%d\n", status->MaxQuota);
622     else
623         printf("unlimited\n");
624     printf("Current blocks used are %d\n", status->BlocksInUse);
625     printf("The partition has %d blocks available out of %d\n\n",
626            status->PartBlocksAvail, status->PartMaxBlocks);
627     return 0;
628 }
629
630 static const char power_letter[] = {
631   'K',  /* kibi */
632   'M',  /* mebi */
633   'G',  /* gibi */
634   'T',  /* tebi */
635   'P',  /* pebi */
636 };
637
638 static void
639 HumanPrintSpace(afs_int32 int_space)
640 {
641     int exponent = 0;
642     int exponent_max = sizeof(power_letter) - 1;
643     float space = int_space;
644
645     while (space >= 1024 && exponent < exponent_max) {
646         exponent++;
647         space /= 1024;
648     }
649     printf("%9.1f%c", space, power_letter[exponent]);
650 }
651
652 static int
653 QuickPrintStatus(VolumeStatus * status, char *name, int human)
654 {
655     double QuotaUsed = 0.0;
656     double PartUsed = 0.0;
657     int WARN = 0;
658     printf("%-25.25s", name);
659
660     if (status->MaxQuota != 0) {
661         if (human) {
662             printf(" ");
663             HumanPrintSpace(status->MaxQuota);
664             printf(" ");
665             HumanPrintSpace(status->BlocksInUse);
666         }
667         else
668             printf(" %10d %10d", status->MaxQuota, status->BlocksInUse);
669         QuotaUsed =
670             ((((double)status->BlocksInUse) / status->MaxQuota) * 100.0);
671     } else {
672         printf("   no limit ");
673         if (human)
674             HumanPrintSpace(status->BlocksInUse);
675         else
676             printf("%10d", status->BlocksInUse);
677     }
678     if (QuotaUsed > 90.0) {
679         printf("%5.0f%%<<", QuotaUsed);
680         WARN = 1;
681     } else
682         printf("%5.0f%%  ", QuotaUsed);
683     PartUsed =
684         (100.0 -
685          ((((double)status->PartBlocksAvail) / status->PartMaxBlocks) *
686           100.0));
687     if (PartUsed > 97.0) {
688         printf("%9.0f%%<<", PartUsed);
689         WARN = 1;
690     } else
691         printf("%9.0f%%  ", PartUsed);
692     if (WARN) {
693         printf("  <<WARNING\n");
694     } else
695         printf("\n");
696     return 0;
697 }
698
699 static int
700 QuickPrintSpace(VolumeStatus * status, char *name, int human)
701 {
702     double PartUsed = 0.0;
703     int WARN = 0;
704     printf("%-25.25s", name);
705
706     if (human) {
707         HumanPrintSpace(status->PartMaxBlocks);
708         HumanPrintSpace(status->PartMaxBlocks - status->PartBlocksAvail);
709         HumanPrintSpace(status->PartBlocksAvail);
710     }
711     else
712         printf("%10d%10d%10d", status->PartMaxBlocks,
713                status->PartMaxBlocks - status->PartBlocksAvail,
714                status->PartBlocksAvail);
715
716     PartUsed =
717         (100.0 -
718          ((((double)status->PartBlocksAvail) / status->PartMaxBlocks) *
719           100.0));
720     if (PartUsed > 90.0) {
721         printf(" %4.0f%%<<", PartUsed);
722         WARN = 1;
723     } else
724         printf(" %4.0f%%  ", PartUsed);
725     if (WARN) {
726         printf("  <<WARNING\n");
727     } else
728         printf("\n");
729     return 0;
730 }
731
732 static char *
733 AclToString(struct Acl *acl)
734 {
735     static char mydata[AFS_PIOCTL_MAXSIZE];
736     char tstring[AFS_PIOCTL_MAXSIZE];
737     char dfsstring[30];
738     struct AclEntry *tp;
739
740     if (acl->dfs)
741         sprintf(dfsstring, " dfs:%d %s", acl->dfs, acl->cell);
742     else
743         dfsstring[0] = '\0';
744     sprintf(mydata, "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus);
745     for (tp = acl->pluslist; tp; tp = tp->next) {
746         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
747         strcat(mydata, tstring);
748     }
749     for (tp = acl->minuslist; tp; tp = tp->next) {
750         sprintf(tstring, "%s %d\n", tp->name, tp->rights);
751         strcat(mydata, tstring);
752     }
753     return mydata;
754 }
755
756 static int
757 SetACLCmd(struct cmd_syndesc *as, void *arock)
758 {
759     afs_int32 code;
760     struct ViceIoctl blob;
761     struct Acl *ta = 0;
762     struct cmd_item *ti, *ui;
763     int plusp;
764     afs_int32 rights;
765     int clear;
766     int idf = getidf(as, parm_setacl_id);
767     int error = 0;
768
769     if (as->parms[2].items)
770         clear = 1;
771     else
772         clear = 0;
773     plusp = !(as->parms[3].items);
774     for (ti = as->parms[0].items; ti; ti = ti->next) {
775         blob.out_size = AFS_PIOCTL_MAXSIZE;
776         blob.in_size = idf;
777         blob.in = blob.out = space;
778         code = pioctl(ti->data, VIOCGETAL, &blob, 1);
779         if (code) {
780             Die(errno, ti->data);
781             error = 1;
782             continue;
783         }
784
785         if (ta)
786             ZapAcl(ta);
787         ta = ParseAcl(space);
788         if (!plusp && ta->dfs) {
789             fprintf(stderr,
790                     "%s: %s: you may not use the -negative switch with DFS acl's.\n%s",
791                     pn, ti->data,
792                     "(you may specify \"null\" to revoke all rights, however)\n");
793             error = 1;
794             continue;
795         }
796
797         if (ta)
798             ZapAcl(ta);
799         if (clear)
800             ta = EmptyAcl(space);
801         else
802             ta = ParseAcl(space);
803         CleanAcl(ta, ti->data);
804         for (ui = as->parms[1].items; ui; ui = ui->next->next) {
805             enum rtype rtype;
806             if (!ui->next) {
807                 fprintf(stderr,
808                         "%s: Missing second half of user/access pair.\n", pn);
809                 ZapAcl(ta);
810                 return 1;
811             }
812             rights = Convert(ui->next->data, ta->dfs, &rtype);
813             if (rtype == destroy && !ta->dfs) {
814                 struct AclEntry *tlist;
815
816                 tlist = (plusp ? ta->pluslist : ta->minuslist);
817                 if (!FindList(tlist, ui->data))
818                     continue;
819             }
820             if (rtype == deny && !ta->dfs)
821                 plusp = 0;
822             if (rtype == destroy && ta->dfs)
823                 rights = -1;
824             ChangeList(ta, plusp, ui->data, rights);
825         }
826         blob.in = AclToString(ta);
827         blob.out_size = 0;
828         blob.in_size = 1 + strlen(blob.in);
829         code = pioctl(ti->data, VIOCSETAL, &blob, 1);
830         if (code) {
831             if (errno == EINVAL) {
832                 if (ta->dfs) {
833                     static char *fsenv = 0;
834                     if (!fsenv) {
835                         fsenv = (char *)getenv("FS_EXPERT");
836                     }
837                     fprintf(stderr,
838                             "%s: \"Invalid argument\" was returned when you tried to store a DFS access list.\n",
839                             pn);
840                     if (!fsenv) {
841                         fprintf(stderr,
842                                 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
843                                 "\nPossible reasons for this include:\n\n",
844                                 " -You may have specified an inappropriate combination of rights.\n",
845                                 "  For example, some DFS-supported filesystems may not allow you to\n",
846                                 "  drop the \"c\" right from \"user_obj\".\n\n",
847                                 " -A mask_obj may be required (it is likely required by the underlying\n",
848                                 "  filesystem if you try to set anything other than the basic \"user_obj\"\n",
849                                 "  \"mask_obj\", or \"group_obj\" entries). Unlike acl_edit, the fs command\n",
850                                 "  does not automatically create or update the mask_obj. Try setting\n",
851                                 "  the rights \"mask_obj all\" with \"fs sa\" before adding any explicit\n",
852                                 "  users or groups. You can do this with a single command, such as\n",
853                                 "  \"fs sa mask_obj all user:somename read\"\n\n",
854                                 " -A specified user or group may not exist.\n\n",
855                                 " -You may have tried to delete \"user_obj\", \"group_obj\", or \"other_obj\".\n",
856                                 "  This is probably not allowed by the underlying file system.\n\n",
857                                 " -If you add a user or group to a DFS ACL, remember that it must be\n",
858                                 "  fully specified as \"user:username\" or \"group:groupname\". In addition, there\n",
859                                 "  may be local requirements on the format of the user or group name.\n",
860                                 "  Check with your cell administrator.\n\n",
861                                 " -Or numerous other possibilities. It would be great if we could be more\n",
862                                 "  precise about the actual problem, but for various reasons, this is\n",
863                                 "  impractical via this interface.  If you can't figure it out, you\n",
864                                 "  might try logging into a DCE-equipped machine and use acl_edit (or\n",
865                                 "  whatever is provided). You may get better results. Good luck!\n\n",
866                                 " (You may inhibit this message by setting \"FS_EXPERT\" in your environment)\n");
867                     }
868                 } else {
869                     fprintf(stderr,
870                             "%s: Invalid argument, possible reasons include:\n",
871                             pn);
872                     fprintf(stderr, "\t-File not in AFS\n");
873                     fprintf(stderr,
874                             "\t-Too many users on access control list\n");
875                     fprintf(stderr,
876                             "\t-Tried to add non-existent user to access control list\n");
877                 }
878             } else {
879                 Die(errno, ti->data);
880             }
881             error = 1;
882         }
883     }
884     if (ta)
885         ZapAcl(ta);
886     return error;
887 }
888
889
890 static int
891 CopyACLCmd(struct cmd_syndesc *as, void *arock)
892 {
893     afs_int32 code;
894     struct ViceIoctl blob;
895     struct Acl *fa, *ta = 0;
896     struct AclEntry *tp;
897     struct cmd_item *ti;
898     int clear;
899     int idf = getidf(as, parm_copyacl_id);
900     int error = 0;
901
902     if (as->parms[2].items)
903         clear = 1;
904     else
905         clear = 0;
906     blob.out_size = AFS_PIOCTL_MAXSIZE;
907     blob.in_size = idf;
908     blob.in = blob.out = space;
909     code = pioctl(as->parms[0].items->data, VIOCGETAL, &blob, 1);
910     if (code) {
911         Die(errno, as->parms[0].items->data);
912         return 1;
913     }
914     fa = ParseAcl(space);
915     CleanAcl(fa, as->parms[0].items->data);
916     for (ti = as->parms[1].items; ti; ti = ti->next) {
917         blob.out_size = AFS_PIOCTL_MAXSIZE;
918         blob.in_size = idf;
919         blob.in = blob.out = space;
920         code = pioctl(ti->data, VIOCGETAL, &blob, 1);
921         if (code) {
922             Die(errno, ti->data);
923             error = 1;
924             continue;
925         }
926
927         if (ta)
928             ZapAcl(ta);
929         if (clear)
930             ta = EmptyAcl(space);
931         else
932             ta = ParseAcl(space);
933         CleanAcl(ta, ti->data);
934         if (ta->dfs != fa->dfs) {
935             fprintf(stderr,
936                     "%s: incompatible file system types: acl not copied to %s; aborted\n",
937                     pn, ti->data);
938             error = 1;
939             continue;
940         }
941         if (ta->dfs) {
942             if (!clear && strcmp(ta->cell, fa->cell) != 0) {
943                 fprintf(stderr,
944                         "%s: default DCE cell differs for file %s: use \"-clear\" switch; acl not merged\n",
945                         pn, ti->data);
946                 error = 1;
947                 continue;
948             }
949             strcpy(ta->cell, fa->cell);
950         }
951         for (tp = fa->pluslist; tp; tp = tp->next)
952             ChangeList(ta, 1, tp->name, tp->rights);
953         for (tp = fa->minuslist; tp; tp = tp->next)
954             ChangeList(ta, 0, tp->name, tp->rights);
955         blob.in = AclToString(ta);
956         blob.out_size = 0;
957         blob.in_size = 1 + strlen(blob.in);
958         code = pioctl(ti->data, VIOCSETAL, &blob, 1);
959         if (code) {
960             if (errno == EINVAL) {
961                 fprintf(stderr,
962                         "%s: Invalid argument, possible reasons include:\n",
963                         pn);
964                 fprintf(stderr, "\t-File not in AFS\n");
965             } else {
966                 Die(errno, ti->data);
967             }
968             error = 1;
969         }
970     }
971     if (ta)
972         ZapAcl(ta);
973     ZapAcl(fa);
974     return error;
975 }
976
977 /* pioctl() call to get the cellname of a pathname */
978 static afs_int32
979 GetCell(char *fname, char *cellname)
980 {
981     afs_int32 code;
982     struct ViceIoctl blob;
983
984     blob.in_size = 0;
985     blob.out_size = MAXCELLCHARS;
986     blob.out = cellname;
987
988     code = pioctl(fname, VIOC_FILE_CELL_NAME, &blob, 1);
989     return code ? errno : 0;
990 }
991
992 /* Check if a username is valid: If it contains only digits (or a
993  * negative sign), then it might be bad. We then query the ptserver
994  * to see.
995  */
996 static int
997 BadName(char *aname, char *fname)
998 {
999     afs_int32 tc, code, id;
1000     char *nm;
1001     char cell[MAXCELLCHARS];
1002
1003     for (nm = aname; (tc = *nm); nm++) {
1004         /* all must be '-' or digit to be bad */
1005         if (tc != '-' && (tc < '0' || tc > '9'))
1006             return 0;
1007     }
1008
1009     /* Go to the PRDB and see if this all number username is valid */
1010     code = GetCell(fname, cell);
1011     if (code)
1012         return 0;
1013
1014     pr_Initialize(1, AFSDIR_CLIENT_ETC_DIRPATH, cell);
1015     code = pr_SNameToId(aname, &id);
1016     pr_End();
1017
1018     /* 1=>Not-valid; 0=>Valid */
1019     return ((!code && (id == ANONYMOUSID)) ? 1 : 0);
1020 }
1021
1022
1023 /* clean up an access control list of its bad entries; return 1 if we made
1024    any changes to the list, and 0 otherwise */
1025 static int
1026 CleanAcl(struct Acl *aa, char *fname)
1027 {
1028     struct AclEntry *te, **le, *ne;
1029     int changes;
1030
1031     /* Don't correct DFS ACL's for now */
1032     if (aa->dfs)
1033         return 0;
1034
1035     /* prune out bad entries */
1036     changes = 0;                /* count deleted entries */
1037     le = &aa->pluslist;
1038     for (te = aa->pluslist; te; te = ne) {
1039         ne = te->next;
1040         if (BadName(te->name, fname)) {
1041             /* zap this dude */
1042             *le = te->next;
1043             aa->nplus--;
1044             free(te);
1045             changes++;
1046         } else {
1047             le = &te->next;
1048         }
1049     }
1050     le = &aa->minuslist;
1051     for (te = aa->minuslist; te; te = ne) {
1052         ne = te->next;
1053         if (BadName(te->name, fname)) {
1054             /* zap this dude */
1055             *le = te->next;
1056             aa->nminus--;
1057             free(te);
1058             changes++;
1059         } else {
1060             le = &te->next;
1061         }
1062     }
1063     return changes;
1064 }
1065
1066
1067 /* clean up an acl to not have bogus entries */
1068 static int
1069 CleanACLCmd(struct cmd_syndesc *as, void *arock)
1070 {
1071     afs_int32 code;
1072     struct Acl *ta = 0;
1073     struct ViceIoctl blob;
1074     int changes;
1075     struct cmd_item *ti;
1076     struct AclEntry *te;
1077     int error = 0;
1078
1079     SetDotDefault(&as->parms[0].items);
1080     for (ti = as->parms[0].items; ti; ti = ti->next) {
1081         blob.out_size = AFS_PIOCTL_MAXSIZE;
1082         blob.in_size = 0;
1083         blob.out = space;
1084         code = pioctl(ti->data, VIOCGETAL, &blob, 1);
1085         if (code) {
1086             Die(errno, ti->data);
1087             error = 1;
1088             continue;
1089         }
1090
1091         if (ta)
1092             ZapAcl(ta);
1093         ta = ParseAcl(space);
1094         if (ta->dfs) {
1095             fprintf(stderr,
1096                     "%s: cleanacl is not supported for DFS access lists.\n",
1097                     pn);
1098             error = 1;
1099             continue;
1100         }
1101
1102         changes = CleanAcl(ta, ti->data);
1103
1104         if (changes) {
1105             /* now set the acl */
1106             blob.in = AclToString(ta);
1107             blob.in_size = strlen(blob.in) + 1;
1108             blob.out_size = 0;
1109             code = pioctl(ti->data, VIOCSETAL, &blob, 1);
1110             if (code) {
1111                 if (errno == EINVAL) {
1112                     fprintf(stderr,
1113                             "%s: Invalid argument, possible reasons include\n",
1114                             pn);
1115                     fprintf(stderr, "%s: File not in vice or\n", pn);
1116                     fprintf(stderr,
1117                             "%s: Too many users on access control list or\n",
1118                             pn);
1119                 } else {
1120                     Die(errno, ti->data);
1121                 }
1122                 error = 1;
1123                 continue;
1124             }
1125
1126             /* now list the updated acl */
1127             printf("Access list for %s is now\n", ti->data);
1128             if (ta->nplus > 0) {
1129                 if (!ta->dfs)
1130                     printf("Normal rights:\n");
1131                 for (te = ta->pluslist; te; te = te->next) {
1132                     printf("  %s ", te->name);
1133                     PRights(te->rights, ta->dfs);
1134                     printf("\n");
1135                 }
1136             }
1137             if (ta->nminus > 0) {
1138                 printf("Negative rights:\n");
1139                 for (te = ta->minuslist; te; te = te->next) {
1140                     printf("  %s ", te->name);
1141                     PRights(te->rights, ta->dfs);
1142                     printf("\n");
1143                 }
1144             }
1145             if (ti->next)
1146                 printf("\n");
1147         } else
1148             printf("Access list for %s is fine.\n", ti->data);
1149     }
1150     if (ta)
1151         ZapAcl(ta);
1152     return error;
1153 }
1154
1155 static int
1156 ListACLCmd(struct cmd_syndesc *as, void *arock)
1157 {
1158     afs_int32 code;
1159     struct Acl *ta;
1160     struct ViceIoctl blob;
1161     struct AclEntry *te;
1162     struct cmd_item *ti;
1163     int idf = getidf(as, parm_listacl_id);
1164     int error = 0;
1165
1166     SetDotDefault(&as->parms[0].items);
1167     for (ti = as->parms[0].items; ti; ti = ti->next) {
1168         blob.out_size = AFS_PIOCTL_MAXSIZE;
1169         blob.in_size = idf;
1170         blob.in = blob.out = space;
1171         code = pioctl(ti->data, VIOCGETAL, &blob, 1);
1172         if (code) {
1173             Die(errno, ti->data);
1174             error = 1;
1175             continue;
1176         }
1177         ta = ParseAcl(space);
1178         if (as->parms[3].items) {                       /* -cmd */
1179             printf("fs setacl -dir %s -acl ", ti->data);
1180             if (ta->nplus > 0) {
1181                 for (te = ta->pluslist; te; te = te->next) {
1182                     printf("  %s ", te->name);
1183                     PRights(te->rights, ta->dfs);
1184                 }
1185             }
1186             printf("\n");
1187             if (ta->nminus > 0) {
1188                 printf("fs setacl -dir %s -acl ", ti->data);
1189                 for (te = ta->minuslist; te; te = te->next) {
1190                     printf("  %s ", te->name);
1191                     PRights(te->rights, ta->dfs);
1192                 }
1193                 printf(" -negative\n");
1194             }
1195         } else {
1196             switch (ta->dfs) {
1197             case 0:
1198                 printf("Access list for %s is\n", ti->data);
1199                 break;
1200             case 1:
1201                 printf("DFS access list for %s is\n", ti->data);
1202                 break;
1203             case 2:
1204                 printf("DFS initial directory access list of %s is\n", ti->data);
1205                 break;
1206             case 3:
1207                 printf("DFS initial file access list of %s is\n", ti->data);
1208                 break;
1209             }
1210             if (ta->dfs) {
1211                 printf("  Default cell = %s\n", ta->cell);
1212             }
1213             if (ta->nplus > 0) {
1214                 if (!ta->dfs)
1215                     printf("Normal rights:\n");
1216                 for (te = ta->pluslist; te; te = te->next) {
1217                     printf("  %s ", te->name);
1218                     PRights(te->rights, ta->dfs);
1219                     printf("\n");
1220                 }
1221             }
1222             if (ta->nminus > 0) {
1223                 printf("Negative rights:\n");
1224                 for (te = ta->minuslist; te; te = te->next) {
1225                     printf("  %s ", te->name);
1226                     PRights(te->rights, ta->dfs);
1227                     printf("\n");
1228                 }
1229             }
1230             if (ti->next)
1231                 printf("\n");
1232         }
1233         ZapAcl(ta);
1234     }
1235     return error;
1236 }
1237
1238 static int
1239 GetCallerAccess(struct cmd_syndesc *as, void *arock)
1240 {
1241     struct cmd_item *ti;
1242     int error = 0;
1243
1244     SetDotDefault(&as->parms[0].items);
1245     for (ti = as->parms[0].items; ti; ti = ti->next) {
1246         afs_int32 code;
1247         struct ViceIoctl blob;
1248         struct vcxstat2 stat;
1249         blob.out_size = sizeof(struct vcxstat2);
1250         blob.in_size = 0;
1251         blob.out = (void *)&stat;
1252         code = pioctl(ti->data, VIOC_GETVCXSTATUS2, &blob, 1);
1253         if (code) {
1254             Die(errno, ti->data);
1255             error = 1;
1256             continue;
1257         }
1258         printf("Callers access to %s is ", ti->data);
1259         PRights(stat.callerAccess, 0);
1260         printf("\n");
1261     }
1262     return error;
1263 }
1264
1265 static int
1266 FlushVolumeCmd(struct cmd_syndesc *as, void *arock)
1267 {
1268     afs_int32 code;
1269     struct ViceIoctl blob;
1270     struct cmd_item *ti;
1271     int error = 0;
1272
1273     SetDotDefault(&as->parms[0].items);
1274     for (ti = as->parms[0].items; ti; ti = ti->next) {
1275         blob.in_size = blob.out_size = 0;
1276         code = pioctl(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
1277         if (code) {
1278             fprintf(stderr, "Error flushing volume ");
1279             perror(ti->data);
1280             error = 1;
1281             continue;
1282         }
1283     }
1284     return error;
1285 }
1286
1287 /*
1288  * The Windows version of UuidCmd displays the UUID.
1289  * When the UNIX version is updated to do the same
1290  * be sure to replace the CMD_REQUIRED flag with
1291  * CMD_OPTIONAL in the cmd_AddParam(-generate) call
1292  */
1293 static int
1294 UuidCmd(struct cmd_syndesc *as, void *arock)
1295 {
1296     afs_int32 code;
1297     struct ViceIoctl blob;
1298
1299     blob.in_size = 0;
1300     blob.out_size = 0;
1301
1302     if (as->parms[0].items) {
1303         if (geteuid()) {
1304             fprintf (stderr, "Permission denied: requires root access.\n");
1305             return EACCES;
1306         }
1307
1308         /* generate new UUID */
1309         code = pioctl(0, VIOC_NEWUUID, &blob, 1);
1310
1311         if (code) {
1312             Die(errno, 0);
1313             return 1;
1314         }
1315
1316         printf("New uuid generated.\n");
1317     } else {
1318         /* This will never execute */
1319         printf("Please add the '-generate' option to generate a new UUID.\n");
1320     }
1321     return 0;
1322 }
1323
1324 #if defined(AFS_CACHE_BYPASS)
1325 /*
1326  * Set cache-bypass threshold.  Files larger than this size will not be cached.
1327  * With a threshold of 0, the cache is always bypassed.  With a threshold of -1,
1328  * cache bypass is disabled.
1329  */
1330
1331 static int
1332 BypassThresholdCmd(struct cmd_syndesc *as, void *arock)
1333 {
1334     afs_int32 code;
1335     struct ViceIoctl blob;
1336     afs_int32 threshold_i, threshold_o;
1337     char *tp;
1338
1339     /* if new threshold supplied, then set and confirm, else,
1340      * get current threshold and print
1341      */
1342
1343     if(as->parms[0].items) {
1344         int digit, ix, len;
1345
1346         tp = as->parms[0].items->data;
1347         len = strlen(tp);
1348
1349         if (!strcmp(tp,"-1")) {
1350             threshold_i = -1;
1351         } else {
1352             digit = 1;
1353             for(ix = 0; ix < len; ++ix) {
1354                 if(!isdigit(tp[0])) {
1355                     digit = 0;
1356                     break;
1357                 }
1358             }
1359             if (digit == 0) {
1360                 fprintf(stderr, "fs bypassthreshold -size: %s must be an integer between -1 and 2^31\n", tp);
1361                 return EINVAL;
1362             }
1363             threshold_i = atoi(tp);
1364             if(ix > 9 && threshold_i < 2147483647)
1365                 threshold_i = 2147483647;
1366         }
1367         blob.in = (char *) &threshold_i;
1368         blob.in_size = sizeof(threshold_i);
1369     } else {
1370         blob.in = NULL;
1371         blob.in_size = 0;
1372     }
1373
1374     blob.out = (char *) &threshold_o;
1375     blob.out_size = sizeof(threshold_o);
1376     code = pioctl(0, VIOC_SETBYPASS_THRESH, &blob, 1);
1377     if (code) {
1378         Die(errno, NULL);
1379         return 1;
1380     } else {
1381         printf("Cache bypass threshold %d", threshold_o);
1382         if(threshold_o ==  -1)
1383             printf(" (disabled)");
1384         printf("\n");
1385     }
1386
1387     return 0;
1388 }
1389
1390 #endif
1391
1392 static int
1393 FlushCmd(struct cmd_syndesc *as, void *arock)
1394 {
1395     afs_int32 code;
1396     struct ViceIoctl blob;
1397     struct cmd_item *ti;
1398     int error = 0;
1399
1400     for (ti = as->parms[0].items; ti; ti = ti->next) {
1401         blob.in_size = blob.out_size = 0;
1402         code = pioctl(ti->data, VIOCFLUSH, &blob, 0);
1403         if (code) {
1404             if (errno == EMFILE) {
1405                 fprintf(stderr, "%s: Can't flush active file %s\n", pn,
1406                         ti->data);
1407             } else {
1408                 fprintf(stderr, "%s: Error flushing file ", pn);
1409                 perror(ti->data);
1410             }
1411             error = 1;
1412             continue;
1413         }
1414     }
1415     return error;
1416 }
1417
1418 /* all this command does is repackage its args and call SetVolCmd */
1419 static int
1420 SetQuotaCmd(struct cmd_syndesc *as, void *arock)
1421 {
1422     struct cmd_syndesc ts;
1423
1424     /* copy useful stuff from our command slot; we may later have to reorder */
1425     memcpy(&ts, as, sizeof(ts));        /* copy whole thing */
1426     return SetVolCmd(&ts, arock);
1427 }
1428
1429 static int
1430 SetVolCmd(struct cmd_syndesc *as, void *arock)
1431 {
1432     afs_int32 code;
1433     struct ViceIoctl blob;
1434     struct cmd_item *ti;
1435     struct VolumeStatus *status;
1436     char *offmsg, *input;
1437     int error = 0;
1438
1439     SetDotDefault(&as->parms[0].items);
1440     for (ti = as->parms[0].items; ti; ti = ti->next) {
1441         /* once per file */
1442         blob.out_size = AFS_PIOCTL_MAXSIZE;
1443         blob.in_size = sizeof(*status) + 3;     /* for the three terminating nulls */
1444         blob.out = space;
1445         blob.in = space;
1446         status = (VolumeStatus *) space;
1447         status->MinQuota = status->MaxQuota = -1;
1448         offmsg = NULL;
1449         if (as->parms[1].items) {
1450             code = util_GetHumanInt32(as->parms[1].items->data, &status->MaxQuota);
1451             if (code) {
1452                 fprintf(stderr, "%s: bad integer specified for quota.\n", pn);
1453                 error = 1;
1454                 continue;
1455             }
1456         }
1457         if (as->parms[2].items)
1458             offmsg = as->parms[2].items->data;
1459         input = (char *)status + sizeof(*status);
1460         *(input++) = '\0';      /* never set name: this call doesn't change vldb */
1461         if (offmsg) {
1462             if (strlen(offmsg) >= VMSGSIZE) {
1463                 fprintf(stderr,
1464                         "%s: message must be shorter than %d characters\n",
1465                         pn, VMSGSIZE);
1466                 error = 1;
1467                 continue;
1468             }
1469             strcpy(input, offmsg);
1470             blob.in_size += strlen(offmsg);
1471             input += strlen(offmsg) + 1;
1472         } else
1473             *(input++) = '\0';
1474         *(input++) = '\0';      /* Pad for old style volume "motd" */
1475         code = pioctl(ti->data, VIOCSETVOLSTAT, &blob, 1);
1476         if (code) {
1477             Die(errno, ti->data);
1478             error = 1;
1479         }
1480     }
1481     return error;
1482 }
1483
1484 /*
1485  * Why is VenusFid declared in the kernel-only section of afs.h,
1486  * if it's the exported interface of the cache manager?
1487  */
1488 struct VenusFid {
1489     afs_int32 Cell;
1490     AFSFid Fid;
1491 };
1492
1493 static int
1494 ExamineCmd(struct cmd_syndesc *as, void *arock)
1495 {
1496     afs_int32 code;
1497     struct ViceIoctl blob;
1498     struct cmd_item *ti;
1499     struct VolumeStatus *status;
1500     char *name, *offmsg;
1501     int error = 0;
1502
1503     SetDotDefault(&as->parms[0].items);
1504     for (ti = as->parms[0].items; ti; ti = ti->next) {
1505         struct VenusFid vfid;
1506
1507         /* once per file */
1508         blob.out_size = AFS_PIOCTL_MAXSIZE;
1509         blob.in_size = 0;
1510         blob.out = space;
1511         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1512         if (code) {
1513             Die(errno, ti->data);
1514             error = 1;
1515             continue;
1516         }
1517         status = (VolumeStatus *) space;
1518         name = (char *)status + sizeof(*status);
1519         offmsg = name + strlen(name) + 1;
1520
1521         blob.out_size = sizeof(struct VenusFid);
1522         blob.out = (char *) &vfid;
1523         if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
1524             printf("File %s (%u.%u.%u) contained in volume %u\n",
1525                    ti->data, vfid.Fid.Volume, vfid.Fid.Vnode, vfid.Fid.Unique,
1526                    vfid.Fid.Volume);
1527         }
1528
1529         PrintStatus(status, name, offmsg);
1530     }
1531     return error;
1532 }
1533
1534 static int
1535 ListQuotaCmd(struct cmd_syndesc *as, void *arock)
1536 {
1537     afs_int32 code;
1538     struct ViceIoctl blob;
1539     struct cmd_item *ti;
1540     struct VolumeStatus *status;
1541     char *name;
1542     int error = 0;
1543     int human = 0;
1544
1545     if (as->parms[1].items)
1546         human = 1;
1547
1548     printf("%-25s%-11s%-11s%-7s%-11s\n", "Volume Name", "      Quota",
1549            "       Used", " %Used", "  Partition");
1550     SetDotDefault(&as->parms[0].items);
1551     for (ti = as->parms[0].items; ti; ti = ti->next) {
1552         /* once per file */
1553         blob.out_size = AFS_PIOCTL_MAXSIZE;
1554         blob.in_size = 0;
1555         blob.out = space;
1556         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1557         if (code) {
1558             Die(errno, ti->data);
1559             error = 1;
1560             continue;
1561         }
1562         status = (VolumeStatus *) space;
1563         name = (char *)status + sizeof(*status);
1564         QuickPrintStatus(status, name, human);
1565     }
1566     return error;
1567 }
1568
1569 static int
1570 WhereIsCmd(struct cmd_syndesc *as, void *arock)
1571 {
1572     afs_int32 code;
1573     struct ViceIoctl blob;
1574     struct cmd_item *ti;
1575     int j;
1576     afs_int32 *hosts;
1577     char *tp;
1578     int error = 0;
1579
1580     SetDotDefault(&as->parms[0].items);
1581     for (ti = as->parms[0].items; ti; ti = ti->next) {
1582         /* once per file */
1583         blob.out_size = AFS_PIOCTL_MAXSIZE;
1584         blob.in_size = 0;
1585         blob.out = space;
1586         memset(space, 0, sizeof(space));
1587         code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
1588         if (code) {
1589             Die(errno, ti->data);
1590             error = 1;
1591             continue;
1592         }
1593         hosts = (afs_int32 *) space;
1594         printf("File %s is on host%s ", ti->data,
1595                (hosts[0] && !hosts[1]) ? "" : "s");
1596         for (j = 0; j < AFS_MAXHOSTS; j++) {
1597             if (hosts[j] == 0)
1598                 break;
1599             tp = hostutil_GetNameByINet(hosts[j]);
1600             printf("%s ", tp);
1601         }
1602         printf("\n");
1603     }
1604     return error;
1605 }
1606
1607
1608 static int
1609 DiskFreeCmd(struct cmd_syndesc *as, void *arock)
1610 {
1611     afs_int32 code;
1612     struct ViceIoctl blob;
1613     struct cmd_item *ti;
1614     char *name;
1615     struct VolumeStatus *status;
1616     int error = 0;
1617     int human = 0;
1618
1619     if (as->parms[1].items)
1620         human = 1;
1621
1622     printf("%-25s%10s%10s%10s%6s\n", "Volume Name",
1623            human ? "total" : "kbytes", "used", "avail", "%used");
1624     SetDotDefault(&as->parms[0].items);
1625     for (ti = as->parms[0].items; ti; ti = ti->next) {
1626         /* once per file */
1627         blob.out_size = AFS_PIOCTL_MAXSIZE;
1628         blob.in_size = 0;
1629         blob.out = space;
1630         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1631         if (code) {
1632             Die(errno, ti->data);
1633             error = 1;
1634             continue;
1635         }
1636         status = (VolumeStatus *) space;
1637         name = (char *)status + sizeof(*status);
1638         QuickPrintSpace(status, name, human);
1639     }
1640     return error;
1641 }
1642
1643 static int
1644 QuotaCmd(struct cmd_syndesc *as, void *arock)
1645 {
1646     afs_int32 code;
1647     struct ViceIoctl blob;
1648     struct cmd_item *ti;
1649     double quotaPct;
1650     struct VolumeStatus *status;
1651     int error = 0;
1652
1653     SetDotDefault(&as->parms[0].items);
1654     for (ti = as->parms[0].items; ti; ti = ti->next) {
1655         /* once per file */
1656         blob.out_size = AFS_PIOCTL_MAXSIZE;
1657         blob.in_size = 0;
1658         blob.out = space;
1659         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1660         if (code) {
1661             Die(errno, ti->data);
1662             error = 1;
1663             continue;
1664         }
1665         status = (VolumeStatus *) space;
1666         if (status->MaxQuota)
1667             quotaPct =
1668                 ((((double)status->BlocksInUse) / status->MaxQuota) * 100.0);
1669         else
1670             quotaPct = 0.0;
1671         printf("%2.0f%% of quota used.\n", quotaPct);
1672     }
1673     return error;
1674 }
1675
1676 static int
1677 GetLastComponent(const char *data, char **outdir, char **outbase,
1678                  int *thru_symlink)
1679 {
1680     char orig_name[1024];       /*Original name, may be modified */
1681     char true_name[1024];       /*``True'' dirname (e.g., symlink target) */
1682     char *lastSlash;
1683     struct stat statbuff;       /*Buffer for status info */
1684     int link_chars_read;        /*Num chars read in readlink() */
1685     char *dirname = NULL;
1686     char *basename = NULL;
1687
1688     if (thru_symlink)
1689         *thru_symlink = 0;
1690
1691     snprintf(orig_name, sizeof(orig_name), "%s%s",
1692              (data[0] == '/') ? "" : "./", data);
1693
1694     if (lstat(orig_name, &statbuff) < 0) {
1695         /* if lstat fails, we should still try the pioctl, since it
1696          * may work (for example, lstat will fail, but pioctl will
1697          * work if the volume of offline (returning ENODEV). */
1698         statbuff.st_mode = S_IFDIR;     /* lie like pros */
1699     }
1700
1701     /*
1702      * The lstat succeeded.  If the given file is a symlink, substitute
1703      * the file name with the link name.
1704      */
1705     if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
1706         if (thru_symlink)
1707              *thru_symlink = 1;
1708
1709         /* Read name of resolved file */
1710         link_chars_read = readlink(orig_name, true_name, 1024);
1711         if (link_chars_read <= 0) {
1712             fprintf(stderr,
1713                     "%s: Can't read target name for '%s' symbolic link!\n",
1714                     pn, orig_name);
1715             goto out;
1716         }
1717
1718         /* Add a trailing null to what was read, bump the length. */
1719         true_name[link_chars_read++] = 0;
1720
1721         /*
1722          * If the symlink is an absolute pathname, we're fine.  Otherwise, we
1723          * have to create a full pathname using the original name and the
1724          * relative symlink name.  Find the rightmost slash in the original
1725          * name (we know there is one) and splice in the symlink value.
1726          */
1727         if (true_name[0] != '/') {
1728             lastSlash = strrchr(orig_name, '/');
1729             strcpy(++lastSlash, true_name);
1730             strcpy(true_name, orig_name);
1731         }
1732      } else {
1733         strcpy(true_name, orig_name);
1734      }
1735
1736     /* Find rightmost slash, if any. */
1737     lastSlash = strrchr(true_name, '/');
1738     if (lastSlash == true_name) {
1739         dirname = strdup("/");
1740         basename = strdup(lastSlash+1);
1741     } else if (lastSlash != NULL) {
1742         /*
1743          * Found it.  Designate everything before it as the parent directory,
1744          * everything after it as the final component.
1745          */
1746         *lastSlash = '\0';
1747         dirname = strdup(true_name);
1748         basename = strdup(lastSlash+1);
1749     } else {
1750         /*
1751          * No slash appears in the given file name.  Set parent_dir to the current
1752          * directory, and the last component as the given name.
1753          */
1754         dirname = strdup(".");
1755         basename = strdup(true_name);
1756     }
1757
1758     if (strcmp(basename, ".") == 0
1759         || strcmp(basename, "..") == 0) {
1760         fprintf(stderr,
1761                 "%s: you may not use '.' or '..' as the last component\n", pn);
1762         fprintf(stderr, "%s: of a name in this fs command.\n", pn);
1763         goto out;
1764     }
1765
1766     *outdir = dirname;
1767     *outbase = basename;
1768
1769     return 0;
1770
1771 out:
1772     if (outdir)
1773         free(outdir);
1774     if (outbase)
1775         free(outbase);
1776     return -1;
1777 }
1778
1779
1780 static int
1781 ListMountCmd(struct cmd_syndesc *as, void *arock)
1782 {
1783     afs_int32 code;
1784     struct ViceIoctl blob;
1785     struct cmd_item *ti;
1786     char *last_component;
1787     char *parent_dir;
1788     int thru_symlink = 0;
1789     int error = 0;
1790
1791     for (ti = as->parms[0].items; ti; ti = ti->next) {
1792         if (GetLastComponent(ti->data, &parent_dir,
1793                              &last_component, &thru_symlink) != 0) {
1794             error = 1;
1795             continue;
1796         }
1797
1798         blob.in = last_component;
1799         blob.in_size = strlen(last_component) + 1;
1800         blob.out_size = AFS_PIOCTL_MAXSIZE;
1801         blob.out = space;
1802         memset(space, 0, AFS_PIOCTL_MAXSIZE);
1803
1804         code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
1805         free(last_component);
1806         free(parent_dir);
1807
1808         if (code == 0) {
1809             printf("'%s' is a %smount point for volume '%s'\n", ti->data,
1810                    (thru_symlink ? "symbolic link, leading to a " : ""),
1811                    space);
1812         } else {
1813             if (errno == EINVAL) {
1814                 fprintf(stderr, "'%s' is not a mount point.\n", ti->data);
1815             } else {
1816                 Die(errno, (ti->data ? ti->data : parent_dir));
1817             }
1818             error = 1;
1819         }
1820     }
1821     return error;
1822 }
1823
1824 static int
1825 MakeMountCmd(struct cmd_syndesc *as, void *arock)
1826 {
1827     afs_int32 code;
1828     char *cellName, *volName, *tmpName;
1829     struct afsconf_cell info;
1830     struct vldbentry vldbEntry;
1831     struct ViceIoctl blob;
1832
1833 /*
1834
1835 defect #3069
1836
1837     if (as->parms[5].items && !as->parms[2].items) {
1838         fprintf(stderr, "%s: must provide cell when creating cellular mount point.\n", pn);
1839         return 1;
1840     }
1841 */
1842
1843     if (as->parms[2].items)     /* cell name specified */
1844         cellName = as->parms[2].items->data;
1845     else
1846         cellName = NULL;
1847     volName = as->parms[1].items->data;
1848
1849     if (strlen(volName) >= 64) {
1850         fprintf(stderr,
1851                 "%s: volume name too long (length must be < 64 characters)\n",
1852                 pn);
1853         return 1;
1854     }
1855
1856     /* Check for a cellname in the volume specification, and complain
1857      * if it doesn't match what was specified with -cell */
1858     if ((tmpName = strchr(volName, ':'))) {
1859         *tmpName = '\0';
1860         if (cellName) {
1861             if (strcasecmp(cellName, volName)) {
1862                 fprintf(stderr, "%s: cellnames do not match.\n", pn);
1863                 return 1;
1864             }
1865         }
1866         cellName = volName;
1867         volName = ++tmpName;
1868     }
1869
1870     if (!InAFS(Parent(as->parms[0].items->data))) {
1871         fprintf(stderr,
1872                 "%s: mount points must be created within the AFS file system\n",
1873                 pn);
1874         return 1;
1875     }
1876
1877     if (!cellName) {
1878         blob.in_size = 0;
1879         blob.out_size = AFS_PIOCTL_MAXSIZE;
1880         blob.out = space;
1881         code =
1882             pioctl(Parent(as->parms[0].items->data), VIOC_FILE_CELL_NAME,
1883                    &blob, 1);
1884     }
1885
1886     code = GetCellName(cellName ? cellName : space, &info);
1887     if (code) {
1888         return 1;
1889     }
1890     if (!(as->parms[4].items)) {
1891         /* not fast, check which cell the mountpoint is being created in */
1892         /* not fast, check name with VLDB */
1893         code = VLDBInit(1, &info);
1894         if (code == 0) {
1895             /* make the check.  Don't complain if there are problems with init */
1896             code =
1897                 ubik_VL_GetEntryByNameO(uclient, 0, volName,
1898                           &vldbEntry);
1899             if (code == VL_NOENT) {
1900                 fprintf(stderr,
1901                         "%s: warning, volume %s does not exist in cell %s.\n",
1902                         pn, volName, cellName ? cellName : space);
1903             }
1904         }
1905     }
1906
1907     if (as->parms[3].items)     /* if -rw specified */
1908         strcpy(space, "%");
1909     else
1910         strcpy(space, "#");
1911     if (cellName) {
1912         /* cellular mount point, prepend cell prefix */
1913         strcat(space, info.name);
1914         strcat(space, ":");
1915     }
1916     strcat(space, volName);     /* append volume name */
1917     strcat(space, ".");         /* stupid convention; these end with a period */
1918     code = symlink(space, as->parms[0].items->data);
1919     if (code) {
1920         Die(errno, as->parms[0].items->data);
1921         return 1;
1922     }
1923     return 0;
1924 }
1925
1926 /*
1927  * Delete AFS mount points.  Variables are used as follows:
1928  *      tbuffer: Set to point to the null-terminated directory name of the mount point
1929  *          (or ``.'' if none is provided)
1930  *      tp: Set to point to the actual name of the mount point to nuke.
1931  */
1932 static int
1933 RemoveMountCmd(struct cmd_syndesc *as, void *arock)
1934 {
1935     afs_int32 code = 0;
1936     struct ViceIoctl blob;
1937     struct cmd_item *ti;
1938     char tbuffer[1024];
1939     char lsbuffer[1024];
1940     char *tp;
1941     int error = 0;
1942
1943     for (ti = as->parms[0].items; ti; ti = ti->next) {
1944         /* once per file */
1945         tp = (char *)strrchr(ti->data, '/');
1946         if (tp) {
1947             strncpy(tbuffer, ti->data, code = tp - ti->data);   /* the dir name */
1948             tbuffer[code] = 0;
1949             tp++;               /* skip the slash */
1950         } else {
1951             strcpy(tbuffer, ".");
1952             tp = ti->data;
1953         }
1954         blob.in = tp;
1955         blob.in_size = strlen(tp) + 1;
1956         blob.out = lsbuffer;
1957         blob.out_size = sizeof(lsbuffer);
1958         code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 1);
1959         if (code) {
1960             if (errno == EINVAL) {
1961                 fprintf(stderr, "%s: '%s' is not a mount point.\n", pn,
1962                         ti->data);
1963             } else {
1964                 Die(errno, ti->data);
1965             }
1966             error = 1;
1967             continue;           /* don't bother trying */
1968         }
1969         blob.out_size = 0;
1970         blob.in = tp;
1971         blob.in_size = strlen(tp) + 1;
1972         code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 1);
1973         if (code) {
1974             Die(errno, ti->data);
1975             error = 1;
1976         }
1977     }
1978     return error;
1979 }
1980
1981 /*
1982 */
1983
1984 static int
1985 CheckServersCmd(struct cmd_syndesc *as, void *arock)
1986 {
1987     afs_int32 code;
1988     struct ViceIoctl blob;
1989     afs_int32 j;
1990     afs_int32 temp;
1991     char *tp;
1992     struct afsconf_cell info;
1993     struct chservinfo checkserv;
1994
1995     memset(&checkserv, 0, sizeof(struct chservinfo));
1996     blob.in_size = sizeof(struct chservinfo);
1997     blob.in = (caddr_t) & checkserv;
1998
1999     blob.out_size = AFS_PIOCTL_MAXSIZE;
2000     blob.out = space;
2001     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
2002
2003     /* prepare flags for checkservers command */
2004     temp = 2;                   /* default to checking local cell only */
2005     if (as->parms[2].items)
2006         temp |= 1;              /* set fast flag */
2007     if (as->parms[1].items)
2008         temp &= ~2;             /* turn off local cell check */
2009
2010     checkserv.magic = 0x12345678;       /* XXX */
2011     checkserv.tflags = temp;
2012
2013     /* now copy in optional cell name, if specified */
2014     if (as->parms[0].items) {
2015         code = GetCellName(as->parms[0].items->data, &info);
2016         if (code) {
2017             return 1;
2018         }
2019         strcpy(checkserv.tbuffer, info.name);
2020         checkserv.tsize = strlen(info.name) + 1;
2021     } else {
2022         strcpy(checkserv.tbuffer, "\0");
2023         checkserv.tsize = 0;
2024     }
2025
2026     if (as->parms[3].items) {
2027         checkserv.tinterval = atol(as->parms[3].items->data);
2028
2029         /* sanity check */
2030         if (checkserv.tinterval < 0) {
2031             printf
2032                 ("Warning: The negative -interval is ignored; treated as an inquiry\n");
2033             checkserv.tinterval = 0;
2034         } else if (checkserv.tinterval > 600) {
2035             printf
2036                 ("Warning: The maximum -interval value is 10 mins (600 secs)\n");
2037             checkserv.tinterval = 600;  /* 10 min max interval */
2038         }
2039     } else {
2040         checkserv.tinterval = -1;       /* don't change current interval */
2041     }
2042
2043     code = pioctl(0, VIOCCKSERV, &blob, 1);
2044     if (code) {
2045         if ((errno == EACCES) && (checkserv.tinterval > 0)) {
2046             printf("Must be root to change -interval\n");
2047             return 1;
2048         }
2049         Die(errno, 0);
2050         return 1;
2051     }
2052     memcpy(&temp, space, sizeof(afs_int32));
2053     if (checkserv.tinterval >= 0) {
2054         if (checkserv.tinterval > 0)
2055             printf
2056                 ("The new down server probe interval (%d secs) is now in effect (old interval was %d secs)\n",
2057                  checkserv.tinterval, temp);
2058         else
2059             printf("The current down server probe interval is %d secs\n",
2060                    temp);
2061         return 0;
2062     }
2063     if (temp == 0) {
2064         printf("All servers are running.\n");
2065     } else {
2066         printf
2067             ("These servers unavailable due to network or server problems: ");
2068         for (j = 0;; j++) {
2069             memcpy(&temp, space + j * sizeof(afs_int32), sizeof(afs_int32));
2070             if (temp == 0)
2071                 break;
2072             tp = hostutil_GetNameByINet(temp);
2073             printf(" %s", tp);
2074         }
2075         printf(".\n");
2076         code = 1;               /* XXX */
2077     }
2078     return code;
2079 }
2080
2081 static int
2082 MessagesCmd(struct cmd_syndesc *as, void *arock)
2083 {
2084     afs_int32 code = 0;
2085     struct ViceIoctl blob;
2086     struct gaginfo gagflags;
2087     struct cmd_item *show;
2088
2089     memset(&gagflags, 0, sizeof(struct gaginfo));
2090     blob.in_size = sizeof(struct gaginfo);
2091     blob.in = (caddr_t) & gagflags;
2092     blob.out_size = AFS_PIOCTL_MAXSIZE;
2093     blob.out = space;
2094     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
2095
2096     if ((show = as->parms[0].items)) {
2097         if (!strcasecmp(show->data, "user"))
2098             gagflags.showflags |= GAGUSER;
2099         else if (!strcasecmp(show->data, "console"))
2100             gagflags.showflags |= GAGCONSOLE;
2101         else if (!strcasecmp(show->data, "all"))
2102             gagflags.showflags |= GAGCONSOLE | GAGUSER;
2103         else if (!strcasecmp(show->data, "none"))
2104             /* do nothing */ ;
2105         else {
2106             fprintf(stderr,
2107                     "unrecognized flag %s: must be in {user,console,all,none}\n",
2108                     show->data);
2109             code = EINVAL;
2110         }
2111     }
2112
2113     if (code)
2114         return 1;
2115
2116     code = pioctl(0, VIOC_GAG, &blob, 1);
2117     if (code) {
2118         Die(errno, 0);
2119         return 1;
2120     }
2121
2122     return 0;
2123 }
2124
2125 static int
2126 CheckVolumesCmd(struct cmd_syndesc *as, void *arock)
2127 {
2128     afs_int32 code;
2129     struct ViceIoctl blob;
2130
2131     blob.in_size = 0;
2132     blob.out_size = 0;
2133     code = pioctl(0, VIOCCKBACK, &blob, 1);
2134     if (code) {
2135         Die(errno, 0);
2136         return 1;
2137     }
2138
2139     printf("All volumeID/name mappings checked.\n");
2140     return 0;
2141 }
2142
2143 static int
2144 PreCacheCmd(struct cmd_syndesc *as, void *arock)
2145 {
2146     afs_int32 code;
2147     struct ViceIoctl blob;
2148     afs_int32 temp;
2149
2150     if (!as->parms[0].items && !as->parms[1].items) {
2151         fprintf(stderr, "%s: syntax error in precache cmd.\n", pn);
2152         return 1;
2153     }
2154     if (as->parms[0].items) {
2155         code = util_GetInt32(as->parms[0].items->data, &temp);
2156         if (code) {
2157             fprintf(stderr, "%s: bad integer specified for precache size.\n",
2158                     pn);
2159             return 1;
2160         }
2161     } else
2162         temp = 0;
2163     blob.in = (char *)&temp;
2164     blob.in_size = sizeof(afs_int32);
2165     blob.out_size = 0;
2166     code = pioctl(0, VIOCPRECACHE, &blob, 1);
2167     if (code) {
2168         Die(errno, NULL);
2169         return 1;
2170     }
2171
2172     printf("New precache size set.\n");
2173     return 0;
2174 }
2175
2176 static int
2177 SetCacheSizeCmd(struct cmd_syndesc *as, void *arock)
2178 {
2179     afs_int32 code;
2180     struct ViceIoctl blob;
2181     afs_int32 temp;
2182
2183     if (!as->parms[0].items && !as->parms[1].items) {
2184         fprintf(stderr, "%s: syntax error in setcachesize cmd.\n", pn);
2185         return 1;
2186     }
2187     if (as->parms[0].items) {
2188         code = util_GetHumanInt32(as->parms[0].items->data, &temp);
2189         if (code) {
2190             fprintf(stderr, "%s: bad integer specified for cache size.\n",
2191                     pn);
2192             return 1;
2193         }
2194     } else
2195         temp = 0;
2196     blob.in = (char *)&temp;
2197     blob.in_size = sizeof(afs_int32);
2198     blob.out_size = 0;
2199     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
2200     if (code) {
2201         if (errno == EROFS) {
2202             printf
2203                 ("'fs setcache' not allowed on memory cache based cache managers.\n");
2204         } else {
2205             Die(errno, NULL);
2206         }
2207         return 1;
2208     }
2209
2210     printf("New cache size set.\n");
2211     return 0;
2212 }
2213
2214 #define MAXGCSIZE       16
2215 static int
2216 GetCacheParmsCmd(struct cmd_syndesc *as, void *arock)
2217 {
2218     afs_int32 code, filesUsed;
2219     struct ViceIoctl blob;
2220     afs_int32 parms[MAXGCSIZE];
2221     double percentFiles, percentBlocks;
2222     afs_int32 flags = 0;
2223
2224     if (as->parms[0].items){ /* -files */
2225         flags = 1;
2226     } else if (as->parms[1].items){ /* -excessive */
2227         flags = 2;
2228     } else {
2229         flags = 0;
2230     }
2231
2232     memset(parms, '\0', sizeof parms);  /* avoid Purify UMR error */
2233     if (flags){
2234         blob.in = (char *)&flags;
2235         blob.in_size = sizeof(afs_int32);
2236     } else {    /* be backward compatible */
2237         blob.in = NULL;
2238         blob.in_size = 0;
2239     }
2240     blob.out_size = sizeof(parms);
2241     blob.out = (char *)parms;
2242     code = pioctl(0, VIOCGETCACHEPARMS, &blob, 1);
2243     if (code) {
2244         Die(errno, NULL);
2245         return 1;
2246     }
2247
2248     if (!flags){
2249         printf("AFS using %d of the cache's available %d 1K byte blocks.\n",
2250                 parms[1], parms[0]);
2251         if (parms[1] > parms[0])
2252                 printf("[Cache guideline temporarily deliberately exceeded; it will be adjusted down but you may wish to increase the cache size.]\n");
2253         return 0;
2254     }
2255
2256     percentBlocks = ((double)parms[1]/parms[0]) * 100;
2257     printf("AFS using %5.0f%% of cache blocks (%d of %d 1k blocks)\n",
2258            percentBlocks, parms[1], parms[0]);
2259
2260     if (parms[2] == 0)
2261         return 0;
2262
2263     filesUsed = parms[2] - parms[3];
2264     percentFiles = ((double)filesUsed/parms[2]) * 100;
2265     printf("          %5.0f%% of the cache files (%d of %d files)\n",
2266             percentFiles, filesUsed, parms[2]);
2267     if (flags == 2){
2268         printf("        afs_cacheFiles: %10d\n", parms[2]);
2269         printf("        IFFree:         %10d\n", parms[3]);
2270         printf("        IFEverUsed:     %10d\n", parms[4]);
2271         printf("        IFDataMod:      %10d\n", parms[5]);
2272         printf("        IFDirtyPages:   %10d\n", parms[6]);
2273         printf("        IFAnyPages:     %10d\n", parms[7]);
2274         printf("        IFDiscarded:    %10d\n", parms[8]);
2275         printf("        DCentries:  %10d\n", parms[9]);
2276         printf("          0k-   4K: %10d\n", parms[10]);
2277         printf("          4k-  16k: %10d\n", parms[11]);
2278         printf("         16k-  64k: %10d\n", parms[12]);
2279         printf("         64k- 256k: %10d\n", parms[13]);
2280         printf("        256k-   1M: %10d\n", parms[14]);
2281         printf("              >=1M: %10d\n", parms[15]);
2282     }
2283
2284     if (percentBlocks > 90)
2285         printf("[cache size usage over 90%%, consider increasing cache size]\n");
2286     if (percentFiles > 90)
2287         printf("[cache file usage over 90%%, consider increasing '-files' argument to afsd]\n");
2288
2289     return 0;
2290 }
2291
2292 static int
2293 ListCellsCmd(struct cmd_syndesc *as, void *arock)
2294 {
2295     afs_int32 code;
2296     afs_int32 i, j;
2297     char *tp;
2298     struct ViceIoctl blob;
2299     int resolve;
2300
2301     resolve = !(as->parms[0].items);    /* -numeric */
2302
2303     for (i = 0;; i++) {
2304         tp = space;
2305         memcpy(tp, &i, sizeof(afs_int32));
2306         blob.out_size = AFS_PIOCTL_MAXSIZE;
2307         blob.in_size = sizeof(afs_int32);
2308         blob.in = space;
2309         blob.out = space;
2310         code = pioctl(0, VIOCGETCELL, &blob, 1);
2311         if (code < 0) {
2312             if (errno == EDOM)
2313                 break;          /* done with the list */
2314             Die(errno, 0);
2315             return 1;
2316         }
2317         tp = space;
2318         printf("Cell %s on hosts", tp + AFS_MAXCELLHOSTS * sizeof(afs_int32));
2319         for (j = 0; j < AFS_MAXCELLHOSTS; j++) {
2320             afs_int32 addr;
2321             char *name, tbuffer[20];
2322
2323             memcpy(&addr, tp + j * sizeof(afs_int32), sizeof(afs_int32));
2324             if (addr == 0)
2325                 break;
2326
2327             if (resolve) {
2328                 name = hostutil_GetNameByINet(addr);
2329             } else {
2330                 addr = ntohl(addr);
2331                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
2332                         (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
2333                 name = tbuffer;
2334             }
2335             printf(" %s", name);
2336         }
2337         printf(".\n");
2338     }
2339     return 0;
2340 }
2341
2342 static int
2343 ListAliasesCmd(struct cmd_syndesc *as, void *arock)
2344 {
2345     afs_int32 code, i;
2346     char *tp, *aliasName, *realName;
2347     struct ViceIoctl blob;
2348
2349     for (i = 0;; i++) {
2350         tp = space;
2351         memcpy(tp, &i, sizeof(afs_int32));
2352         blob.out_size = AFS_PIOCTL_MAXSIZE;
2353         blob.in_size = sizeof(afs_int32);
2354         blob.in = space;
2355         blob.out = space;
2356         code = pioctl(0, VIOC_GETALIAS, &blob, 1);
2357         if (code < 0) {
2358             if (errno == EDOM)
2359                 break;          /* done with the list */
2360             Die(errno, 0);
2361             return 1;
2362         }
2363         tp = space;
2364         aliasName = tp;
2365         tp += strlen(aliasName) + 1;
2366         realName = tp;
2367         printf("Alias %s for cell %s\n", aliasName, realName);
2368     }
2369     return 0;
2370 }
2371
2372 static int
2373 CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
2374 {
2375     afs_int32 code;
2376     struct ViceIoctl blob;
2377     struct cmd_item *ti;
2378     afs_int32 hostAddr;
2379     struct hostent *thp;
2380
2381     ti = as->parms[0].items;
2382     if (ti) {
2383         thp = hostutil_GetHostByName(ti->data);
2384         if (!thp) {
2385             fprintf(stderr, "host %s not found in host table.\n", ti->data);
2386             return 1;
2387         }
2388         else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2389     } else {
2390         hostAddr = 0;   /* means don't set host */
2391     }
2392
2393     /* now do operation */
2394     blob.in_size = sizeof(afs_int32);
2395     blob.out_size = sizeof(afs_int32);
2396     blob.in = (char *) &hostAddr;
2397     blob.out = (char *) &hostAddr;
2398
2399     code = pioctl(0, VIOC_CBADDR, &blob, 1);
2400     if (code < 0) {
2401         Die(errno, 0);
2402         return 1;
2403     }
2404     return 0;
2405 }
2406
2407 static int
2408 NukeNFSCredsCmd(struct cmd_syndesc *as, void *arock)
2409 {
2410     afs_int32 code;
2411     struct ViceIoctl blob;
2412     struct cmd_item *ti;
2413     afs_int32 hostAddr;
2414     struct hostent *thp;
2415
2416     ti = as->parms[0].items;
2417     thp = hostutil_GetHostByName(ti->data);
2418     if (!thp) {
2419         fprintf(stderr, "host %s not found in host table.\n", ti->data);
2420         return 1;
2421     }
2422     else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2423
2424     /* now do operation */
2425     blob.in_size = sizeof(afs_int32);
2426     blob.out_size = sizeof(afs_int32);
2427     blob.in = (char *) &hostAddr;
2428     blob.out = (char *) &hostAddr;
2429
2430     code = pioctl(0, VIOC_NFS_NUKE_CREDS, &blob, 1);
2431     if (code < 0) {
2432         Die(errno, 0);
2433         return 1;
2434     }
2435     return 0;
2436 }
2437
2438 static int
2439 NewCellCmd(struct cmd_syndesc *as, void *arock)
2440 {
2441     afs_int32 code, linkedstate = 0, size = 0, *lp;
2442     struct ViceIoctl blob;
2443     struct cmd_item *ti;
2444     char *tp, *cellname = 0;
2445     struct hostent *thp;
2446     afs_int32 fsport = 0, vlport = 0;
2447     afs_int32 scount;           /* Number of servers to pass in pioctl call */
2448
2449     /* Yuck!
2450      * With the NEWCELL pioctl call, 3.4 clients take an array of
2451      * AFS_MAXHOSTS (13) servers while 3.5 clients take an array of
2452      * AFS_MAXCELLHOSTS (8) servers. To determine which we are talking to,
2453      * do a GETCELL pioctl and pass it a magic number. If an array of
2454      * 8 comes back, its a 3.5 client. If not, its a 3.4 client.
2455      * If we get back EDOM, there are no cells in the kernel yet,
2456      * and we'll assume a 3.5 client.
2457      */
2458     tp = space;
2459     lp = (afs_int32 *) tp;
2460     *lp++ = 0;                  /* first cell entry */
2461     *lp = 0x12345678;           /* magic */
2462     blob.out_size = AFS_PIOCTL_MAXSIZE;
2463     blob.in_size = sizeof(afs_int32) + sizeof(afs_int32);
2464     blob.in = space;
2465     blob.out = space;
2466     code = pioctl(0, VIOCGETCELL, &blob, 1);
2467     if (code < 0 && errno != EDOM) {
2468         Die(errno, 0);
2469         return 1;
2470     }
2471     if (code < 1 && errno == EDOM) {
2472         scount = AFS_MAXHOSTS;
2473     } else {
2474         tp = space;
2475         cellname = tp + AFS_MAXCELLHOSTS * sizeof(afs_int32);
2476         scount = ((cellname[0] != '\0') ? AFS_MAXCELLHOSTS : AFS_MAXHOSTS);
2477     }
2478
2479     /* Now setup and do the NEWCELL pioctl call */
2480     memset(space, 0, (scount + 1) * sizeof(afs_int32));
2481     tp = space;
2482     lp = (afs_int32 *) tp;
2483     *lp++ = 0x12345678;
2484     tp += sizeof(afs_int32);
2485     for (ti = as->parms[1].items; ti; ti = ti->next) {
2486         thp = hostutil_GetHostByName(ti->data);
2487         if (!thp) {
2488             fprintf(stderr,
2489                     "%s: Host %s not found in host table, skipping it.\n", pn,
2490                     ti->data);
2491         } else {
2492             memcpy(tp, thp->h_addr, sizeof(afs_int32));
2493             tp += sizeof(afs_int32);
2494         }
2495     }
2496     if (as->parms[2].items) {
2497         /*
2498          * Link the cell, for the purposes of volume location, to the specified
2499          * cell.
2500          */
2501         cellname = as->parms[2].items->data;
2502         linkedstate = 1;
2503     }
2504 #ifdef FS_ENABLE_SERVER_DEBUG_PORTS
2505     if (as->parms[3].items) {
2506         code = util_GetInt32(as->parms[3].items->data, &vlport);
2507         if (code) {
2508             fprintf(stderr,
2509                     "%s: bad integer specified for the fileserver port.\n",
2510                     pn);
2511             return 1;
2512         }
2513     }
2514     if (as->parms[4].items) {
2515         code = util_GetInt32(as->parms[4].items->data, &fsport);
2516         if (code) {
2517             fprintf(stderr,
2518                     "%s: bad integer specified for the vldb server port.\n",
2519                     pn);
2520             return 1;
2521         }
2522     }
2523 #endif
2524     tp = (char *)(space + (scount + 1) * sizeof(afs_int32));
2525     lp = (afs_int32 *) tp;
2526     *lp++ = fsport;
2527     *lp++ = vlport;
2528     *lp = linkedstate;
2529     strcpy(space + ((scount + 4) * sizeof(afs_int32)),
2530            as->parms[0].items->data);
2531     size = ((scount + 4) * sizeof(afs_int32))
2532         + strlen(as->parms[0].items->data)
2533         + 1 /* for null */ ;
2534     tp = (char *)(space + size);
2535     if (linkedstate) {
2536         strcpy(tp, cellname);
2537         size += strlen(cellname) + 1;
2538     }
2539     blob.in_size = size;
2540     blob.in = space;
2541     blob.out_size = 0;
2542     code = pioctl(0, VIOCNEWCELL, &blob, 1);
2543     if (code < 0) {
2544         Die(errno, 0);
2545         return 1;
2546     }
2547     return 0;
2548 }
2549
2550 static int
2551 NewAliasCmd(struct cmd_syndesc *as, void *arock)
2552 {
2553     afs_int32 code;
2554     struct ViceIoctl blob;
2555     char *tp;
2556     char *aliasName, *realName;
2557
2558     /* Now setup and do the NEWCELL pioctl call */
2559     aliasName = as->parms[0].items->data;
2560     realName = as->parms[1].items->data;
2561     tp = space;
2562     strcpy(tp, aliasName);
2563     tp += strlen(aliasName) + 1;
2564     strcpy(tp, realName);
2565     tp += strlen(realName) + 1;
2566
2567     blob.in_size = tp - space;
2568     blob.in = space;
2569     blob.out_size = 0;
2570     blob.out = space;
2571     code = pioctl(0, VIOC_NEWALIAS, &blob, 1);
2572     if (code < 0) {
2573         if (errno == EEXIST) {
2574             fprintf(stderr,
2575                     "%s: cell name `%s' in use by an existing cell.\n", pn,
2576                     aliasName);
2577         } else {
2578             Die(errno, 0);
2579         }
2580         return 1;
2581     }
2582     return 0;
2583 }
2584
2585 static int
2586 WhichCellCmd(struct cmd_syndesc *as, void *arock)
2587 {
2588     afs_int32 code;
2589     struct cmd_item *ti;
2590     int error = 0;
2591     char cell[MAXCELLCHARS];
2592
2593     SetDotDefault(&as->parms[0].items);
2594     for (ti = as->parms[0].items; ti; ti = ti->next) {
2595         code = GetCell(ti->data, cell);
2596         if (code) {
2597             if (errno == ENOENT)
2598                 fprintf(stderr, "%s: no such cell as '%s'\n", pn, ti->data);
2599             else
2600                 Die(errno, ti->data);
2601             error = 1;
2602             continue;
2603         }
2604
2605         printf("File %s lives in cell '%s'\n", ti->data, cell);
2606     }
2607     return error;
2608 }
2609
2610 static int
2611 WSCellCmd(struct cmd_syndesc *as, void *arock)
2612 {
2613     afs_int32 code;
2614     struct ViceIoctl blob;
2615
2616     blob.in_size = 0;
2617     blob.in = NULL;
2618     blob.out_size = AFS_PIOCTL_MAXSIZE;
2619     blob.out = space;
2620
2621     code = pioctl(NULL, VIOC_GET_WS_CELL, &blob, 1);
2622     if (code) {
2623         Die(errno, NULL);
2624         return 1;
2625     }
2626
2627     printf("This workstation belongs to cell '%s'\n", space);
2628     return 0;
2629 }
2630
2631 /*
2632 static PrimaryCellCmd(as)
2633     struct cmd_syndesc *as;
2634 {
2635     fprintf(stderr, "This command is obsolete, as is the concept of a primary token.\n");
2636     return 0;
2637 }
2638 */
2639
2640 static int
2641 MonitorCmd(struct cmd_syndesc *as, void *arock)
2642 {
2643     afs_int32 code;
2644     struct ViceIoctl blob;
2645     struct cmd_item *ti;
2646     afs_int32 hostAddr;
2647     struct hostent *thp;
2648     char *tp;
2649     int setp;
2650
2651     ti = as->parms[0].items;
2652     setp = 1;
2653     if (ti) {
2654         /* set the host */
2655         if (!strcmp(ti->data, "off"))
2656             hostAddr = 0xffffffff;
2657         else {
2658             thp = hostutil_GetHostByName(ti->data);
2659             if (!thp) {
2660                 if (!strcmp(ti->data, "localhost")) {
2661                     fprintf(stderr,
2662                             "localhost not in host table, assuming 127.0.0.1\n");
2663                     hostAddr = htonl(0x7f000001);
2664                 } else {
2665                     fprintf(stderr, "host %s not found in host table.\n",
2666                             ti->data);
2667                     return 1;
2668                 }
2669             } else
2670                 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2671         }
2672     } else {
2673         hostAddr = 0;           /* means don't set host */
2674         setp = 0;               /* aren't setting host */
2675     }
2676
2677     /* now do operation */
2678     blob.in_size = sizeof(afs_int32);
2679     blob.out_size = sizeof(afs_int32);
2680     blob.in = (char *)&hostAddr;
2681     blob.out = (char *)&hostAddr;
2682     code = pioctl(0, VIOC_AFS_MARINER_HOST, &blob, 1);
2683     if (code) {
2684         Die(errno, 0);
2685         return 1;
2686     }
2687     if (setp) {
2688         printf("%s: new monitor host set.\n", pn);
2689     } else {
2690         /* now decode old address */
2691         if (hostAddr == 0xffffffff) {
2692             printf("Cache monitoring is currently disabled.\n");
2693         } else {
2694             tp = hostutil_GetNameByINet(hostAddr);
2695             printf("Using host %s for monitor services.\n", tp);
2696         }
2697     }
2698     return 0;
2699 }
2700
2701 static int
2702 SysNameCmd(struct cmd_syndesc *as, void *arock)
2703 {
2704     afs_int32 code;
2705     struct ViceIoctl blob;
2706     struct cmd_item *ti;
2707     char *input = space;
2708     afs_int32 setp = 0;
2709
2710     ti = as->parms[0].items;
2711     blob.in = space;
2712     blob.out = space;
2713     blob.out_size = AFS_PIOCTL_MAXSIZE;
2714     blob.in_size = sizeof(afs_int32);
2715     input += sizeof(afs_int32);
2716     for (; ti; ti = ti->next) {
2717         setp++;
2718         blob.in_size += strlen(ti->data) + 1;
2719         if (blob.in_size > AFS_PIOCTL_MAXSIZE) {
2720             fprintf(stderr, "%s: sysname%s too long.\n", pn,
2721                     setp > 1 ? "s" : "");
2722             return 1;
2723         }
2724         strcpy(input, ti->data);
2725         input += strlen(ti->data);
2726         *(input++) = '\0';
2727     }
2728     memcpy(space, &setp, sizeof(afs_int32));
2729     code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
2730     if (code) {
2731         Die(errno, 0);
2732         return 1;
2733     }
2734     if (setp) {
2735         printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
2736         return 0;
2737     }
2738     input = space;
2739     memcpy(&setp, input, sizeof(afs_int32));
2740     input += sizeof(afs_int32);
2741     if (!setp) {
2742         fprintf(stderr, "No sysname name value was found\n");
2743         return 1;
2744     }
2745     printf("Current sysname%s is", setp > 1 ? " list" : "");
2746     for (; setp > 0; --setp) {
2747         printf(" \'%s\'", input);
2748         input += strlen(input) + 1;
2749     }
2750     printf("\n");
2751     return 0;
2752 }
2753
2754 static char *exported_types[] = { "null", "nfs", "" };
2755 static int
2756 ExportAfsCmd(struct cmd_syndesc *as, void *arock)
2757 {
2758     afs_int32 code;
2759     struct ViceIoctl blob;
2760     struct cmd_item *ti;
2761     int export = 0, type = 0, mode = 0, exportcall, pwsync =
2762         0, smounts = 0, clipags = 0, pagcb = 0;
2763
2764     ti = as->parms[0].items;
2765     if (strcmp(ti->data, "nfs") == 0)
2766         type = 0x71;            /* NFS */
2767     else {
2768         fprintf(stderr,
2769                 "Invalid exporter type, '%s', Only the 'nfs' exporter is currently supported\n",
2770                 ti->data);
2771         return 1;
2772     }
2773     ti = as->parms[1].items;
2774     if (ti) {
2775         if (strcmp(ti->data, "on") == 0)
2776             export = 3;
2777         else if (strcmp(ti->data, "off") == 0)
2778             export = 2;
2779         else {
2780             fprintf(stderr, "Illegal argument %s\n", ti->data);
2781             return 1;
2782         }
2783     }
2784     if ((ti = as->parms[2].items)) {    /* -noconvert */
2785         if (strcmp(ti->data, "on") == 0)
2786             mode = 2;
2787         else if (strcmp(ti->data, "off") == 0)
2788             mode = 3;
2789         else {
2790             fprintf(stderr, "Illegal argument %s\n", ti->data);
2791             return 1;
2792         }
2793     }
2794     if ((ti = as->parms[3].items)) {    /* -uidcheck */
2795         if (strcmp(ti->data, "on") == 0)
2796             pwsync = 3;
2797         else if (strcmp(ti->data, "off") == 0)
2798             pwsync = 2;
2799         else {
2800             fprintf(stderr, "Illegal argument %s\n", ti->data);
2801             return 1;
2802         }
2803     }
2804     if ((ti = as->parms[4].items)) {    /* -submounts */
2805         if (strcmp(ti->data, "on") == 0)
2806             smounts = 3;
2807         else if (strcmp(ti->data, "off") == 0)
2808             smounts = 2;
2809         else {
2810             fprintf(stderr, "Illegal argument %s\n", ti->data);
2811             return 1;
2812         }
2813     }
2814     if ((ti = as->parms[5].items)) {    /* -clipags */
2815         if (strcmp(ti->data, "on") == 0)
2816             clipags = 3;
2817         else if (strcmp(ti->data, "off") == 0)
2818             clipags = 2;
2819         else {
2820             fprintf(stderr, "Illegal argument %s\n", ti->data);
2821             return 1;
2822         }
2823     }
2824     if ((ti = as->parms[6].items)) {    /* -pagcb */
2825         if (strcmp(ti->data, "on") == 0)
2826             pagcb = 3;
2827         else if (strcmp(ti->data, "off") == 0)
2828             pagcb = 2;
2829         else {
2830             fprintf(stderr, "Illegal argument %s\n", ti->data);
2831             return 1;
2832         }
2833     }
2834     exportcall =
2835         (type << 24) | (pagcb << 10) | (clipags << 8) |
2836         (mode << 6) | (pwsync << 4) | (smounts << 2) | export;
2837     type &= ~0x70;
2838     /* make the call */
2839     blob.in = (char *)&exportcall;
2840     blob.in_size = sizeof(afs_int32);
2841     blob.out = (char *)&exportcall;
2842     blob.out_size = sizeof(afs_int32);
2843     code = pioctl(0, VIOC_EXPORTAFS, &blob, 1);
2844     if (code) {
2845         if (errno == ENODEV) {
2846             fprintf(stderr,
2847                     "Sorry, the %s-exporter type is currently not supported on this AFS client\n",
2848                     exported_types[type]);
2849         } else {
2850             Die(errno, 0);
2851         }
2852         return 1;
2853     }
2854
2855     if (exportcall & 1) {
2856         printf("'%s' translator is enabled with the following options:\n",
2857                exported_types[type]);
2858         printf("\tRunning in %s mode\n",
2859                (exportcall & 2 ? "strict unix" :
2860                 "convert owner mode bits to world/other"));
2861         printf("\tRunning in %s mode\n",
2862                (exportcall & 4 ? "strict 'passwd sync'" :
2863                 "no 'passwd sync'"));
2864         printf("\t%s\n",
2865                (exportcall & 8 ? "Allow mounts of /afs/.. subdirs" :
2866                 "Only mounts to /afs allowed"));
2867         printf("\t%s\n",
2868                (exportcall & 16 ? "Client-assigned PAG's are used" :
2869                 "Client-assigned PAG's are not used"));
2870         printf("\t%s\n",
2871                (exportcall & 32 ?
2872                 "Callbacks are made to get creds from new clients" :
2873                 "Callbacks are not made to get creds from new clients"));
2874     } else {
2875         printf("'%s' translator is disabled\n", exported_types[type]);
2876     }
2877     return 0;
2878 }
2879
2880
2881 static int
2882 GetCellCmd(struct cmd_syndesc *as, void *arock)
2883 {
2884     afs_int32 code;
2885     struct ViceIoctl blob;
2886     struct afsconf_cell info;
2887     struct cmd_item *ti;
2888     struct a {
2889         afs_int32 stat;
2890         afs_int32 junk;
2891     } args;
2892     int error = 0;
2893
2894     memset(&args, '\0', sizeof args);   /* avoid Purify UMR error */
2895     for (ti = as->parms[0].items; ti; ti = ti->next) {
2896         /* once per cell */
2897         blob.out_size = sizeof(args);
2898         blob.out = (caddr_t) & args;
2899         code = GetCellName(ti->data, &info);
2900         if (code) {
2901             error = 1;
2902             continue;
2903         }
2904         blob.in_size = 1 + strlen(info.name);
2905         blob.in = info.name;
2906         code = pioctl(0, VIOC_GETCELLSTATUS, &blob, 1);
2907         if (code) {
2908             if (errno == ENOENT)
2909                 fprintf(stderr, "%s: the cell named '%s' does not exist\n",
2910                         pn, info.name);
2911             else
2912                 Die(errno, info.name);
2913             error = 1;
2914             continue;
2915         }
2916         printf("Cell %s status: ", info.name);
2917 #ifdef notdef
2918         if (args.stat & 1)
2919             printf("primary ");
2920 #endif
2921         if (args.stat & 2)
2922             printf("no setuid allowed");
2923         else
2924             printf("setuid allowed");
2925         if (args.stat & 4)
2926             printf(", using old VLDB");
2927         printf("\n");
2928     }
2929     return error;
2930 }
2931
2932 static int
2933 SetCellCmd(struct cmd_syndesc *as, void *arock)
2934 {
2935     afs_int32 code;
2936     struct ViceIoctl blob;
2937     struct afsconf_cell info;
2938     struct cmd_item *ti;
2939     struct a {
2940         afs_int32 stat;
2941         afs_int32 junk;
2942         char cname[64];
2943     } args;
2944     int error = 0;
2945
2946     /* Check arguments. */
2947     if (as->parms[1].items && as->parms[2].items) {
2948         fprintf(stderr, "Cannot specify both -suid and -nosuid.\n");
2949         return 1;
2950     }
2951
2952     /* figure stuff to set */
2953     args.stat = 0;
2954     args.junk = 0;
2955
2956     if (!as->parms[1].items)
2957         args.stat |= 2;         /* default to -nosuid */
2958
2959     /* set stat for all listed cells */
2960     for (ti = as->parms[0].items; ti; ti = ti->next) {
2961         /* once per cell */
2962         code = GetCellName(ti->data, &info);
2963         if (code) {
2964             error = 1;
2965             continue;
2966         }
2967         strcpy(args.cname, info.name);
2968         blob.in_size = sizeof(args);
2969         blob.in = (caddr_t) & args;
2970         blob.out_size = 0;
2971         blob.out = (caddr_t) 0;
2972         code = pioctl(0, VIOC_SETCELLSTATUS, &blob, 1);
2973         if (code) {
2974             Die(errno, info.name);      /* XXX added cell name to Die() call */
2975             error = 1;
2976         }
2977     }
2978     return error;
2979 }
2980
2981 static int
2982 GetCellName(char *cellName, struct afsconf_cell *info)
2983 {
2984     struct afsconf_dir *tdir;
2985     int code;
2986
2987     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
2988     if (!tdir) {
2989         fprintf(stderr,
2990                 "Could not process files in configuration directory (%s).\n",
2991                 AFSDIR_CLIENT_ETC_DIRPATH);
2992         return -1;
2993     }
2994
2995     code = afsconf_GetCellInfo(tdir, cellName, AFSCONF_VLDBSERVICE, info);
2996     if (code) {
2997         fprintf(stderr, "%s: cell %s not in %s\n", pn, cellName,
2998                 AFSDIR_CLIENT_CELLSERVDB_FILEPATH);
2999         return code;
3000     }
3001
3002     return 0;
3003 }
3004
3005
3006 static int
3007 VLDBInit(int noAuthFlag, struct afsconf_cell *info)
3008 {
3009     afs_int32 code;
3010
3011     code = ugen_ClientInit(noAuthFlag, (char *) AFSDIR_CLIENT_ETC_DIRPATH,
3012                            info->name, 0, &uclient,
3013                            NULL, pn, rxkad_clear,
3014                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
3015                            0, 0, USER_SERVICE_ID);
3016     rxInitDone = 1;
3017     return code;
3018 }
3019
3020 static struct ViceIoctl gblob;
3021 static int debug = 0;
3022 /*
3023  * here follow some routines in suport of the setserverprefs and
3024  * getserverprefs commands.  They are:
3025  * SetPrefCmd  "top-level" routine
3026  * addServer   adds a server to the list of servers to be poked into the
3027  *             kernel.  Will poke the list into the kernel if it threatens
3028  *             to get too large.
3029  * pokeServers pokes the existing list of servers and ranks into the kernel
3030  * GetPrefCmd  reads the Cache Manager's current list of server ranks
3031  */
3032
3033 /*
3034  * returns -1 if error message printed,
3035  * 0 on success,
3036  * errno value if error and no error message printed
3037  */
3038 static int
3039 pokeServers(void)
3040 {
3041     int code;
3042
3043     code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
3044     if (code && (errno == EINVAL)) {
3045         struct setspref *ssp;
3046         ssp = (struct setspref *)gblob.in;
3047         if (!(ssp->flags & DBservers)) {
3048             gblob.in = (void *)&(ssp->servers[0]);
3049             gblob.in_size -= ((char *)&(ssp->servers[0])) - (char *)ssp;
3050             code = pioctl(0, VIOC_SETSPREFS33, &gblob, 1);
3051             return code ? errno : 0;
3052         }
3053         fprintf(stderr,
3054                 "This cache manager does not support VL server preferences.\n");
3055         return -1;
3056     }
3057
3058     return code ? errno : 0;
3059 }
3060
3061 /*
3062  * returns -1 if error message printed,
3063  * 0 on success,
3064  * errno value if error and no error message printed
3065  */
3066 static int
3067 addServer(char *name, afs_int32 rank)
3068 {
3069     int t, code;
3070     struct setspref *ssp;
3071     struct spref *sp;
3072     struct hostent *thostent;
3073     int error = 0;
3074
3075 #ifndef MAXUSHORT
3076 #ifdef MAXSHORT
3077 #define MAXUSHORT ((unsigned short) 2*MAXSHORT+1)       /* assumes two's complement binary system */
3078 #else
3079 #define MAXUSHORT ((unsigned short) ~0)
3080 #endif
3081 #endif
3082
3083     thostent = hostutil_GetHostByName(name);
3084     if (!thostent) {
3085         fprintf(stderr, "%s: couldn't resolve name.\n", name);
3086         return -1;
3087     }
3088
3089     ssp = (struct setspref *)(gblob.in);
3090
3091     for (t = 0; thostent->h_addr_list[t]; t++) {
3092         if (gblob.in_size > MAXINSIZE - sizeof(struct spref)) {
3093             code = pokeServers();
3094             if (code)
3095                 error = code;
3096             ssp->num_servers = 0;
3097         }
3098
3099         sp = (struct spref *)(gblob.in + gblob.in_size);
3100         memcpy(&(sp->server.s_addr), thostent->h_addr_list[t],
3101                sizeof(afs_uint32));
3102         sp->rank = (rank > MAXUSHORT ? MAXUSHORT : rank);
3103         gblob.in_size += sizeof(struct spref);
3104         ssp->num_servers++;
3105
3106         if (debug)
3107             fprintf(stderr, "adding server %s, rank %d, ip addr 0x%lx\n",
3108                     name, sp->rank, (long unsigned int) sp->server.s_addr);
3109     }
3110
3111     return error;
3112 }
3113
3114
3115 static int
3116 SetPrefCmd(struct cmd_syndesc *as, void *arock)
3117 {
3118     FILE *infd;
3119     afs_int32 code;
3120     struct cmd_item *ti;
3121     char name[80];
3122     afs_int32 rank;
3123     struct setspref *ssp;
3124     int error = 0;              /* -1 means error message printed,
3125                                  * >0 means errno value for unprinted message */
3126
3127     ssp = (struct setspref *)space;
3128     ssp->flags = 0;
3129     ssp->num_servers = 0;
3130     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3131     gblob.in = space;
3132     gblob.out = space;
3133     gblob.out_size = AFS_PIOCTL_MAXSIZE;
3134
3135
3136     if (geteuid()) {
3137         fprintf(stderr, "Permission denied: requires root access.\n");
3138         return 1;
3139     }
3140
3141     ti = as->parms[2].items;    /* -file */
3142     if (ti) {
3143         if (debug)
3144             fprintf(stderr, "opening file %s\n", ti->data);
3145         if (!(infd = fopen(ti->data, "r"))) {
3146             perror(ti->data);
3147             error = -1;
3148         } else {
3149             while (fscanf(infd, "%79s%ld", name, (long int *)&rank) != EOF) {
3150                 code = addServer(name, (unsigned short)rank);
3151                 if (code)
3152                     error = code;
3153             }
3154         }
3155     }
3156
3157     ti = as->parms[3].items;    /* -stdin */
3158     if (ti) {
3159         while (scanf("%79s%ld", name, (long int *)&rank) != EOF) {
3160             code = addServer(name, (unsigned short)rank);
3161             if (code)
3162                 error = code;
3163         }
3164     }
3165
3166     for (ti = as->parms[0].items; ti; ti = ti->next) {  /* list of servers, ranks */
3167         if (ti) {
3168             if (!ti->next) {
3169                 break;
3170             }
3171             code = addServer(ti->data, (unsigned short)atol(ti->next->data));
3172             if (code)
3173                 error = code;
3174             if (debug)
3175                 printf("set fs prefs %s %s\n", ti->data, ti->next->data);
3176             ti = ti->next;
3177         }
3178     }
3179     code = pokeServers();
3180     if (code)
3181         error = code;
3182     if (debug)
3183         printf("now working on vlservers, code=%d\n", code);
3184
3185     ssp = (struct setspref *)space;
3186     ssp->flags = DBservers;
3187     ssp->num_servers = 0;
3188     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3189     gblob.in = space;
3190
3191     for (ti = as->parms[1].items; ti; ti = ti->next) {  /* list of dbservers, ranks */
3192         if (ti) {
3193             if (!ti->next) {
3194                 break;
3195             }
3196             code = addServer(ti->data, (unsigned short)atol(ti->next->data));
3197             if (code)
3198                 error = code;
3199             if (debug)
3200                 printf("set vl prefs %s %s\n", ti->data, ti->next->data);
3201             ti = ti->next;
3202         }
3203     }
3204
3205     if (as->parms[1].items) {
3206         if (debug)
3207             printf("now poking vlservers\n");
3208         code = pokeServers();
3209         if (code)
3210             error = code;
3211     }
3212
3213     if (error > 0)
3214         Die(error, 0);
3215
3216     return error ? 1 : 0;
3217 }
3218
3219
3220
3221 static int
3222 GetPrefCmd(struct cmd_syndesc *as, void *arock)
3223 {
3224     afs_int32 code;
3225     struct cmd_item *ti;
3226     char *name, tbuffer[20];
3227     afs_int32 addr;
3228     FILE *outfd;
3229     int resolve;
3230     int vlservers = 0;
3231     struct ViceIoctl blob;
3232     struct sprefrequest *in;
3233     struct sprefinfo *out;
3234     int i;
3235
3236     ti = as->parms[0].items;    /* -file */
3237     if (ti) {
3238         if (debug)
3239             fprintf(stderr, "opening file %s\n", ti->data);
3240         if (!(outfd = freopen(ti->data, "w", stdout))) {
3241             perror(ti->data);
3242             return 1;
3243         }
3244     }
3245
3246     ti = as->parms[1].items;    /* -numeric */
3247     resolve = !(ti);
3248     ti = as->parms[2].items;    /* -vlservers */
3249     vlservers |= (ti ? DBservers : 0);
3250     /*  ti = as->parms[3].items;   -cell */
3251
3252     in = (struct sprefrequest *)space;
3253     in->offset = 0;
3254
3255     do {
3256         blob.in_size = sizeof(struct sprefrequest);
3257         blob.in = (char *)in;
3258         blob.out = space;
3259         blob.out_size = AFS_PIOCTL_MAXSIZE;
3260
3261         in->num_servers =
3262             (AFS_PIOCTL_MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
3263         in->flags = vlservers;
3264
3265         do {
3266             code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
3267             if (code) {
3268                 if ((errno != E2BIG) || (2 * blob.out_size > 0x7FFF)) {
3269                     perror("getserverprefs pioctl");
3270                     return 1;
3271                 }
3272                 blob.out_size *= 2;
3273                 if (blob.out == space)
3274                     blob.out = malloc(blob.out_size);
3275                 else
3276                     blob.out = realloc(blob.out, blob.out_size);
3277             }
3278         } while (code != 0);
3279
3280         out = (struct sprefinfo *)blob.out;
3281
3282         for (i = 0; i < out->num_servers; i++) {
3283             if (resolve) {
3284                 name = hostutil_GetNameByINet(out->servers[i].server.s_addr);
3285             } else {
3286                 addr = ntohl(out->servers[i].server.s_addr);
3287                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
3288                         (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
3289                 name = tbuffer;
3290             }
3291             printf("%-50s %5u\n", name, out->servers[i].rank);
3292         }
3293
3294         in->offset = out->next_offset;
3295     } while (out->next_offset > 0);
3296
3297     if (blob.out != space)
3298         free(blob.out);
3299
3300     return 0;
3301 }
3302
3303 static int
3304 StoreBehindCmd(struct cmd_syndesc *as, void *arock)
3305 {
3306     afs_int32 code = 0;
3307     struct ViceIoctl blob;
3308     struct cmd_item *ti;
3309     struct sbstruct tsb, tsb2;
3310     int verbose = 0;
3311     afs_int32 allfiles;
3312     char *t;
3313     int error = 0;
3314
3315     tsb.sb_thisfile = -1;
3316     ti = as->parms[0].items;    /* -kbytes */
3317     if (ti) {
3318         if (!as->parms[1].items) {
3319             fprintf(stderr, "%s: you must specify -files with -kbytes.\n",
3320                     pn);
3321             return 1;
3322         }
3323         tsb.sb_thisfile = strtol(ti->data, &t, 10) * 1024;
3324         if ((tsb.sb_thisfile < 0) || (t != ti->data + strlen(ti->data))) {
3325             fprintf(stderr, "%s: %s must be 0 or a positive number.\n", pn,
3326                     ti->data);
3327             return 1;
3328         }
3329     }
3330
3331     allfiles = tsb.sb_default = -1;     /* Don't set allfiles yet */
3332     ti = as->parms[2].items;    /* -allfiles */
3333     if (ti) {
3334         allfiles = strtol(ti->data, &t, 10) * 1024;
3335         if ((allfiles < 0) || (t != ti->data + strlen(ti->data))) {
3336             fprintf(stderr, "%s: %s must be 0 or a positive number.\n", pn,
3337                     ti->data);
3338             return 1;
3339         }
3340     }
3341
3342     /* -verbose or -file only or no options */
3343     if (as->parms[3].items || (as->parms[1].items && !as->parms[0].items)
3344         || (!as->parms[0].items && !as->parms[1].items
3345             && !as->parms[2].items))
3346         verbose = 1;
3347
3348     blob.in = (char *)&tsb;
3349     blob.in_size = sizeof(struct sbstruct);
3350
3351     /* once per -file */
3352     for (ti = as->parms[1].items; ti; ti = ti->next) {
3353         /* Do this solely to see if the file is there */
3354
3355         blob.out = space;
3356         blob.out_size = AFS_PIOCTL_MAXSIZE;
3357         code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
3358         if (code) {
3359             Die(errno, ti->data);
3360             error = 1;
3361             continue;
3362         }
3363
3364         memset(&tsb2, 0, sizeof(tsb2));
3365         blob.out = (char *)&tsb2;
3366         blob.out_size = sizeof(struct sbstruct);
3367         code = pioctl(ti->data, VIOC_STORBEHIND, &blob, 1);
3368         if (code) {
3369             Die(errno, ti->data);
3370             error = 1;
3371             continue;
3372         }
3373
3374         if (verbose && (blob.out_size == sizeof(tsb2))) {
3375             if (tsb2.sb_thisfile == -1) {
3376                 fprintf(stdout, "Will store %s according to default.\n",
3377                         ti->data);
3378             } else {
3379                 fprintf(stdout,
3380                         "Will store up to %d kbytes of %s asynchronously.\n",
3381                         (tsb2.sb_thisfile / 1024), ti->data);
3382             }
3383         }
3384     }
3385
3386     /* If no files - make at least one pioctl call, or
3387      * set the allfiles default if we need to.
3388      */
3389     if (!as->parms[1].items || (allfiles != -1)) {
3390         tsb.sb_default = allfiles;
3391         memset(&tsb2, 0, sizeof(tsb2));
3392         blob.out = (char *)&tsb2;
3393         blob.out_size = sizeof(struct sbstruct);
3394         code = pioctl(0, VIOC_STORBEHIND, &blob, 1);
3395         if (code) {
3396             Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
3397             error = 1;
3398         }
3399     }
3400
3401     /* Having no arguments also reports the default store asynchrony */
3402     if (!error && verbose && (blob.out_size == sizeof(tsb2))) {
3403         fprintf(stdout, "Default store asynchrony is %d kbytes.\n",
3404                 (tsb2.sb_default / 1024));
3405     }
3406
3407     return error;
3408 }
3409
3410
3411 static int
3412 SetCryptCmd(struct cmd_syndesc *as, void *arock)
3413 {
3414     afs_int32 code = 0, flag;
3415     struct ViceIoctl blob;
3416     char *tp;
3417
3418     tp = as->parms[0].items->data;
3419     if (strcmp(tp, "on") == 0)
3420         flag = 1;
3421     else if (strcmp(tp, "off") == 0)
3422         flag = 0;
3423     else {
3424         fprintf(stderr, "%s: %s must be \"on\" or \"off\".\n", pn, tp);
3425         return EINVAL;
3426     }
3427
3428     blob.in = (char *)&flag;
3429     blob.in_size = sizeof(flag);
3430     blob.out_size = 0;
3431     code = pioctl(0, VIOC_SETRXKCRYPT, &blob, 1);
3432     if (code)
3433         Die(errno, NULL);
3434     return 0;
3435 }
3436
3437
3438 static int
3439 GetCryptCmd(struct cmd_syndesc *as, void *arock)
3440 {
3441     afs_int32 code = 0, flag;
3442     struct ViceIoctl blob;
3443     char *tp;
3444
3445     blob.in = NULL;
3446     blob.in_size = 0;
3447     blob.out_size = sizeof(flag);
3448     blob.out = space;
3449
3450     code = pioctl(0, VIOC_GETRXKCRYPT, &blob, 1);
3451
3452     if (code)
3453         Die(errno, NULL);
3454     else {
3455         tp = space;
3456         memcpy(&flag, tp, sizeof(afs_int32));
3457         printf("Security level is currently ");
3458         if (flag == 1)
3459             printf("crypt (data security).\n");
3460         else
3461             printf("clear.\n");
3462     }
3463     return 0;
3464 }
3465
3466 static char *modenames[] = {
3467     "offline",
3468     "online",
3469     "readonly",  /* Not currently supported */
3470     "fetchonly", /* Not currently supported */
3471     "partial",   /* Not currently supported */
3472     NULL
3473 };
3474
3475 static char *policynames[] = {
3476     "client",
3477     "server",
3478     "closer",  /* Not currently supported. */
3479     "manual",  /* Not currently supported. */
3480     NULL
3481 };
3482
3483 static int
3484 DisconCmd(struct cmd_syndesc *as, void *arock)
3485 {
3486     struct cmd_item *ti;
3487     char *modename;
3488     char *policyname;
3489     int modelen, policylen;
3490     afs_int32 mode, policy, code, unixuid = 0;
3491     struct ViceIoctl blob;
3492
3493     blob.in = NULL;
3494     blob.in_size = 0;
3495
3496     space[0] = space[1] = space[2] = space[3] = 0;
3497
3498     ti = as->parms[0].items;
3499     if (ti) {
3500         modename = ti->data;
3501         modelen = strlen(modename);
3502         for (mode = 0; modenames[mode] != NULL; mode++)
3503             if (!strncasecmp(modename, modenames[mode], modelen))
3504                 break;
3505         if (modenames[mode] == NULL)
3506             printf("Unknown discon mode \"%s\"\n", modename);
3507         else {
3508             space[0] = mode + 1;
3509         }
3510     }
3511     ti = as->parms[1].items;
3512     if (ti) {
3513         policyname = ti->data;
3514         policylen = strlen(policyname);
3515         for (policy = 0; policynames[policy] != NULL; policy++)
3516             if (!strncasecmp(policyname, policynames[policy], policylen))
3517                 break;
3518         if (policynames[policy] == NULL)
3519             printf("Unknown discon mode \"%s\"\n", policyname);
3520         else {
3521             space[1] = policy + 1;
3522         }
3523     }
3524
3525     if (as->parms[2].items) {
3526         space[2] = 1;
3527         printf("force on\n");
3528     }
3529
3530     ti = as->parms[3].items;
3531     if (ti) {
3532         code = util_GetInt32(ti->data, &unixuid);
3533         if (code) {
3534             fprintf(stderr, "%s: bad integer specified for uid.\n", pn);
3535             return 1;
3536         }
3537         space[3] = unixuid;
3538     } else
3539         space[3] = 0;
3540
3541     blob.in = space;
3542     blob.in_size = 4 * sizeof(afs_int32);
3543
3544     blob.out_size = sizeof(mode);
3545     blob.out = space;
3546     code = pioctl(0, VIOC_DISCON, &blob, 1);
3547     if (code)
3548         Die(errno, NULL);
3549     else {
3550         memcpy(&mode, space, sizeof mode);
3551         if (mode < sizeof modenames / sizeof (char *))
3552             printf("Discon mode is now \"%s\"\n", modenames[mode]);
3553         else
3554             printf("Unknown discon mode %d\n", mode);
3555     }
3556
3557     return 0;
3558 }
3559
3560 #include "AFS_component_version_number.c"
3561
3562 int
3563 main(int argc, char **argv)
3564 {
3565     afs_int32 code;
3566     struct cmd_syndesc *ts;
3567
3568 #ifdef  AFS_AIX32_ENV
3569     /*
3570      * The following signal action for AIX is necessary so that in case of a
3571      * crash (i.e. core is generated) we can include the user's data section
3572      * in the core dump. Unfortunately, by default, only a partial core is
3573      * generated which, in many cases, isn't too useful.
3574      */
3575     struct sigaction nsa;
3576
3577     sigemptyset(&nsa.sa_mask);
3578     nsa.sa_handler = SIG_DFL;
3579     nsa.sa_flags = SA_FULLDUMP;
3580     sigaction(SIGSEGV, &nsa, NULL);
3581 #endif
3582
3583     /* try to find volume location information */
3584     ts = cmd_CreateSyntax("getclientaddrs", GetClientAddrsCmd, NULL,
3585                           "get client network interface addresses");
3586     cmd_CreateAlias(ts, "gc");
3587
3588     ts = cmd_CreateSyntax("setclientaddrs", SetClientAddrsCmd, NULL,
3589                           "set client network interface addresses");
3590     cmd_AddParm(ts, "-address", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
3591                 "client network interfaces");
3592     cmd_CreateAlias(ts, "sc");
3593
3594     ts = cmd_CreateSyntax("setserverprefs", SetPrefCmd, NULL,
3595                           "set server ranks");
3596     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
3597                 "fileserver names and ranks");
3598     cmd_AddParm(ts, "-vlservers", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
3599                 "VL server names and ranks");
3600     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL,
3601                 "input from named file");
3602     cmd_AddParm(ts, "-stdin", CMD_FLAG, CMD_OPTIONAL, "input from stdin");
3603     cmd_CreateAlias(ts, "sp");
3604
3605     ts = cmd_CreateSyntax("getserverprefs", GetPrefCmd, NULL,
3606                           "get server ranks");
3607     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL,
3608                 "output to named file");
3609     cmd_AddParm(ts, "-numeric", CMD_FLAG, CMD_OPTIONAL, "addresses only");
3610     cmd_AddParm(ts, "-vlservers", CMD_FLAG, CMD_OPTIONAL, "VL servers");
3611 /*    cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */
3612     cmd_CreateAlias(ts, "gp");
3613
3614     ts = cmd_CreateSyntax("setacl", SetACLCmd, NULL, "set access control list");
3615     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
3616     cmd_AddParm(ts, "-acl", CMD_LIST, 0, "access list entries");
3617     cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, "clear access list");
3618     cmd_AddParm(ts, "-negative", CMD_FLAG, CMD_OPTIONAL,
3619                 "apply to negative rights");
3620     parm_setacl_id = ts->nParms;
3621     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL,
3622                 "initial directory acl (DFS only)");
3623     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL,
3624                 "initial file acl (DFS only)");
3625     cmd_CreateAlias(ts, "sa");
3626
3627     ts = cmd_CreateSyntax("listacl", ListACLCmd, NULL,
3628                           "list access control list");
3629     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3630     parm_listacl_id = ts->nParms;
3631     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl");
3632     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl");
3633     cmd_AddParm(ts, "-cmd", CMD_FLAG, CMD_OPTIONAL, "output as 'fs setacl' command");
3634     cmd_CreateAlias(ts, "la");
3635
3636     ts = cmd_CreateSyntax("getcalleraccess", GetCallerAccess, NULL,
3637             "list callers access");
3638     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3639     cmd_CreateAlias(ts, "gca");
3640
3641     ts = cmd_CreateSyntax("cleanacl", CleanACLCmd, NULL,
3642                           "clean up access control list");
3643     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3644
3645     ts = cmd_CreateSyntax("copyacl", CopyACLCmd, NULL,
3646                           "copy access control list");
3647     cmd_AddParm(ts, "-fromdir", CMD_SINGLE, 0,
3648                 "source directory (or DFS file)");
3649     cmd_AddParm(ts, "-todir", CMD_LIST, 0,
3650                 "destination directory (or DFS file)");
3651     cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL,
3652                 "first clear dest access list");
3653     parm_copyacl_id = ts->nParms;
3654     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl");
3655     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl");
3656
3657     cmd_CreateAlias(ts, "ca");
3658
3659     ts = cmd_CreateSyntax("flush", FlushCmd, NULL, "flush file from cache");
3660     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3661     ts = cmd_CreateSyntax("flushmount", FlushMountCmd, NULL,
3662                           "flush mount symlink from cache");
3663     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3664
3665     ts = cmd_CreateSyntax("setvol", SetVolCmd, NULL, "set volume status");
3666     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3667     cmd_AddParm(ts, "-max", CMD_SINGLE, CMD_OPTIONAL,
3668                 "disk space quota in 1K units");
3669 #ifdef notdef
3670     cmd_AddParm(ts, "-min", CMD_SINGLE, CMD_OPTIONAL,
3671                 "disk space guaranteed");
3672     cmd_AddParm(ts, "-motd", CMD_SINGLE, CMD_OPTIONAL, "message of the day");
3673 #endif
3674     cmd_AddParm(ts, "-offlinemsg", CMD_SINGLE, CMD_OPTIONAL,
3675                 "offline message");
3676     cmd_CreateAlias(ts, "sv");
3677
3678     ts = cmd_CreateSyntax("messages", MessagesCmd, NULL,
3679                           "control Cache Manager messages");
3680     cmd_AddParm(ts, "-show", CMD_SINGLE, CMD_OPTIONAL,
3681                 "[user|console|all|none]");
3682
3683     ts = cmd_CreateSyntax("examine", ExamineCmd, NULL, "display file/volume status");
3684     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3685     cmd_CreateAlias(ts, "lv");
3686     cmd_CreateAlias(ts, "listvol");
3687
3688     ts = cmd_CreateSyntax("listquota", ListQuotaCmd, NULL, "list volume quota");
3689     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3690     cmd_AddParm(ts, "-human", CMD_FLAG, CMD_OPTIONAL, "human-readable listing");
3691     cmd_CreateAlias(ts, "lq");
3692
3693     ts = cmd_CreateSyntax("diskfree", DiskFreeCmd, NULL,
3694                           "show server disk space usage");
3695     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3696     cmd_AddParm(ts, "-human", CMD_FLAG, CMD_OPTIONAL, "human-readable listing");
3697     cmd_CreateAlias(ts, "df");
3698
3699     ts = cmd_CreateSyntax("quota", QuotaCmd, NULL, "show volume quota usage");
3700     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3701
3702     ts = cmd_CreateSyntax("lsmount", ListMountCmd, NULL, "list mount point");
3703     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
3704
3705     ts = cmd_CreateSyntax("mkmount", MakeMountCmd, NULL, "make mount point");
3706     cmd_AddParm(ts, "-dir", CMD_SINGLE, 0, "directory");
3707     cmd_AddParm(ts, "-vol", CMD_SINGLE, 0, "volume name");
3708     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
3709     cmd_AddParm(ts, "-rw", CMD_FLAG, CMD_OPTIONAL, "force r/w volume");
3710     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL,
3711                 "don't check name with VLDB");
3712
3713 #if defined(AFS_CACHE_BYPASS)
3714         ts = cmd_CreateSyntax("bypassthreshold", BypassThresholdCmd, 0,
3715                 "get/set cache bypass file size threshold");
3716         cmd_AddParm(ts, "-size", CMD_SINGLE, CMD_OPTIONAL, "file size");
3717 #endif
3718
3719 /*
3720
3721 defect 3069
3722
3723     cmd_AddParm(ts, "-root", CMD_FLAG, CMD_OPTIONAL, "create cellular mount point");
3724 */
3725
3726
3727     ts = cmd_CreateSyntax("rmmount", RemoveMountCmd, NULL, "remove mount point");
3728     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
3729
3730     ts = cmd_CreateSyntax("checkservers", CheckServersCmd, NULL,
3731                           "check local cell's servers");
3732     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell to check");
3733     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "check all cells");
3734     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL,
3735                 "just list, don't check");
3736     cmd_AddParm(ts, "-interval", CMD_SINGLE, CMD_OPTIONAL,
3737                 "seconds between probes");
3738
3739     ts = cmd_CreateSyntax("checkvolumes", CheckVolumesCmd, NULL,
3740                           "check volumeID/name mappings");
3741     cmd_CreateAlias(ts, "checkbackups");
3742
3743
3744     ts = cmd_CreateSyntax("setcachesize", SetCacheSizeCmd, NULL,
3745                           "set cache size");
3746     cmd_AddParm(ts, "-blocks", CMD_SINGLE, CMD_OPTIONAL,
3747                 "size in 1K byte blocks (0 => reset)");
3748     cmd_CreateAlias(ts, "cachesize");
3749
3750     cmd_AddParm(ts, "-reset", CMD_FLAG, CMD_OPTIONAL,
3751                 "reset size back to boot value");
3752
3753     ts = cmd_CreateSyntax("getcacheparms", GetCacheParmsCmd, NULL,