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