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