venus: Tidy up header includes
[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 ListMountCmd(struct cmd_syndesc *as, void *arock)
1678 {
1679     afs_int32 code;
1680     struct ViceIoctl blob;
1681     struct cmd_item *ti;
1682     char orig_name[1024];       /*Original name, may be modified */
1683     char true_name[1024];       /*``True'' dirname (e.g., symlink target) */
1684     char parent_dir[1024];      /*Parent directory of true name */
1685     char *last_component;       /*Last component of true name */
1686     struct stat statbuff;       /*Buffer for status info */
1687     int link_chars_read;        /*Num chars read in readlink() */
1688     int thru_symlink;           /*Did we get to a mount point via a symlink? */
1689     int error = 0;
1690
1691     for (ti = as->parms[0].items; ti; ti = ti->next) {
1692         /* once per file */
1693         thru_symlink = 0;
1694         sprintf(orig_name, "%s%s", (ti->data[0] == '/') ? "" : "./",
1695                 ti->data);
1696
1697         if (lstat(orig_name, &statbuff) < 0) {
1698             /* if lstat fails, we should still try the pioctl, since it
1699              * may work (for example, lstat will fail, but pioctl will
1700              * work if the volume of offline (returning ENODEV). */
1701             statbuff.st_mode = S_IFDIR; /* lie like pros */
1702         }
1703
1704         /*
1705          * The lstat succeeded.  If the given file is a symlink, substitute
1706          * the file name with the link name.
1707          */
1708         if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
1709             thru_symlink = 1;
1710             /*
1711              * Read name of resolved file.
1712              */
1713             link_chars_read = readlink(orig_name, true_name, 1024);
1714             if (link_chars_read <= 0) {
1715                 fprintf(stderr,
1716                         "%s: Can't read target name for '%s' symbolic link!\n",
1717                         pn, orig_name);
1718                 error = 1;
1719                 continue;
1720             }
1721
1722             /*
1723              * Add a trailing null to what was read, bump the length.
1724              */
1725             true_name[link_chars_read++] = 0;
1726
1727             /*
1728              * If the symlink is an absolute pathname, we're fine.  Otherwise, we
1729              * have to create a full pathname using the original name and the
1730              * relative symlink name.  Find the rightmost slash in the original
1731              * name (we know there is one) and splice in the symlink value.
1732              */
1733             if (true_name[0] != '/') {
1734                 last_component = (char *)strrchr(orig_name, '/');
1735                 strcpy(++last_component, true_name);
1736                 strcpy(true_name, orig_name);
1737             }
1738         } else
1739             strcpy(true_name, orig_name);
1740
1741         /*
1742          * Find rightmost slash, if any.
1743          */
1744         last_component = (char *)strrchr(true_name, '/');
1745         if (last_component == (char *)true_name) {
1746             strcpy(parent_dir, "/");
1747             last_component++;
1748         }
1749         else if (last_component != (char *)NULL) {
1750             /*
1751              * Found it.  Designate everything before it as the parent directory,
1752              * everything after it as the final component.
1753              */
1754             strncpy(parent_dir, true_name, last_component - true_name);
1755             parent_dir[last_component - true_name] = 0;
1756             last_component++;   /*Skip the slash */
1757         } else {
1758             /*
1759              * No slash appears in the given file name.  Set parent_dir to the current
1760              * directory, and the last component as the given name.
1761              */
1762             strcpy(parent_dir, ".");
1763             last_component = true_name;
1764         }
1765
1766         if (strcmp(last_component, ".") == 0
1767             || strcmp(last_component, "..") == 0) {
1768             fprintf(stderr,
1769                     "%s: you may not use '.' or '..' as the last component\n",
1770                     pn);
1771             fprintf(stderr, "%s: of a name in the 'fs lsmount' command.\n",
1772                     pn);
1773             error = 1;
1774             continue;
1775         }
1776
1777         blob.in = last_component;
1778         blob.in_size = strlen(last_component) + 1;
1779         blob.out_size = AFS_PIOCTL_MAXSIZE;
1780         blob.out = space;
1781         memset(space, 0, AFS_PIOCTL_MAXSIZE);
1782
1783         code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
1784
1785         if (code == 0) {
1786             printf("'%s' is a %smount point for volume '%s'\n", ti->data,
1787                    (thru_symlink ? "symbolic link, leading to a " : ""),
1788                    space);
1789         } else {
1790             if (errno == EINVAL) {
1791                 fprintf(stderr, "'%s' is not a mount point.\n", ti->data);
1792             } else {
1793                 Die(errno, (ti->data ? ti->data : parent_dir));
1794             }
1795             error = 1;
1796         }
1797     }
1798     return error;
1799 }
1800
1801 static int
1802 MakeMountCmd(struct cmd_syndesc *as, void *arock)
1803 {
1804     afs_int32 code;
1805     char *cellName, *volName, *tmpName;
1806     struct afsconf_cell info;
1807     struct vldbentry vldbEntry;
1808     struct ViceIoctl blob;
1809
1810 /*
1811
1812 defect #3069
1813
1814     if (as->parms[5].items && !as->parms[2].items) {
1815         fprintf(stderr, "%s: must provide cell when creating cellular mount point.\n", pn);
1816         return 1;
1817     }
1818 */
1819
1820     if (as->parms[2].items)     /* cell name specified */
1821         cellName = as->parms[2].items->data;
1822     else
1823         cellName = NULL;
1824     volName = as->parms[1].items->data;
1825
1826     if (strlen(volName) >= 64) {
1827         fprintf(stderr,
1828                 "%s: volume name too long (length must be < 64 characters)\n",
1829                 pn);
1830         return 1;
1831     }
1832
1833     /* Check for a cellname in the volume specification, and complain
1834      * if it doesn't match what was specified with -cell */
1835     if ((tmpName = strchr(volName, ':'))) {
1836         *tmpName = '\0';
1837         if (cellName) {
1838             if (strcasecmp(cellName, volName)) {
1839                 fprintf(stderr, "%s: cellnames do not match.\n", pn);
1840                 return 1;
1841             }
1842         }
1843         cellName = volName;
1844         volName = ++tmpName;
1845     }
1846
1847     if (!InAFS(Parent(as->parms[0].items->data))) {
1848         fprintf(stderr,
1849                 "%s: mount points must be created within the AFS file system\n",
1850                 pn);
1851         return 1;
1852     }
1853
1854     if (!cellName) {
1855         blob.in_size = 0;
1856         blob.out_size = AFS_PIOCTL_MAXSIZE;
1857         blob.out = space;
1858         code =
1859             pioctl(Parent(as->parms[0].items->data), VIOC_FILE_CELL_NAME,
1860                    &blob, 1);
1861     }
1862
1863     code = GetCellName(cellName ? cellName : space, &info);
1864     if (code) {
1865         return 1;
1866     }
1867     if (!(as->parms[4].items)) {
1868         /* not fast, check which cell the mountpoint is being created in */
1869         /* not fast, check name with VLDB */
1870         code = VLDBInit(1, &info);
1871         if (code == 0) {
1872             /* make the check.  Don't complain if there are problems with init */
1873             code =
1874                 ubik_VL_GetEntryByNameO(uclient, 0, volName,
1875                           &vldbEntry);
1876             if (code == VL_NOENT) {
1877                 fprintf(stderr,
1878                         "%s: warning, volume %s does not exist in cell %s.\n",
1879                         pn, volName, cellName ? cellName : space);
1880             }
1881         }
1882     }
1883
1884     if (as->parms[3].items)     /* if -rw specified */
1885         strcpy(space, "%");
1886     else
1887         strcpy(space, "#");
1888     if (cellName) {
1889         /* cellular mount point, prepend cell prefix */
1890         strcat(space, info.name);
1891         strcat(space, ":");
1892     }
1893     strcat(space, volName);     /* append volume name */
1894     strcat(space, ".");         /* stupid convention; these end with a period */
1895     code = symlink(space, as->parms[0].items->data);
1896     if (code) {
1897         Die(errno, as->parms[0].items->data);
1898         return 1;
1899     }
1900     return 0;
1901 }
1902
1903 /*
1904  * Delete AFS mount points.  Variables are used as follows:
1905  *      tbuffer: Set to point to the null-terminated directory name of the mount point
1906  *          (or ``.'' if none is provided)
1907  *      tp: Set to point to the actual name of the mount point to nuke.
1908  */
1909 static int
1910 RemoveMountCmd(struct cmd_syndesc *as, void *arock)
1911 {
1912     afs_int32 code = 0;
1913     struct ViceIoctl blob;
1914     struct cmd_item *ti;
1915     char tbuffer[1024];
1916     char lsbuffer[1024];
1917     char *tp;
1918     int error = 0;
1919
1920     for (ti = as->parms[0].items; ti; ti = ti->next) {
1921         /* once per file */
1922         tp = (char *)strrchr(ti->data, '/');
1923         if (tp) {
1924             strncpy(tbuffer, ti->data, code = tp - ti->data);   /* the dir name */
1925             tbuffer[code] = 0;
1926             tp++;               /* skip the slash */
1927         } else {
1928             strcpy(tbuffer, ".");
1929             tp = ti->data;
1930         }
1931         blob.in = tp;
1932         blob.in_size = strlen(tp) + 1;
1933         blob.out = lsbuffer;
1934         blob.out_size = sizeof(lsbuffer);
1935         code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 1);
1936         if (code) {
1937             if (errno == EINVAL) {
1938                 fprintf(stderr, "%s: '%s' is not a mount point.\n", pn,
1939                         ti->data);
1940             } else {
1941                 Die(errno, ti->data);
1942             }
1943             error = 1;
1944             continue;           /* don't bother trying */
1945         }
1946         blob.out_size = 0;
1947         blob.in = tp;
1948         blob.in_size = strlen(tp) + 1;
1949         code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 1);
1950         if (code) {
1951             Die(errno, ti->data);
1952             error = 1;
1953         }
1954     }
1955     return error;
1956 }
1957
1958 /*
1959 */
1960
1961 static int
1962 CheckServersCmd(struct cmd_syndesc *as, void *arock)
1963 {
1964     afs_int32 code;
1965     struct ViceIoctl blob;
1966     afs_int32 j;
1967     afs_int32 temp;
1968     char *tp;
1969     struct afsconf_cell info;
1970     struct chservinfo checkserv;
1971
1972     memset(&checkserv, 0, sizeof(struct chservinfo));
1973     blob.in_size = sizeof(struct chservinfo);
1974     blob.in = (caddr_t) & checkserv;
1975
1976     blob.out_size = AFS_PIOCTL_MAXSIZE;
1977     blob.out = space;
1978     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
1979
1980     /* prepare flags for checkservers command */
1981     temp = 2;                   /* default to checking local cell only */
1982     if (as->parms[2].items)
1983         temp |= 1;              /* set fast flag */
1984     if (as->parms[1].items)
1985         temp &= ~2;             /* turn off local cell check */
1986
1987     checkserv.magic = 0x12345678;       /* XXX */
1988     checkserv.tflags = temp;
1989
1990     /* now copy in optional cell name, if specified */
1991     if (as->parms[0].items) {
1992         code = GetCellName(as->parms[0].items->data, &info);
1993         if (code) {
1994             return 1;
1995         }
1996         strcpy(checkserv.tbuffer, info.name);
1997         checkserv.tsize = strlen(info.name) + 1;
1998     } else {
1999         strcpy(checkserv.tbuffer, "\0");
2000         checkserv.tsize = 0;
2001     }
2002
2003     if (as->parms[3].items) {
2004         checkserv.tinterval = atol(as->parms[3].items->data);
2005
2006         /* sanity check */
2007         if (checkserv.tinterval < 0) {
2008             printf
2009                 ("Warning: The negative -interval is ignored; treated as an inquiry\n");
2010             checkserv.tinterval = 0;
2011         } else if (checkserv.tinterval > 600) {
2012             printf
2013                 ("Warning: The maximum -interval value is 10 mins (600 secs)\n");
2014             checkserv.tinterval = 600;  /* 10 min max interval */
2015         }
2016     } else {
2017         checkserv.tinterval = -1;       /* don't change current interval */
2018     }
2019
2020     code = pioctl(0, VIOCCKSERV, &blob, 1);
2021     if (code) {
2022         if ((errno == EACCES) && (checkserv.tinterval > 0)) {
2023             printf("Must be root to change -interval\n");
2024             return 1;
2025         }
2026         Die(errno, 0);
2027         return 1;
2028     }
2029     memcpy(&temp, space, sizeof(afs_int32));
2030     if (checkserv.tinterval >= 0) {
2031         if (checkserv.tinterval > 0)
2032             printf
2033                 ("The new down server probe interval (%d secs) is now in effect (old interval was %d secs)\n",
2034                  checkserv.tinterval, temp);
2035         else
2036             printf("The current down server probe interval is %d secs\n",
2037                    temp);
2038         return 0;
2039     }
2040     if (temp == 0) {
2041         printf("All servers are running.\n");
2042     } else {
2043         printf
2044             ("These servers unavailable due to network or server problems: ");
2045         for (j = 0;; j++) {
2046             memcpy(&temp, space + j * sizeof(afs_int32), sizeof(afs_int32));
2047             if (temp == 0)
2048                 break;
2049             tp = hostutil_GetNameByINet(temp);
2050             printf(" %s", tp);
2051         }
2052         printf(".\n");
2053         code = 1;               /* XXX */
2054     }
2055     return code;
2056 }
2057
2058 static int
2059 MessagesCmd(struct cmd_syndesc *as, void *arock)
2060 {
2061     afs_int32 code = 0;
2062     struct ViceIoctl blob;
2063     struct gaginfo gagflags;
2064     struct cmd_item *show;
2065
2066     memset(&gagflags, 0, sizeof(struct gaginfo));
2067     blob.in_size = sizeof(struct gaginfo);
2068     blob.in = (caddr_t) & gagflags;
2069     blob.out_size = AFS_PIOCTL_MAXSIZE;
2070     blob.out = space;
2071     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
2072
2073     if ((show = as->parms[0].items)) {
2074         if (!strcasecmp(show->data, "user"))
2075             gagflags.showflags |= GAGUSER;
2076         else if (!strcasecmp(show->data, "console"))
2077             gagflags.showflags |= GAGCONSOLE;
2078         else if (!strcasecmp(show->data, "all"))
2079             gagflags.showflags |= GAGCONSOLE | GAGUSER;
2080         else if (!strcasecmp(show->data, "none"))
2081             /* do nothing */ ;
2082         else {
2083             fprintf(stderr,
2084                     "unrecognized flag %s: must be in {user,console,all,none}\n",
2085                     show->data);
2086             code = EINVAL;
2087         }
2088     }
2089
2090     if (code)
2091         return 1;
2092
2093     code = pioctl(0, VIOC_GAG, &blob, 1);
2094     if (code) {
2095         Die(errno, 0);
2096         return 1;
2097     }
2098
2099     return 0;
2100 }
2101
2102 static int
2103 CheckVolumesCmd(struct cmd_syndesc *as, void *arock)
2104 {
2105     afs_int32 code;
2106     struct ViceIoctl blob;
2107
2108     blob.in_size = 0;
2109     blob.out_size = 0;
2110     code = pioctl(0, VIOCCKBACK, &blob, 1);
2111     if (code) {
2112         Die(errno, 0);
2113         return 1;
2114     }
2115
2116     printf("All volumeID/name mappings checked.\n");
2117     return 0;
2118 }
2119
2120 static int
2121 PreCacheCmd(struct cmd_syndesc *as, void *arock)
2122 {
2123     afs_int32 code;
2124     struct ViceIoctl blob;
2125     afs_int32 temp;
2126
2127     if (!as->parms[0].items && !as->parms[1].items) {
2128         fprintf(stderr, "%s: syntax error in precache cmd.\n", pn);
2129         return 1;
2130     }
2131     if (as->parms[0].items) {
2132         code = util_GetInt32(as->parms[0].items->data, &temp);
2133         if (code) {
2134             fprintf(stderr, "%s: bad integer specified for precache size.\n",
2135                     pn);
2136             return 1;
2137         }
2138     } else
2139         temp = 0;
2140     blob.in = (char *)&temp;
2141     blob.in_size = sizeof(afs_int32);
2142     blob.out_size = 0;
2143     code = pioctl(0, VIOCPRECACHE, &blob, 1);
2144     if (code) {
2145         Die(errno, NULL);
2146         return 1;
2147     }
2148
2149     printf("New precache size set.\n");
2150     return 0;
2151 }
2152
2153 static int
2154 SetCacheSizeCmd(struct cmd_syndesc *as, void *arock)
2155 {
2156     afs_int32 code;
2157     struct ViceIoctl blob;
2158     afs_int32 temp;
2159
2160     if (!as->parms[0].items && !as->parms[1].items) {
2161         fprintf(stderr, "%s: syntax error in setcachesize cmd.\n", pn);
2162         return 1;
2163     }
2164     if (as->parms[0].items) {
2165         code = util_GetHumanInt32(as->parms[0].items->data, &temp);
2166         if (code) {
2167             fprintf(stderr, "%s: bad integer specified for cache size.\n",
2168                     pn);
2169             return 1;
2170         }
2171     } else
2172         temp = 0;
2173     blob.in = (char *)&temp;
2174     blob.in_size = sizeof(afs_int32);
2175     blob.out_size = 0;
2176     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
2177     if (code) {
2178         if (errno == EROFS) {
2179             printf
2180                 ("'fs setcache' not allowed on memory cache based cache managers.\n");
2181         } else {
2182             Die(errno, NULL);
2183         }
2184         return 1;
2185     }
2186
2187     printf("New cache size set.\n");
2188     return 0;
2189 }
2190
2191 #define MAXGCSIZE       16
2192 static int
2193 GetCacheParmsCmd(struct cmd_syndesc *as, void *arock)
2194 {
2195     afs_int32 code, filesUsed;
2196     struct ViceIoctl blob;
2197     afs_int32 parms[MAXGCSIZE];
2198     double percentFiles, percentBlocks;
2199     afs_int32 flags = 0;
2200
2201     if (as->parms[0].items){ /* -files */
2202         flags = 1;
2203     } else if (as->parms[1].items){ /* -excessive */
2204         flags = 2;
2205     } else {
2206         flags = 0;
2207     }
2208
2209     memset(parms, '\0', sizeof parms);  /* avoid Purify UMR error */
2210     if (flags){
2211         blob.in = (char *)&flags;
2212         blob.in_size = sizeof(afs_int32);
2213     } else {    /* be backward compatible */
2214         blob.in = NULL;
2215         blob.in_size = 0;
2216     }
2217     blob.out_size = sizeof(parms);
2218     blob.out = (char *)parms;
2219     code = pioctl(0, VIOCGETCACHEPARMS, &blob, 1);
2220     if (code) {
2221         Die(errno, NULL);
2222         return 1;
2223     }
2224
2225     if (!flags){
2226         printf("AFS using %d of the cache's available %d 1K byte blocks.\n",
2227                 parms[1], parms[0]);
2228         if (parms[1] > parms[0])
2229                 printf("[Cache guideline temporarily deliberately exceeded; it will be adjusted down but you may wish to increase the cache size.]\n");
2230         return 0;
2231     }
2232
2233     percentBlocks = ((double)parms[1]/parms[0]) * 100;
2234     printf("AFS using %5.0f%% of cache blocks (%d of %d 1k blocks)\n",
2235            percentBlocks, parms[1], parms[0]);
2236
2237     if (parms[2] == 0)
2238         return 0;
2239
2240     filesUsed = parms[2] - parms[3];
2241     percentFiles = ((double)filesUsed/parms[2]) * 100;
2242     printf("          %5.0f%% of the cache files (%d of %d files)\n",
2243             percentFiles, filesUsed, parms[2]);
2244     if (flags == 2){
2245         printf("        afs_cacheFiles: %10d\n", parms[2]);
2246         printf("        IFFree:         %10d\n", parms[3]);
2247         printf("        IFEverUsed:     %10d\n", parms[4]);
2248         printf("        IFDataMod:      %10d\n", parms[5]);
2249         printf("        IFDirtyPages:   %10d\n", parms[6]);
2250         printf("        IFAnyPages:     %10d\n", parms[7]);
2251         printf("        IFDiscarded:    %10d\n", parms[8]);
2252         printf("        DCentries:  %10d\n", parms[9]);
2253         printf("          0k-   4K: %10d\n", parms[10]);
2254         printf("          4k-  16k: %10d\n", parms[11]);
2255         printf("         16k-  64k: %10d\n", parms[12]);
2256         printf("         64k- 256k: %10d\n", parms[13]);
2257         printf("        256k-   1M: %10d\n", parms[14]);
2258         printf("              >=1M: %10d\n", parms[15]);
2259     }
2260
2261     if (percentBlocks > 90)
2262         printf("[cache size usage over 90%%, consider increasing cache size]\n");
2263     if (percentFiles > 90)
2264         printf("[cache file usage over 90%%, consider increasing '-files' argument to afsd]\n");
2265
2266     return 0;
2267 }
2268
2269 static int
2270 ListCellsCmd(struct cmd_syndesc *as, void *arock)
2271 {
2272     afs_int32 code;
2273     afs_int32 i, j;
2274     char *tp;
2275     struct ViceIoctl blob;
2276     int resolve;
2277
2278     resolve = !(as->parms[0].items);    /* -numeric */
2279
2280     for (i = 0;; i++) {
2281         tp = space;
2282         memcpy(tp, &i, sizeof(afs_int32));
2283         blob.out_size = AFS_PIOCTL_MAXSIZE;
2284         blob.in_size = sizeof(afs_int32);
2285         blob.in = space;
2286         blob.out = space;
2287         code = pioctl(0, VIOCGETCELL, &blob, 1);
2288         if (code < 0) {
2289             if (errno == EDOM)
2290                 break;          /* done with the list */
2291             Die(errno, 0);
2292             return 1;
2293         }
2294         tp = space;
2295         printf("Cell %s on hosts", tp + AFS_MAXCELLHOSTS * sizeof(afs_int32));
2296         for (j = 0; j < AFS_MAXCELLHOSTS; j++) {
2297             afs_int32 addr;
2298             char *name, tbuffer[20];
2299
2300             memcpy(&addr, tp + j * sizeof(afs_int32), sizeof(afs_int32));
2301             if (addr == 0)
2302                 break;
2303
2304             if (resolve) {
2305                 name = hostutil_GetNameByINet(addr);
2306             } else {
2307                 addr = ntohl(addr);
2308                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
2309                         (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
2310                 name = tbuffer;
2311             }
2312             printf(" %s", name);
2313         }
2314         printf(".\n");
2315     }
2316     return 0;
2317 }
2318
2319 static int
2320 ListAliasesCmd(struct cmd_syndesc *as, void *arock)
2321 {
2322     afs_int32 code, i;
2323     char *tp, *aliasName, *realName;
2324     struct ViceIoctl blob;
2325
2326     for (i = 0;; i++) {
2327         tp = space;
2328         memcpy(tp, &i, sizeof(afs_int32));
2329         blob.out_size = AFS_PIOCTL_MAXSIZE;
2330         blob.in_size = sizeof(afs_int32);
2331         blob.in = space;
2332         blob.out = space;
2333         code = pioctl(0, VIOC_GETALIAS, &blob, 1);
2334         if (code < 0) {
2335             if (errno == EDOM)
2336                 break;          /* done with the list */
2337             Die(errno, 0);
2338             return 1;
2339         }
2340         tp = space;
2341         aliasName = tp;
2342         tp += strlen(aliasName) + 1;
2343         realName = tp;
2344         printf("Alias %s for cell %s\n", aliasName, realName);
2345     }
2346     return 0;
2347 }
2348
2349 static int
2350 CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
2351 {
2352     afs_int32 code;
2353     struct ViceIoctl blob;
2354     struct cmd_item *ti;
2355     afs_int32 hostAddr;
2356     struct hostent *thp;
2357     int setp;
2358
2359     ti = as->parms[0].items;
2360     setp = 1;
2361     if (ti) {
2362         thp = hostutil_GetHostByName(ti->data);
2363         if (!thp) {
2364             fprintf(stderr, "host %s not found in host table.\n", ti->data);
2365             return 1;
2366         }
2367         else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2368     } else {
2369         hostAddr = 0;   /* means don't set host */
2370         setp = 0;       /* aren't setting host */
2371     }
2372
2373     /* now do operation */
2374     blob.in_size = sizeof(afs_int32);
2375     blob.out_size = sizeof(afs_int32);
2376     blob.in = (char *) &hostAddr;
2377     blob.out = (char *) &hostAddr;
2378
2379     code = pioctl(0, VIOC_CBADDR, &blob, 1);
2380     if (code < 0) {
2381         Die(errno, 0);
2382         return 1;
2383     }
2384     return 0;
2385 }
2386
2387 static int
2388 NukeNFSCredsCmd(struct cmd_syndesc *as, void *arock)
2389 {
2390     afs_int32 code;
2391     struct ViceIoctl blob;
2392     struct cmd_item *ti;
2393     afs_int32 hostAddr;
2394     struct hostent *thp;
2395
2396     ti = as->parms[0].items;
2397     thp = hostutil_GetHostByName(ti->data);
2398     if (!thp) {
2399         fprintf(stderr, "host %s not found in host table.\n", ti->data);
2400         return 1;
2401     }
2402     else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2403
2404     /* now do operation */
2405     blob.in_size = sizeof(afs_int32);
2406     blob.out_size = sizeof(afs_int32);
2407     blob.in = (char *) &hostAddr;
2408     blob.out = (char *) &hostAddr;
2409
2410     code = pioctl(0, VIOC_NFS_NUKE_CREDS, &blob, 1);
2411     if (code < 0) {
2412         Die(errno, 0);
2413         return 1;
2414     }
2415     return 0;
2416 }
2417
2418 static int
2419 NewCellCmd(struct cmd_syndesc *as, void *arock)
2420 {
2421     afs_int32 code, linkedstate = 0, size = 0, *lp;
2422     struct ViceIoctl blob;
2423     struct cmd_item *ti;
2424     char *tp, *cellname = 0;
2425     struct hostent *thp;
2426     afs_int32 fsport = 0, vlport = 0;
2427     afs_int32 scount;           /* Number of servers to pass in pioctl call */
2428
2429     /* Yuck!
2430      * With the NEWCELL pioctl call, 3.4 clients take an array of
2431      * AFS_MAXHOSTS (13) servers while 3.5 clients take an array of
2432      * AFS_MAXCELLHOSTS (8) servers. To determine which we are talking to,
2433      * do a GETCELL pioctl and pass it a magic number. If an array of
2434      * 8 comes back, its a 3.5 client. If not, its a 3.4 client.
2435      * If we get back EDOM, there are no cells in the kernel yet,
2436      * and we'll assume a 3.5 client.
2437      */
2438     tp = space;
2439     lp = (afs_int32 *) tp;
2440     *lp++ = 0;                  /* first cell entry */
2441     *lp = 0x12345678;           /* magic */
2442     blob.out_size = AFS_PIOCTL_MAXSIZE;
2443     blob.in_size = sizeof(afs_int32) + sizeof(afs_int32);
2444     blob.in = space;
2445     blob.out = space;
2446     code = pioctl(0, VIOCGETCELL, &blob, 1);
2447     if (code < 0 && errno != EDOM) {
2448         Die(errno, 0);
2449         return 1;
2450     }
2451     if (code < 1 && errno == EDOM) {
2452         scount = AFS_MAXHOSTS;
2453     } else {
2454         tp = space;
2455         cellname = tp + AFS_MAXCELLHOSTS * sizeof(afs_int32);
2456         scount = ((cellname[0] != '\0') ? AFS_MAXCELLHOSTS : AFS_MAXHOSTS);
2457     }
2458
2459     /* Now setup and do the NEWCELL pioctl call */
2460     memset(space, 0, (scount + 1) * sizeof(afs_int32));
2461     tp = space;
2462     lp = (afs_int32 *) tp;
2463     *lp++ = 0x12345678;
2464     tp += sizeof(afs_int32);
2465     for (ti = as->parms[1].items; ti; ti = ti->next) {
2466         thp = hostutil_GetHostByName(ti->data);
2467         if (!thp) {
2468             fprintf(stderr,
2469                     "%s: Host %s not found in host table, skipping it.\n", pn,
2470                     ti->data);
2471         } else {
2472             memcpy(tp, thp->h_addr, sizeof(afs_int32));
2473             tp += sizeof(afs_int32);
2474         }
2475     }
2476     if (as->parms[2].items) {
2477         /*
2478          * Link the cell, for the purposes of volume location, to the specified
2479          * cell.
2480          */
2481         cellname = as->parms[2].items->data;
2482         linkedstate = 1;
2483     }
2484 #ifdef FS_ENABLE_SERVER_DEBUG_PORTS
2485     if (as->parms[3].items) {
2486         code = util_GetInt32(as->parms[3].items->data, &vlport);
2487         if (code) {
2488             fprintf(stderr,
2489                     "%s: bad integer specified for the fileserver port.\n",
2490                     pn);
2491             return 1;
2492         }
2493     }
2494     if (as->parms[4].items) {
2495         code = util_GetInt32(as->parms[4].items->data, &fsport);
2496         if (code) {
2497             fprintf(stderr,
2498                     "%s: bad integer specified for the vldb server port.\n",
2499                     pn);
2500             return 1;
2501         }
2502     }
2503 #endif
2504     tp = (char *)(space + (scount + 1) * sizeof(afs_int32));
2505     lp = (afs_int32 *) tp;
2506     *lp++ = fsport;
2507     *lp++ = vlport;
2508     *lp = linkedstate;
2509     strcpy(space + ((scount + 4) * sizeof(afs_int32)),
2510            as->parms[0].items->data);
2511     size = ((scount + 4) * sizeof(afs_int32))
2512         + strlen(as->parms[0].items->data)
2513         + 1 /* for null */ ;
2514     tp = (char *)(space + size);
2515     if (linkedstate) {
2516         strcpy(tp, cellname);
2517         size += strlen(cellname) + 1;
2518     }
2519     blob.in_size = size;
2520     blob.in = space;
2521     blob.out_size = 0;
2522     code = pioctl(0, VIOCNEWCELL, &blob, 1);
2523     if (code < 0) {
2524         Die(errno, 0);
2525         return 1;
2526     }
2527     return 0;
2528 }
2529
2530 static int
2531 NewAliasCmd(struct cmd_syndesc *as, void *arock)
2532 {
2533     afs_int32 code;
2534     struct ViceIoctl blob;
2535     char *tp;
2536     char *aliasName, *realName;
2537
2538     /* Now setup and do the NEWCELL pioctl call */
2539     aliasName = as->parms[0].items->data;
2540     realName = as->parms[1].items->data;
2541     tp = space;
2542     strcpy(tp, aliasName);
2543     tp += strlen(aliasName) + 1;
2544     strcpy(tp, realName);
2545     tp += strlen(realName) + 1;
2546
2547     blob.in_size = tp - space;
2548     blob.in = space;
2549     blob.out_size = 0;
2550     blob.out = space;
2551     code = pioctl(0, VIOC_NEWALIAS, &blob, 1);
2552     if (code < 0) {
2553         if (errno == EEXIST) {
2554             fprintf(stderr,
2555                     "%s: cell name `%s' in use by an existing cell.\n", pn,
2556                     aliasName);
2557         } else {
2558             Die(errno, 0);
2559         }
2560         return 1;
2561     }
2562     return 0;
2563 }
2564
2565 static int
2566 WhichCellCmd(struct cmd_syndesc *as, void *arock)
2567 {
2568     afs_int32 code;
2569     struct cmd_item *ti;
2570     int error = 0;
2571     char cell[MAXCELLCHARS];
2572
2573     SetDotDefault(&as->parms[0].items);
2574     for (ti = as->parms[0].items; ti; ti = ti->next) {
2575         code = GetCell(ti->data, cell);
2576         if (code) {
2577             if (errno == ENOENT)
2578                 fprintf(stderr, "%s: no such cell as '%s'\n", pn, ti->data);
2579             else
2580                 Die(errno, ti->data);
2581             error = 1;
2582             continue;
2583         }
2584
2585         printf("File %s lives in cell '%s'\n", ti->data, cell);
2586     }
2587     return error;
2588 }
2589
2590 static int
2591 WSCellCmd(struct cmd_syndesc *as, void *arock)
2592 {
2593     afs_int32 code;
2594     struct ViceIoctl blob;
2595
2596     blob.in_size = 0;
2597     blob.in = NULL;
2598     blob.out_size = AFS_PIOCTL_MAXSIZE;
2599     blob.out = space;
2600
2601     code = pioctl(NULL, VIOC_GET_WS_CELL, &blob, 1);
2602     if (code) {
2603         Die(errno, NULL);
2604         return 1;
2605     }
2606
2607     printf("This workstation belongs to cell '%s'\n", space);
2608     return 0;
2609 }
2610
2611 /*
2612 static PrimaryCellCmd(as)
2613     struct cmd_syndesc *as;
2614 {
2615     fprintf(stderr, "This command is obsolete, as is the concept of a primary token.\n");
2616     return 0;
2617 }
2618 */
2619
2620 static int
2621 MonitorCmd(struct cmd_syndesc *as, void *arock)
2622 {
2623     afs_int32 code;
2624     struct ViceIoctl blob;
2625     struct cmd_item *ti;
2626     afs_int32 hostAddr;
2627     struct hostent *thp;
2628     char *tp;
2629     int setp;
2630
2631     ti = as->parms[0].items;
2632     setp = 1;
2633     if (ti) {
2634         /* set the host */
2635         if (!strcmp(ti->data, "off"))
2636             hostAddr = 0xffffffff;
2637         else {
2638             thp = hostutil_GetHostByName(ti->data);
2639             if (!thp) {
2640                 if (!strcmp(ti->data, "localhost")) {
2641                     fprintf(stderr,
2642                             "localhost not in host table, assuming 127.0.0.1\n");
2643                     hostAddr = htonl(0x7f000001);
2644                 } else {
2645                     fprintf(stderr, "host %s not found in host table.\n",
2646                             ti->data);
2647                     return 1;
2648                 }
2649             } else
2650                 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2651         }
2652     } else {
2653         hostAddr = 0;           /* means don't set host */
2654         setp = 0;               /* aren't setting host */
2655     }
2656
2657     /* now do operation */
2658     blob.in_size = sizeof(afs_int32);
2659     blob.out_size = sizeof(afs_int32);
2660     blob.in = (char *)&hostAddr;
2661     blob.out = (char *)&hostAddr;
2662     code = pioctl(0, VIOC_AFS_MARINER_HOST, &blob, 1);
2663     if (code) {
2664         Die(errno, 0);
2665         return 1;
2666     }
2667     if (setp) {
2668         printf("%s: new monitor host set.\n", pn);
2669     } else {
2670         /* now decode old address */
2671         if (hostAddr == 0xffffffff) {
2672             printf("Cache monitoring is currently disabled.\n");
2673         } else {
2674             tp = hostutil_GetNameByINet(hostAddr);
2675             printf("Using host %s for monitor services.\n", tp);
2676         }
2677     }
2678     return 0;
2679 }
2680
2681 static int
2682 SysNameCmd(struct cmd_syndesc *as, void *arock)
2683 {
2684     afs_int32 code;
2685     struct ViceIoctl blob;
2686     struct cmd_item *ti;
2687     char *input = space;
2688     afs_int32 setp = 0;
2689
2690     ti = as->parms[0].items;
2691     blob.in = space;
2692     blob.out = space;
2693     blob.out_size = AFS_PIOCTL_MAXSIZE;
2694     blob.in_size = sizeof(afs_int32);
2695     input += sizeof(afs_int32);
2696     for (; ti; ti = ti->next) {
2697         setp++;
2698         blob.in_size += strlen(ti->data) + 1;
2699         if (blob.in_size > AFS_PIOCTL_MAXSIZE) {
2700             fprintf(stderr, "%s: sysname%s too long.\n", pn,
2701                     setp > 1 ? "s" : "");
2702             return 1;
2703         }
2704         strcpy(input, ti->data);
2705         input += strlen(ti->data);
2706         *(input++) = '\0';
2707     }
2708     memcpy(space, &setp, sizeof(afs_int32));
2709     code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
2710     if (code) {
2711         Die(errno, 0);
2712         return 1;
2713     }
2714     if (setp) {
2715         printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
2716         return 0;
2717     }
2718     input = space;
2719     memcpy(&setp, input, sizeof(afs_int32));
2720     input += sizeof(afs_int32);
2721     if (!setp) {
2722         fprintf(stderr, "No sysname name value was found\n");
2723         return 1;
2724     }
2725     printf("Current sysname%s is", setp > 1 ? " list" : "");
2726     for (; setp > 0; --setp) {
2727         printf(" \'%s\'", input);
2728         input += strlen(input) + 1;
2729     }
2730     printf("\n");
2731     return 0;
2732 }
2733
2734 static char *exported_types[] = { "null", "nfs", "" };
2735 static int
2736 ExportAfsCmd(struct cmd_syndesc *as, void *arock)
2737 {
2738     afs_int32 code;
2739     struct ViceIoctl blob;
2740     struct cmd_item *ti;
2741     int export = 0, type = 0, mode = 0, exp = 0, exportcall, pwsync =
2742         0, smounts = 0, clipags = 0, pagcb = 0;
2743
2744     ti = as->parms[0].items;
2745     if (strcmp(ti->data, "nfs") == 0)
2746         type = 0x71;            /* NFS */
2747     else {
2748         fprintf(stderr,
2749                 "Invalid exporter type, '%s', Only the 'nfs' exporter is currently supported\n",
2750                 ti->data);
2751         return 1;
2752     }
2753     ti = as->parms[1].items;
2754     if (ti) {
2755         if (strcmp(ti->data, "on") == 0)
2756             export = 3;
2757         else if (strcmp(ti->data, "off") == 0)
2758             export = 2;
2759         else {
2760             fprintf(stderr, "Illegal argument %s\n", ti->data);
2761             return 1;
2762         }
2763         exp = 1;
2764     }
2765     if ((ti = as->parms[2].items)) {    /* -noconvert */
2766         if (strcmp(ti->data, "on") == 0)
2767             mode = 2;
2768         else if (strcmp(ti->data, "off") == 0)
2769             mode = 3;
2770         else {
2771             fprintf(stderr, "Illegal argument %s\n", ti->data);
2772             return 1;
2773         }
2774     }
2775     if ((ti = as->parms[3].items)) {    /* -uidcheck */
2776         if (strcmp(ti->data, "on") == 0)
2777             pwsync = 3;
2778         else if (strcmp(ti->data, "off") == 0)
2779             pwsync = 2;
2780         else {
2781             fprintf(stderr, "Illegal argument %s\n", ti->data);
2782             return 1;
2783         }
2784     }
2785     if ((ti = as->parms[4].items)) {    /* -submounts */
2786         if (strcmp(ti->data, "on") == 0)
2787             smounts = 3;
2788         else if (strcmp(ti->data, "off") == 0)
2789             smounts = 2;
2790         else {
2791             fprintf(stderr, "Illegal argument %s\n", ti->data);
2792             return 1;
2793         }
2794     }
2795     if ((ti = as->parms[5].items)) {    /* -clipags */
2796         if (strcmp(ti->data, "on") == 0)
2797             clipags = 3;
2798         else if (strcmp(ti->data, "off") == 0)
2799             clipags = 2;
2800         else {
2801             fprintf(stderr, "Illegal argument %s\n", ti->data);
2802             return 1;
2803         }
2804     }
2805     if ((ti = as->parms[6].items)) {    /* -pagcb */
2806         if (strcmp(ti->data, "on") == 0)
2807             pagcb = 3;
2808         else if (strcmp(ti->data, "off") == 0)
2809             pagcb = 2;
2810         else {
2811             fprintf(stderr, "Illegal argument %s\n", ti->data);
2812             return 1;
2813         }
2814     }
2815     exportcall =
2816         (type << 24) | (pagcb << 10) | (clipags << 8) |
2817         (mode << 6) | (pwsync << 4) | (smounts << 2) | export;
2818     type &= ~0x70;
2819     /* make the call */
2820     blob.in = (char *)&exportcall;
2821     blob.in_size = sizeof(afs_int32);
2822     blob.out = (char *)&exportcall;
2823     blob.out_size = sizeof(afs_int32);
2824     code = pioctl(0, VIOC_EXPORTAFS, &blob, 1);
2825     if (code) {
2826         if (errno == ENODEV) {
2827             fprintf(stderr,
2828                     "Sorry, the %s-exporter type is currently not supported on this AFS client\n",
2829                     exported_types[type]);
2830         } else {
2831             Die(errno, 0);
2832         }
2833         return 1;
2834     }
2835
2836     if (exportcall & 1) {
2837         printf("'%s' translator is enabled with the following options:\n",
2838                exported_types[type]);
2839         printf("\tRunning in %s mode\n",
2840                (exportcall & 2 ? "strict unix" :
2841                 "convert owner mode bits to world/other"));
2842         printf("\tRunning in %s mode\n",
2843                (exportcall & 4 ? "strict 'passwd sync'" :
2844                 "no 'passwd sync'"));
2845         printf("\t%s\n",
2846                (exportcall & 8 ? "Allow mounts of /afs/.. subdirs" :
2847                 "Only mounts to /afs allowed"));
2848         printf("\t%s\n",
2849                (exportcall & 16 ? "Client-assigned PAG's are used" :
2850                 "Client-assigned PAG's are not used"));
2851         printf("\t%s\n",
2852                (exportcall & 32 ?
2853                 "Callbacks are made to get creds from new clients" :
2854                 "Callbacks are not made to get creds from new clients"));
2855     } else {
2856         printf("'%s' translator is disabled\n", exported_types[type]);
2857     }
2858     return 0;
2859 }
2860
2861
2862 static int
2863 GetCellCmd(struct cmd_syndesc *as, void *arock)
2864 {
2865     afs_int32 code;
2866     struct ViceIoctl blob;
2867     struct afsconf_cell info;
2868     struct cmd_item *ti;
2869     struct a {
2870         afs_int32 stat;
2871         afs_int32 junk;
2872     } args;
2873     int error = 0;
2874
2875     memset(&args, '\0', sizeof args);   /* avoid Purify UMR error */
2876     for (ti = as->parms[0].items; ti; ti = ti->next) {
2877         /* once per cell */
2878         blob.out_size = sizeof(args);
2879         blob.out = (caddr_t) & args;
2880         code = GetCellName(ti->data, &info);
2881         if (code) {
2882             error = 1;
2883             continue;
2884         }
2885         blob.in_size = 1 + strlen(info.name);
2886         blob.in = info.name;
2887         code = pioctl(0, VIOC_GETCELLSTATUS, &blob, 1);
2888         if (code) {
2889             if (errno == ENOENT)
2890                 fprintf(stderr, "%s: the cell named '%s' does not exist\n",
2891                         pn, info.name);
2892             else
2893                 Die(errno, info.name);
2894             error = 1;
2895             continue;
2896         }
2897         printf("Cell %s status: ", info.name);
2898 #ifdef notdef
2899         if (args.stat & 1)
2900             printf("primary ");
2901 #endif
2902         if (args.stat & 2)
2903             printf("no setuid allowed");
2904         else
2905             printf("setuid allowed");
2906         if (args.stat & 4)
2907             printf(", using old VLDB");
2908         printf("\n");
2909     }
2910     return error;
2911 }
2912
2913 static int
2914 SetCellCmd(struct cmd_syndesc *as, void *arock)
2915 {
2916     afs_int32 code;
2917     struct ViceIoctl blob;
2918     struct afsconf_cell info;
2919     struct cmd_item *ti;
2920     struct a {
2921         afs_int32 stat;
2922         afs_int32 junk;
2923         char cname[64];
2924     } args;
2925     int error = 0;
2926
2927     /* Check arguments. */
2928     if (as->parms[1].items && as->parms[2].items) {
2929         fprintf(stderr, "Cannot specify both -suid and -nosuid.\n");
2930         return 1;
2931     }
2932
2933     /* figure stuff to set */
2934     args.stat = 0;
2935     args.junk = 0;
2936
2937     if (!as->parms[1].items)
2938         args.stat |= 2;         /* default to -nosuid */
2939
2940     /* set stat for all listed cells */
2941     for (ti = as->parms[0].items; ti; ti = ti->next) {
2942         /* once per cell */
2943         code = GetCellName(ti->data, &info);
2944         if (code) {
2945             error = 1;
2946             continue;
2947         }
2948         strcpy(args.cname, info.name);
2949         blob.in_size = sizeof(args);
2950         blob.in = (caddr_t) & args;
2951         blob.out_size = 0;
2952         blob.out = (caddr_t) 0;
2953         code = pioctl(0, VIOC_SETCELLSTATUS, &blob, 1);
2954         if (code) {
2955             Die(errno, info.name);      /* XXX added cell name to Die() call */
2956             error = 1;
2957         }
2958     }
2959     return error;
2960 }
2961
2962 static int
2963 GetCellName(char *cellName, struct afsconf_cell *info)
2964 {
2965     struct afsconf_dir *tdir;
2966     int code;
2967
2968     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
2969     if (!tdir) {
2970         fprintf(stderr,
2971                 "Could not process files in configuration directory (%s).\n",
2972                 AFSDIR_CLIENT_ETC_DIRPATH);
2973         return -1;
2974     }
2975
2976     code = afsconf_GetCellInfo(tdir, cellName, AFSCONF_VLDBSERVICE, info);
2977     if (code) {
2978         fprintf(stderr, "%s: cell %s not in %s\n", pn, cellName,
2979                 AFSDIR_CLIENT_CELLSERVDB_FILEPATH);
2980         return code;
2981     }
2982
2983     return 0;
2984 }
2985
2986
2987 static int
2988 VLDBInit(int noAuthFlag, struct afsconf_cell *info)
2989 {
2990     afs_int32 code;
2991
2992     code = ugen_ClientInit(noAuthFlag, (char *) AFSDIR_CLIENT_ETC_DIRPATH,
2993                            info->name, 0, &uclient,
2994                            NULL, pn, rxkad_clear,
2995                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
2996                            0, 0, USER_SERVICE_ID);
2997     rxInitDone = 1;
2998     return code;
2999 }
3000
3001 static struct ViceIoctl gblob;
3002 static int debug = 0;
3003 /*
3004  * here follow some routines in suport of the setserverprefs and
3005  * getserverprefs commands.  They are:
3006  * SetPrefCmd  "top-level" routine
3007  * addServer   adds a server to the list of servers to be poked into the
3008  *             kernel.  Will poke the list into the kernel if it threatens
3009  *             to get too large.
3010  * pokeServers pokes the existing list of servers and ranks into the kernel
3011  * GetPrefCmd  reads the Cache Manager's current list of server ranks
3012  */
3013
3014 /*
3015  * returns -1 if error message printed,
3016  * 0 on success,
3017  * errno value if error and no error message printed
3018  */
3019 static int
3020 pokeServers(void)
3021 {
3022     int code;
3023
3024     code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
3025     if (code && (errno == EINVAL)) {
3026         struct setspref *ssp;
3027         ssp = (struct setspref *)gblob.in;
3028         if (!(ssp->flags & DBservers)) {
3029             gblob.in = (void *)&(ssp->servers[0]);
3030             gblob.in_size -= ((char *)&(ssp->servers[0])) - (char *)ssp;
3031             code = pioctl(0, VIOC_SETSPREFS33, &gblob, 1);
3032             return code ? errno : 0;
3033         }
3034         fprintf(stderr,
3035                 "This cache manager does not support VL server preferences.\n");
3036         return -1;
3037     }
3038
3039     return code ? errno : 0;
3040 }
3041
3042 /*
3043  * returns -1 if error message printed,
3044  * 0 on success,
3045  * errno value if error and no error message printed
3046  */
3047 static int
3048 addServer(char *name, afs_int32 rank)
3049 {
3050     int t, code;
3051     struct setspref *ssp;
3052     struct spref *sp;
3053     struct hostent *thostent;
3054     int error = 0;
3055
3056 #ifndef MAXUSHORT
3057 #ifdef MAXSHORT
3058 #define MAXUSHORT ((unsigned short) 2*MAXSHORT+1)       /* assumes two's complement binary system */
3059 #else
3060 #define MAXUSHORT ((unsigned short) ~0)
3061 #endif
3062 #endif
3063
3064     thostent = hostutil_GetHostByName(name);
3065     if (!thostent) {
3066         fprintf(stderr, "%s: couldn't resolve name.\n", name);
3067         return -1;
3068     }
3069
3070     ssp = (struct setspref *)(gblob.in);
3071
3072     for (t = 0; thostent->h_addr_list[t]; t++) {
3073         if (gblob.in_size > MAXINSIZE - sizeof(struct spref)) {
3074             code = pokeServers();
3075             if (code)
3076                 error = code;
3077             ssp->num_servers = 0;
3078         }
3079
3080         sp = (struct spref *)(gblob.in + gblob.in_size);
3081         memcpy(&(sp->server.s_addr), thostent->h_addr_list[t],
3082                sizeof(afs_uint32));
3083         sp->rank = (rank > MAXUSHORT ? MAXUSHORT : rank);
3084         gblob.in_size += sizeof(struct spref);
3085         ssp->num_servers++;
3086
3087         if (debug)
3088             fprintf(stderr, "adding server %s, rank %d, ip addr 0x%lx\n",
3089                     name, sp->rank, (long unsigned int) sp->server.s_addr);
3090     }
3091
3092     return error;
3093 }
3094
3095
3096 static int
3097 SetPrefCmd(struct cmd_syndesc *as, void *arock)
3098 {
3099     FILE *infd;
3100     afs_int32 code;
3101     struct cmd_item *ti;
3102     char name[80];
3103     afs_int32 rank;
3104     struct setspref *ssp;
3105     int error = 0;              /* -1 means error message printed,
3106                                  * >0 means errno value for unprinted message */
3107
3108     ssp = (struct setspref *)space;
3109     ssp->flags = 0;
3110     ssp->num_servers = 0;
3111     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3112     gblob.in = space;
3113     gblob.out = space;
3114     gblob.out_size = AFS_PIOCTL_MAXSIZE;
3115
3116
3117     if (geteuid()) {
3118         fprintf(stderr, "Permission denied: requires root access.\n");
3119         return 1;
3120     }
3121
3122     ti = as->parms[2].items;    /* -file */
3123     if (ti) {
3124         if (debug)
3125             fprintf(stderr, "opening file %s\n", ti->data);
3126         if (!(infd = fopen(ti->data, "r"))) {
3127             perror(ti->data);
3128             error = -1;
3129         } else {
3130             while (fscanf(infd, "%79s%ld", name, (long int *)&rank) != EOF) {
3131                 code = addServer(name, (unsigned short)rank);
3132                 if (code)
3133                     error = code;
3134             }
3135         }
3136     }
3137
3138     ti = as->parms[3].items;    /* -stdin */
3139     if (ti) {
3140         while (scanf("%79s%ld", name, (long int *)&rank) != EOF) {
3141             code = addServer(name, (unsigned short)rank);
3142             if (code)
3143                 error = code;
3144         }
3145     }
3146
3147     for (ti = as->parms[0].items; ti; ti = ti->next) {  /* list of servers, ranks */
3148         if (ti) {
3149             if (!ti->next) {
3150                 break;
3151             }
3152             code = addServer(ti->data, (unsigned short)atol(ti->next->data));
3153             if (code)
3154                 error = code;
3155             if (debug)
3156                 printf("set fs prefs %s %s\n", ti->data, ti->next->data);
3157             ti = ti->next;
3158         }
3159     }
3160     code = pokeServers();
3161     if (code)
3162         error = code;
3163     if (debug)
3164         printf("now working on vlservers, code=%d\n", code);
3165
3166     ssp = (struct setspref *)space;
3167     ssp->flags = DBservers;
3168     ssp->num_servers = 0;
3169     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3170     gblob.in = space;
3171
3172     for (ti = as->parms[1].items; ti; ti = ti->next) {  /* list of dbservers, ranks */
3173         if (ti) {
3174             if (!ti->next) {
3175                 break;
3176             }
3177             code = addServer(ti->data, (unsigned short)atol(ti->next->data));
3178             if (code)
3179                 error = code;
3180             if (debug)
3181                 printf("set vl prefs %s %s\n", ti->data, ti->next->data);
3182             ti = ti->next;
3183         }
3184     }
3185
3186     if (as->parms[1].items) {
3187         if (debug)
3188             printf("now poking vlservers\n");
3189         code = pokeServers();
3190         if (code)
3191             error = code;
3192     }
3193
3194     if (error > 0)
3195         Die(error, 0);
3196
3197     return error ? 1 : 0;
3198 }
3199
3200
3201
3202 static int
3203 GetPrefCmd(struct cmd_syndesc *as, void *arock)
3204 {
3205     afs_int32 code;
3206     struct cmd_item *ti;
3207     char *name, tbuffer[20];
3208     afs_int32 addr;
3209     FILE *outfd;
3210     int resolve;
3211     int vlservers = 0;
3212     struct ViceIoctl blob;
3213     struct sprefrequest *in;
3214     struct sprefinfo *out;
3215     int i;
3216
3217     ti = as->parms[0].items;    /* -file */
3218     if (ti) {
3219         if (debug)
3220             fprintf(stderr, "opening file %s\n", ti->data);
3221         if (!(outfd = freopen(ti->data, "w", stdout))) {
3222             perror(ti->data);
3223             return 1;
3224         }
3225     }
3226
3227     ti = as->parms[1].items;    /* -numeric */
3228     resolve = !(ti);
3229     ti = as->parms[2].items;    /* -vlservers */
3230     vlservers |= (ti ? DBservers : 0);
3231     /*  ti = as->parms[3].items;   -cell */
3232
3233     in = (struct sprefrequest *)space;
3234     in->offset = 0;
3235
3236     do {
3237         blob.in_size = sizeof(struct sprefrequest);
3238         blob.in = (char *)in;
3239         blob.out = space;
3240         blob.out_size = AFS_PIOCTL_MAXSIZE;
3241
3242         in->num_servers =
3243             (AFS_PIOCTL_MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
3244         in->flags = vlservers;
3245
3246         do {
3247             code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
3248             if (code) {
3249                 if ((errno != E2BIG) || (2 * blob.out_size > 0x7FFF)) {
3250                     perror("getserverprefs pioctl");
3251                     return 1;
3252                 }
3253                 blob.out_size *= 2;
3254                 if (blob.out == space)
3255                     blob.out = malloc(blob.out_size);
3256                 else
3257                     blob.out = realloc(blob.out, blob.out_size);
3258             }
3259         } while (code != 0);
3260
3261         out = (struct sprefinfo *)blob.out;
3262
3263         for (i = 0; i < out->num_servers; i++) {
3264             if (resolve) {
3265                 name = hostutil_GetNameByINet(out->servers[i].server.s_addr);
3266             } else {
3267                 addr = ntohl(out->servers[i].server.s_addr);
3268                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
3269                         (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
3270                 name = tbuffer;
3271             }
3272             printf("%-50s %5u\n", name, out->servers[i].rank);
3273         }
3274
3275         in->offset = out->next_offset;
3276     } while (out->next_offset > 0);
3277
3278     if (blob.out != space)
3279         free(blob.out);
3280
3281     return 0;
3282 }
3283
3284 static int
3285 StoreBehindCmd(struct cmd_syndesc *as, void *arock)
3286 {
3287     afs_int32 code = 0;
3288     struct ViceIoctl blob;
3289     struct cmd_item *ti;
3290     struct sbstruct tsb, tsb2;
3291     int verbose = 0;
3292     afs_int32 allfiles;
3293     char *t;
3294     int error = 0;
3295
3296     tsb.sb_thisfile = -1;
3297     ti = as->parms[0].items;    /* -kbytes */
3298     if (ti) {
3299         if (!as->parms[1].items) {
3300             fprintf(stderr, "%s: you must specify -files with -kbytes.\n",
3301                     pn);
3302             return 1;
3303         }
3304         tsb.sb_thisfile = strtol(ti->data, &t, 10) * 1024;
3305         if ((tsb.sb_thisfile < 0) || (t != ti->data + strlen(ti->data))) {
3306             fprintf(stderr, "%s: %s must be 0 or a positive number.\n", pn,
3307                     ti->data);
3308             return 1;
3309         }
3310     }
3311
3312     allfiles = tsb.sb_default = -1;     /* Don't set allfiles yet */
3313     ti = as->parms[2].items;    /* -allfiles */
3314     if (ti) {
3315         allfiles = strtol(ti->data, &t, 10) * 1024;
3316         if ((allfiles < 0) || (t != ti->data + strlen(ti->data))) {
3317             fprintf(stderr, "%s: %s must be 0 or a positive number.\n", pn,
3318                     ti->data);
3319             return 1;
3320         }
3321     }
3322
3323     /* -verbose or -file only or no options */
3324     if (as->parms[3].items || (as->parms[1].items && !as->parms[0].items)
3325         || (!as->parms[0].items && !as->parms[1].items
3326             && !as->parms[2].items))
3327         verbose = 1;
3328
3329     blob.in = (char *)&tsb;
3330     blob.in_size = sizeof(struct sbstruct);
3331
3332     /* once per -file */
3333     for (ti = as->parms[1].items; ti; ti = ti->next) {
3334         /* Do this solely to see if the file is there */
3335
3336         blob.out = space;
3337         blob.out_size = AFS_PIOCTL_MAXSIZE;
3338         code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
3339         if (code) {
3340             Die(errno, ti->data);
3341             error = 1;
3342             continue;
3343         }
3344
3345         memset(&tsb2, 0, sizeof(tsb2));
3346         blob.out = (char *)&tsb2;
3347         blob.out_size = sizeof(struct sbstruct);
3348         code = pioctl(ti->data, VIOC_STORBEHIND, &blob, 1);
3349         if (code) {
3350             Die(errno, ti->data);
3351             error = 1;
3352             continue;
3353         }
3354
3355         if (verbose && (blob.out_size == sizeof(tsb2))) {
3356             if (tsb2.sb_thisfile == -1) {
3357                 fprintf(stdout, "Will store %s according to default.\n",
3358                         ti->data);
3359             } else {
3360                 fprintf(stdout,
3361                         "Will store up to %d kbytes of %s asynchronously.\n",
3362                         (tsb2.sb_thisfile / 1024), ti->data);
3363             }
3364         }
3365     }
3366
3367     /* If no files - make at least one pioctl call, or
3368      * set the allfiles default if we need to.
3369      */
3370     if (!as->parms[1].items || (allfiles != -1)) {
3371         tsb.sb_default = allfiles;
3372         memset(&tsb2, 0, sizeof(tsb2));
3373         blob.out = (char *)&tsb2;
3374         blob.out_size = sizeof(struct sbstruct);
3375         code = pioctl(0, VIOC_STORBEHIND, &blob, 1);
3376         if (code) {
3377             Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
3378             error = 1;
3379         }
3380     }
3381
3382     /* Having no arguments also reports the default store asynchrony */
3383     if (!error && verbose && (blob.out_size == sizeof(tsb2))) {
3384         fprintf(stdout, "Default store asynchrony is %d kbytes.\n",
3385                 (tsb2.sb_default / 1024));
3386     }
3387
3388     return error;
3389 }
3390
3391
3392 static int
3393 SetCryptCmd(struct cmd_syndesc *as, void *arock)
3394 {
3395     afs_int32 code = 0, flag;
3396     struct ViceIoctl blob;
3397     char *tp;
3398
3399     tp = as->parms[0].items->data;
3400     if (strcmp(tp, "on") == 0)
3401         flag = 1;
3402     else if (strcmp(tp, "off") == 0)
3403         flag = 0;
3404     else {
3405         fprintf(stderr, "%s: %s must be \"on\" or \"off\".\n", pn, tp);
3406         return EINVAL;
3407     }
3408
3409     blob.in = (char *)&flag;
3410     blob.in_size = sizeof(flag);
3411     blob.out_size = 0;
3412     code = pioctl(0, VIOC_SETRXKCRYPT, &blob, 1);
3413     if (code)
3414         Die(errno, NULL);
3415     return 0;
3416 }
3417
3418
3419 static int
3420 GetCryptCmd(struct cmd_syndesc *as, void *arock)
3421 {
3422     afs_int32 code = 0, flag;
3423     struct ViceIoctl blob;
3424     char *tp;
3425
3426     blob.in = NULL;
3427     blob.in_size = 0;
3428     blob.out_size = sizeof(flag);
3429     blob.out = space;
3430
3431     code = pioctl(0, VIOC_GETRXKCRYPT, &blob, 1);
3432
3433     if (code)
3434         Die(errno, NULL);
3435     else {
3436         tp = space;
3437         memcpy(&flag, tp, sizeof(afs_int32));
3438         printf("Security level is currently ");
3439         if (flag == 1)
3440             printf("crypt (data security).\n");
3441         else
3442             printf("clear.\n");
3443     }
3444     return 0;
3445 }
3446
3447 static char *modenames[] = {
3448     "offline",
3449     "online",
3450     "readonly",  /* Not currently supported */
3451     "fetchonly", /* Not currently supported */
3452     "partial",   /* Not currently supported */
3453     NULL
3454 };
3455
3456 static char *policynames[] = {
3457     "client",
3458     "server",
3459     "closer",  /* Not currently supported. */
3460     "manual",  /* Not currently supported. */
3461     NULL
3462 };
3463
3464 static int
3465 DisconCmd(struct cmd_syndesc *as, void *arock)
3466 {
3467     struct cmd_item *ti;
3468     char *modename;
3469     char *policyname;
3470     int modelen, policylen;
3471     afs_int32 mode, policy, code, unixuid = 0;
3472     struct ViceIoctl blob;
3473
3474     blob.in = NULL;
3475     blob.in_size = 0;
3476
3477     space[0] = space[1] = space[2] = space[3] = 0;
3478
3479     ti = as->parms[0].items;
3480     if (ti) {
3481         modename = ti->data;
3482         modelen = strlen(modename);
3483         for (mode = 0; modenames[mode] != NULL; mode++)
3484             if (!strncasecmp(modename, modenames[mode], modelen))
3485                 break;
3486         if (modenames[mode] == NULL)
3487             printf("Unknown discon mode \"%s\"\n", modename);
3488         else {
3489             space[0] = mode + 1;
3490         }
3491     }
3492     ti = as->parms[1].items;
3493     if (ti) {
3494         policyname = ti->data;
3495         policylen = strlen(policyname);
3496         for (policy = 0; policynames[policy] != NULL; policy++)
3497             if (!strncasecmp(policyname, policynames[policy], policylen))
3498                 break;
3499         if (policynames[policy] == NULL)
3500             printf("Unknown discon mode \"%s\"\n", policyname);
3501         else {
3502             space[1] = policy + 1;
3503         }
3504     }
3505
3506     if (as->parms[2].items) {
3507         space[2] = 1;
3508         printf("force on\n");
3509     }
3510
3511     ti = as->parms[3].items;
3512     if (ti) {
3513         code = util_GetInt32(ti->data, &unixuid);
3514         if (code) {
3515             fprintf(stderr, "%s: bad integer specified for uid.\n", pn);
3516             return 1;
3517         }
3518         space[3] = unixuid;
3519     } else
3520         space[3] = 0;
3521
3522     blob.in = space;
3523     blob.in_size = 4 * sizeof(afs_int32);
3524
3525     blob.out_size = sizeof(mode);
3526     blob.out = space;
3527     code = pioctl(0, VIOC_DISCON, &blob, 1);
3528     if (code)
3529         Die(errno, NULL);
3530     else {
3531         memcpy(&mode, space, sizeof mode);
3532         if (mode < sizeof modenames / sizeof (char *))
3533             printf("Discon mode is now \"%s\"\n", modenames[mode]);
3534         else
3535             printf("Unknown discon mode %d\n", mode);
3536     }
3537
3538     return 0;
3539 }
3540
3541 #include "AFS_component_version_number.c"
3542
3543 int
3544 main(int argc, char **argv)
3545 {
3546     afs_int32 code;
3547     struct cmd_syndesc *ts;
3548
3549 #ifdef  AFS_AIX32_ENV
3550     /*
3551      * The following signal action for AIX is necessary so that in case of a
3552      * crash (i.e. core is generated) we can include the user's data section
3553      * in the core dump. Unfortunately, by default, only a partial core is
3554      * generated which, in many cases, isn't too useful.
3555      */
3556     struct sigaction nsa;
3557
3558     sigemptyset(&nsa.sa_mask);
3559     nsa.sa_handler = SIG_DFL;
3560     nsa.sa_flags = SA_FULLDUMP;
3561     sigaction(SIGSEGV, &nsa, NULL);
3562 #endif
3563
3564     /* try to find volume location information */
3565     ts = cmd_CreateSyntax("getclientaddrs", GetClientAddrsCmd, NULL,
3566                           "get client network interface addresses");
3567     cmd_CreateAlias(ts, "gc");
3568
3569     ts = cmd_CreateSyntax("setclientaddrs", SetClientAddrsCmd, NULL,
3570                           "set client network interface addresses");
3571     cmd_AddParm(ts, "-address", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
3572                 "client network interfaces");
3573     cmd_CreateAlias(ts, "sc");
3574
3575     ts = cmd_CreateSyntax("setserverprefs", SetPrefCmd, NULL,
3576                           "set server ranks");
3577     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
3578                 "fileserver names and ranks");
3579     cmd_AddParm(ts, "-vlservers", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
3580                 "VL server names and ranks");
3581     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL,
3582                 "input from named file");
3583     cmd_AddParm(ts, "-stdin", CMD_FLAG, CMD_OPTIONAL, "input from stdin");
3584     cmd_CreateAlias(ts, "sp");
3585
3586     ts = cmd_CreateSyntax("getserverprefs", GetPrefCmd, NULL,
3587                           "get server ranks");
3588     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL,
3589                 "output to named file");
3590     cmd_AddParm(ts, "-numeric", CMD_FLAG, CMD_OPTIONAL, "addresses only");
3591     cmd_AddParm(ts, "-vlservers", CMD_FLAG, CMD_OPTIONAL, "VL servers");
3592 /*    cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */
3593     cmd_CreateAlias(ts, "gp");
3594
3595     ts = cmd_CreateSyntax("setacl", SetACLCmd, NULL, "set access control list");
3596     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
3597     cmd_AddParm(ts, "-acl", CMD_LIST, 0, "access list entries");
3598     cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, "clear access list");
3599     cmd_AddParm(ts, "-negative", CMD_FLAG, CMD_OPTIONAL,
3600                 "apply to negative rights");
3601     parm_setacl_id = ts->nParms;
3602     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL,
3603                 "initial directory acl (DFS only)");
3604     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL,
3605                 "initial file acl (DFS only)");
3606     cmd_CreateAlias(ts, "sa");
3607
3608     ts = cmd_CreateSyntax("listacl", ListACLCmd, NULL,
3609                           "list access control list");
3610     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3611     parm_listacl_id = ts->nParms;
3612     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl");
3613     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl");
3614     cmd_AddParm(ts, "-cmd", CMD_FLAG, CMD_OPTIONAL, "output as 'fs setacl' command");
3615     cmd_CreateAlias(ts, "la");
3616
3617     ts = cmd_CreateSyntax("getcalleraccess", GetCallerAccess, NULL,
3618             "list callers access");
3619     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3620     cmd_CreateAlias(ts, "gca");
3621
3622     ts = cmd_CreateSyntax("cleanacl", CleanACLCmd, NULL,
3623                           "clean up access control list");
3624     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3625
3626     ts = cmd_CreateSyntax("copyacl", CopyACLCmd, NULL,
3627                           "copy access control list");
3628     cmd_AddParm(ts, "-fromdir", CMD_SINGLE, 0,
3629                 "source directory (or DFS file)");
3630     cmd_AddParm(ts, "-todir", CMD_LIST, 0,
3631                 "destination directory (or DFS file)");
3632     cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL,
3633                 "first clear dest access list");
3634     parm_copyacl_id = ts->nParms;
3635     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl");
3636     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl");
3637
3638     cmd_CreateAlias(ts, "ca");
3639
3640     ts = cmd_CreateSyntax("flush", FlushCmd, NULL, "flush file from cache");
3641     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3642     ts = cmd_CreateSyntax("flushmount", FlushMountCmd, NULL,
3643                           "flush mount symlink from cache");
3644     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3645
3646     ts = cmd_CreateSyntax("setvol", SetVolCmd, NULL, "set volume status");
3647     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3648     cmd_AddParm(ts, "-max", CMD_SINGLE, CMD_OPTIONAL,
3649                 "disk space quota in 1K units");
3650 #ifdef notdef
3651     cmd_AddParm(ts, "-min", CMD_SINGLE, CMD_OPTIONAL,
3652                 "disk space guaranteed");
3653     cmd_AddParm(ts, "-motd", CMD_SINGLE, CMD_OPTIONAL, "message of the day");
3654 #endif
3655     cmd_AddParm(ts, "-offlinemsg", CMD_SINGLE, CMD_OPTIONAL,
3656                 "offline message");
3657     cmd_CreateAlias(ts, "sv");
3658
3659     ts = cmd_CreateSyntax("messages", MessagesCmd, NULL,
3660                           "control Cache Manager messages");
3661     cmd_AddParm(ts, "-show", CMD_SINGLE, CMD_OPTIONAL,
3662                 "[user|console|all|none]");
3663
3664     ts = cmd_CreateSyntax("examine", ExamineCmd, NULL, "display file/volume status");
3665     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3666     cmd_CreateAlias(ts, "lv");
3667     cmd_CreateAlias(ts, "listvol");
3668
3669     ts = cmd_CreateSyntax("listquota", ListQuotaCmd, NULL, "list volume quota");
3670     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3671     cmd_AddParm(ts, "-human", CMD_FLAG, CMD_OPTIONAL, "human-readable listing");
3672     cmd_CreateAlias(ts, "lq");
3673
3674     ts = cmd_CreateSyntax("diskfree", DiskFreeCmd, NULL,
3675                           "show server disk space usage");
3676     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3677     cmd_AddParm(ts, "-human", CMD_FLAG, CMD_OPTIONAL, "human-readable listing");
3678     cmd_CreateAlias(ts, "df");
3679
3680     ts = cmd_CreateSyntax("quota", QuotaCmd, NULL, "show volume quota usage");
3681     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
3682
3683     ts = cmd_CreateSyntax("lsmount", ListMountCmd, NULL, "list mount point");
3684     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
3685
3686     ts = cmd_CreateSyntax("mkmount", MakeMountCmd, NULL, "make mount point");
3687     cmd_AddParm(ts, "-dir", CMD_SINGLE, 0, "directory");
3688     cmd_AddParm(ts, "-vol", CMD_SINGLE, 0, "volume name");
3689     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
3690     cmd_AddParm(ts, "-rw", CMD_FLAG, CMD_OPTIONAL, "force r/w volume");
3691     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL,
3692                 "don't check name with VLDB");
3693
3694 #if defined(AFS_CACHE_BYPASS)
3695         ts = cmd_CreateSyntax("bypassthreshold", BypassThresholdCmd, 0,
3696                 "get/set cache bypass file size threshold");
3697         cmd_AddParm(ts, "-size", CMD_SINGLE, CMD_OPTIONAL, "file size");
3698 #endif
3699
3700 /*
3701
3702 defect 3069
3703
3704     cmd_AddParm(ts, "-root", CMD_FLAG, CMD_OPTIONAL, "create cellular mount point");
3705 */
3706
3707
3708     ts = cmd_CreateSyntax("rmmount", RemoveMountCmd, NULL, "remove mount point");
3709     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
3710
3711     ts = cmd_CreateSyntax("checkservers", CheckServersCmd, NULL,
3712                           "check local cell's servers");
3713     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell to check");
3714     cmd_AddParm(ts, "-all", CMD_FLAG, CMD_OPTIONAL, "check all cells");
3715     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL,
3716                 "just list, don't check");
3717     cmd_AddParm(ts, "-interval", CMD_SINGLE, CMD_OPTIONAL,
3718                 "seconds between probes");
3719
3720     ts = cmd_CreateSyntax("checkvolumes", CheckVolumesCmd, NULL,
3721                           "check volumeID/name mappings");
3722     cmd_CreateAlias(ts, "checkbackups");
3723
3724
3725     ts = cmd_CreateSyntax("setcachesize", SetCacheSizeCmd, NULL,
3726                           "set cache size");
3727     cmd_AddParm(ts, "-blocks", CMD_SINGLE, CMD_OPTIONAL,
3728                 "size in 1K byte blocks (0 => reset)");
3729     cmd_CreateAlias(ts, "cachesize");
3730
3731     cmd_AddParm(ts, "-reset", CMD_FLAG, CMD_OPTIONAL,
3732                 "reset size back to boot value");
3733
3734     ts = cmd_CreateSyntax("getcacheparms", GetCacheParmsCmd, NULL,
3735                           "get cache usage info");
3736     cmd_AddParm(ts, "-files", CMD_FLAG, CMD_OPTIONAL, "Show cach files used as well");
3737     cmd_AddParm(ts, "-excessive", CMD_FLAG, CMD_OPTIONAL, "excessively verbose cache stats");
3738
3739     ts = cmd_CreateSyntax("listcells", ListCellsCmd, NULL,
3740                           "list configured cells");
3741    &nbs