64abc216c78e210c6e3c479fc44c685031c2ce8a
[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     struct cmd_item *ti;
1352
1353     blob.in_size = blob.out_size = 0;
1354     code = pioctl(NULL, VIOC_FLUSHALL, &blob, 0);
1355     if (code) {
1356         fprintf(stderr, "Error flushing all ");
1357         return 1;
1358     }
1359     return 0;
1360 }
1361
1362 static int
1363 FlushVolumeCmd(struct cmd_syndesc *as, char *arock)
1364 {
1365     afs_int32 code;
1366     struct ViceIoctl blob;
1367     struct cmd_item *ti;
1368     int error = 0;
1369
1370     SetDotDefault(&as->parms[0].items);
1371     for(ti=as->parms[0].items; ti; ti=ti->next) {
1372         blob.in_size = blob.out_size = 0;
1373         code = pioctl(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
1374         if (code) {
1375             fprintf(stderr, "Error flushing volume ");
1376             perror(ti->data);
1377             error = 1;
1378             continue;
1379         }
1380     }
1381     return error;
1382 }
1383
1384 static int 
1385 FlushCmd(struct cmd_syndesc *as, char *arock) 
1386 {
1387     afs_int32 code;
1388     struct ViceIoctl blob;
1389     struct cmd_item *ti;
1390
1391     int error = 0;
1392
1393     for(ti=as->parms[0].items; ti; ti=ti->next) {
1394         blob.in_size = blob.out_size = 0;
1395         code = pioctl(ti->data, VIOCFLUSH, &blob, 0);
1396         if (code) {
1397             if (errno == EMFILE) {
1398                 fprintf(stderr, "%s: Can't flush active file %s\n", pn, 
1399                         ti->data);
1400             } else {
1401                 fprintf(stderr, "%s: Error flushing file ", pn);
1402                 perror(ti->data);
1403             }
1404             error = 1;
1405             continue;
1406         }
1407     }
1408     return error;
1409 }
1410
1411 /* all this command does is repackage its args and call SetVolCmd */
1412 static int
1413 SetQuotaCmd(struct cmd_syndesc *as, char *arock) {
1414     struct cmd_syndesc ts;
1415
1416     /* copy useful stuff from our command slot; we may later have to reorder */
1417     memcpy(&ts, as, sizeof(ts));        /* copy whole thing */
1418     return SetVolCmd(&ts, arock);
1419 }
1420
1421 static int
1422 SetVolCmd(struct cmd_syndesc *as, char *arock) {
1423     afs_int32 code;
1424     struct ViceIoctl blob;
1425     struct cmd_item *ti;
1426     struct VolumeStatus *status;
1427     char *motd, *offmsg, *input;
1428     int error = 0;
1429
1430     SetDotDefault(&as->parms[0].items);
1431     for(ti=as->parms[0].items; ti; ti=ti->next) {
1432         /* once per file */
1433         blob.out_size = MAXSIZE;
1434         blob.in_size = sizeof(*status) + 3;     /* for the three terminating nulls */
1435         blob.out = space;
1436         blob.in = space;
1437         status = (VolumeStatus *)space;
1438         status->MinQuota = status->MaxQuota = -1;
1439         motd = offmsg = NULL;
1440         if (as->parms[1].items) {
1441             code = util_GetInt32(as->parms[1].items->data, &status->MaxQuota);
1442             if (code) {
1443                 fprintf(stderr,"%s: bad integer specified for quota.\n", pn);
1444                 error = 1;
1445                 continue;
1446             }
1447         }
1448         if (as->parms[2].items) 
1449             motd = as->parms[2].items->data;
1450         if (as->parms[3].items) 
1451             offmsg = as->parms[3].items->data;
1452         input = (char *)status + sizeof(*status);
1453         *(input++) = '\0';      /* never set name: this call doesn't change vldb */
1454         if(offmsg) {
1455             if (strlen(offmsg) >= VMSGSIZE) {
1456                 fprintf(stderr,"%s: message must be shorter than %d characters\n",
1457                          pn, VMSGSIZE);
1458                 error = 1;
1459                 continue;
1460             }
1461             strcpy(input,offmsg);
1462             blob.in_size += strlen(offmsg);
1463             input += strlen(offmsg) + 1;
1464         } else 
1465             *(input++) = '\0';
1466         if(motd) {
1467             if (strlen(motd) >= VMSGSIZE) {
1468                 fprintf(stderr,"%s: message must be shorter than %d characters\n",
1469                          pn, VMSGSIZE);
1470                 return code;
1471             }
1472             strcpy(input,motd);
1473             blob.in_size += strlen(motd);
1474             input += strlen(motd) + 1;
1475         } else 
1476             *(input++) = '\0';
1477         code = pioctl(ti->data,VIOCSETVOLSTAT, &blob, 1);
1478         if (code) {
1479             error = 1;
1480         }
1481     }
1482     return error;
1483 }
1484
1485 #ifndef WIN32
1486 /* 
1487  * Why is VenusFid declared in the kernel-only section of afs.h, 
1488  * if it's the exported interface of the (UNIX) cache manager?
1489  */
1490 struct VenusFid {
1491     afs_int32 Cell;
1492     AFSFid Fid;
1493 };
1494 #endif /* WIN32 */
1495
1496 static int 
1497 ExamineCmd(struct cmd_syndesc *as, char *arock)
1498 {
1499     afs_int32 code;
1500     struct ViceIoctl blob;
1501     struct cmd_item *ti;
1502     struct VolumeStatus *status;
1503     char *name, *offmsg, *motd;
1504     int error = 0;
1505     
1506     SetDotDefault(&as->parms[0].items);
1507     for(ti=as->parms[0].items; ti; ti=ti->next) {
1508 #ifndef WIN32
1509         struct VenusFid vfid;
1510 #endif /* WIN32 */
1511         /* once per file */
1512         blob.out_size = MAXSIZE;
1513         blob.in_size = 0;
1514         blob.out = space;
1515         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1516         if (code) {
1517             Die(errno, ti->data);
1518             error = 1;
1519             continue;
1520         }
1521         status = (VolumeStatus *)space;
1522         name = (char *)status + sizeof(*status);
1523         offmsg = name + strlen(name) + 1;
1524         motd = offmsg + strlen(offmsg) + 1;
1525
1526 #ifndef WIN32
1527         blob.out_size = sizeof(struct VenusFid);
1528         blob.out = (char *) &vfid;
1529         if (0 == pioctl(ti->data, VIOCGETFID, &blob, 1)) {
1530             printf("File %s (%u.%u.%u) contained in volume %u\n",
1531                     ti->data, vfid.Fid.Volume, vfid.Fid.Vnode, vfid.Fid.Unique,
1532                     vfid.Fid.Volume);
1533         }
1534 #endif /* WIN32 */
1535         PrintStatus(status, name, motd, offmsg);
1536     }
1537     return error;
1538 }
1539
1540 static int
1541 ListQuotaCmd(struct cmd_syndesc *as, char *arock) 
1542 {
1543     afs_int32 code;
1544     struct ViceIoctl blob;
1545     struct cmd_item *ti;
1546     struct VolumeStatus *status;
1547     char *name;
1548
1549     int error = 0;
1550     
1551     printf("%-25s%-10s%-10s%-7s%-13s\n", 
1552            "Volume Name", "     Quota", "      Used", "  %Used", "    Partition");
1553     SetDotDefault(&as->parms[0].items);
1554     for(ti=as->parms[0].items; ti; ti=ti->next) {
1555         /* once per file */
1556         blob.out_size = MAXSIZE;
1557         blob.in_size = 0;
1558         blob.out = space;
1559         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1560         if (code) {
1561             Die(errno, ti->data);
1562             error = 1;
1563             continue;
1564         }
1565         status = (VolumeStatus *)space;
1566         name = (char *)status + sizeof(*status);
1567         QuickPrintStatus(status, name);
1568     }
1569     return error;
1570 }
1571
1572 static int
1573 WhereIsCmd(struct cmd_syndesc *as, char *arock)
1574 {
1575     afs_int32 code;
1576     struct ViceIoctl blob;
1577     struct cmd_item *ti;
1578     int j;
1579     afs_int32 *hosts;
1580     char *tp;
1581     int error = 0;
1582     
1583     SetDotDefault(&as->parms[0].items);
1584     for(ti=as->parms[0].items; ti; ti=ti->next) {
1585         /* once per file */
1586         blob.out_size = MAXSIZE;
1587         blob.in_size = 0;
1588         blob.out = space;
1589         memset(space, 0, sizeof(space));
1590         code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
1591         if (code) {
1592             Die(errno, ti->data);
1593             error = 1;
1594             continue;
1595         }
1596         hosts = (afs_int32 *) space;
1597         printf("File %s is on host%s ", ti->data, 
1598                 (hosts[0] && !hosts[1]) ? "": "s");
1599         for(j=0; j<MAXHOSTS; j++) {
1600             if (hosts[j] == 0) 
1601                 break;
1602             tp = hostutil_GetNameByINet(hosts[j]);
1603             printf("%s ", tp);
1604         }
1605         printf("\n");
1606     }
1607     return error;
1608 }
1609
1610
1611 static int
1612 DiskFreeCmd(struct cmd_syndesc *as, char *arock)
1613 {
1614     afs_int32 code;
1615     struct ViceIoctl blob;
1616     struct cmd_item *ti;
1617     char *name;
1618     struct VolumeStatus *status;
1619     int error = 0;
1620     
1621     printf("%-25s%-10s%-10s%-10s%-6s\n", "Volume Name", "    kbytes",
1622            "      used", "     avail", " %used");
1623     SetDotDefault(&as->parms[0].items);
1624     for(ti=as->parms[0].items; ti; ti=ti->next) {
1625         /* once per file */
1626         blob.out_size = MAXSIZE;
1627         blob.in_size = 0;
1628         blob.out = space;
1629         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1630         if (code) {
1631             Die(errno, ti->data);
1632             error = 1;
1633             continue;
1634         }
1635         status = (VolumeStatus *)space;
1636         name = (char *)status + sizeof(*status);
1637         QuickPrintSpace(status, name);
1638     }
1639     return error;
1640 }
1641
1642 static int
1643 QuotaCmd(struct cmd_syndesc *as, char *arock)
1644 {
1645     afs_int32 code;
1646     struct ViceIoctl blob;
1647     struct cmd_item *ti;
1648     double quotaPct;
1649     struct VolumeStatus *status;
1650     int error = 0;
1651     
1652     SetDotDefault(&as->parms[0].items);
1653     for(ti=as->parms[0].items; ti; ti=ti->next) {
1654         /* once per file */
1655         blob.out_size = MAXSIZE;
1656         blob.in_size = 0;
1657         blob.out = space;
1658         code = pioctl(ti->data, VIOCGETVOLSTAT, &blob, 1);
1659         if (code) {
1660             Die(errno, ti->data);
1661             error = 1;
1662             continue;
1663         }
1664         status = (VolumeStatus *)space;
1665         if (status->MaxQuota) 
1666             quotaPct = ((((double)status->BlocksInUse)/status->MaxQuota) * 100.0);
1667         else 
1668             quotaPct = 0.0;
1669         printf("%2.0f%% of quota used.\n", quotaPct);
1670     }
1671     return error;
1672 }
1673
1674 static int
1675 ListMountCmd(struct cmd_syndesc *as, char *arock)
1676 {
1677     afs_int32 code;
1678     struct ViceIoctl blob;
1679     struct cmd_item *ti;
1680     char orig_name[1024];               /*Original name, may be modified*/
1681     char true_name[1024];               /*``True'' dirname (e.g., symlink target)*/
1682     char parent_dir[1024];              /*Parent directory of true name*/
1683     char *last_component;       /*Last component of true name*/
1684 #ifndef WIN32
1685     struct stat statbuff;               /*Buffer for status info*/
1686 #endif /* not WIN32 */
1687 #ifndef WIN32
1688     int link_chars_read;                /*Num chars read in readlink()*/
1689 #endif /* not WIN32 */
1690     int thru_symlink;                   /*Did we get to a mount point via a symlink?*/
1691     
1692     int error = 0;
1693     for(ti=as->parms[0].items; ti; ti=ti->next) {
1694         /* once per file */
1695         thru_symlink = 0;
1696 #ifdef WIN32
1697         strcpy(orig_name, ti->data);
1698 #else /* not WIN32 */
1699         sprintf(orig_name, "%s%s",
1700                 (ti->data[0] == '/') ? "" : "./",
1701                 ti->data);
1702 #endif /* not WIN32 */
1703
1704 #ifndef WIN32
1705         if (lstat(orig_name, &statbuff) < 0) {
1706             /* if lstat fails, we should still try the pioctl, since it
1707              * may work (for example, lstat will fail, but pioctl will
1708              * work if the volume of offline (returning ENODEV). */
1709             statbuff.st_mode = S_IFDIR; /* lie like pros */
1710         }
1711
1712         /*
1713          * The lstat succeeded.  If the given file is a symlink, substitute
1714          * the file name with the link name.
1715          */
1716         if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
1717             thru_symlink = 1;
1718             /*
1719              * Read name of resolved file.
1720              */
1721             link_chars_read = readlink(orig_name, true_name, 1024);
1722             if (link_chars_read <= 0) {
1723                 fprintf(stderr,
1724                         "%s: Can't read target name for '%s' symbolic link!\n",
1725                        pn, orig_name);
1726                 error = 1;
1727                 continue;
1728             }
1729
1730             /*
1731              * Add a trailing null to what was read, bump the length.
1732              */
1733             true_name[link_chars_read++] = 0;
1734
1735             /*
1736              * If the symlink is an absolute pathname, we're fine.  Otherwise, we
1737              * have to create a full pathname using the original name and the
1738              * relative symlink name.  Find the rightmost slash in the original
1739              * name (we know there is one) and splice in the symlink value.
1740              */
1741             if (true_name[0] != '\\') {
1742                 last_component = (char *) strrchr(orig_name, '\\');
1743                 strcpy(++last_component, true_name);
1744                 strcpy(true_name, orig_name);
1745             }
1746         } else
1747             strcpy(true_name, orig_name);
1748 #else   /* WIN32 */
1749         strcpy(true_name, orig_name);
1750 #endif /* WIN32 */
1751
1752         /*
1753          * Find rightmost slash, if any.
1754          */
1755 #ifdef WIN32
1756         last_component = (char *) strrchr(true_name, '\\');
1757         if (!last_component)
1758 #endif /* WIN32 */
1759             last_component = (char *) strrchr(true_name, '/');
1760         if (last_component) {
1761             /*
1762              * Found it.  Designate everything before it as the parent directory,
1763              * everything after it as the final component.
1764              */
1765             strncpy(parent_dir, true_name, last_component - true_name + 1);
1766             parent_dir[last_component - true_name + 1] = 0;
1767             last_component++;   /*Skip the slash*/
1768 #ifdef WIN32
1769             if (!InAFS(parent_dir)) {
1770                 const char * nbname = NetbiosName();
1771                 int len = strlen(nbname);
1772
1773                 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
1774                     parent_dir[len+2] == '\\' &&
1775                     parent_dir[len+3] == '\0' &&
1776                     !strnicmp(nbname,&parent_dir[2],len))
1777                 {
1778                     sprintf(parent_dir,"\\\\%s\\all\\", nbname);
1779                 }
1780             }
1781 #endif
1782         } else {
1783             /*
1784              * No slash appears in the given file name.  Set parent_dir to the current
1785              * directory, and the last component as the given name.
1786              */
1787             fs_ExtractDriveLetter(true_name, parent_dir);
1788             strcat(parent_dir, ".");
1789             last_component = true_name;
1790             fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
1791         }
1792
1793         if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
1794             fprintf(stderr,"%s: you may not use '.' or '..' as the last component\n",pn);
1795             fprintf(stderr,"%s: of a name in the 'fs lsmount' command.\n",pn);
1796             error = 1;
1797             continue;
1798         }
1799
1800         blob.in = last_component;
1801         blob.in_size = strlen(last_component)+1;
1802         blob.out_size = MAXSIZE;
1803         blob.out = space;
1804         memset(space, 0, MAXSIZE);
1805
1806         code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
1807
1808         if (code == 0) {
1809             printf("'%s' is a %smount point for volume '%s'\n",
1810                    ti->data,
1811                    (thru_symlink ? "symbolic link, leading to a " : ""),
1812                    space);
1813
1814         } else {
1815             if (errno == EINVAL) {
1816                 fprintf(stderr,"'%s' is not a mount point.\n", ti->data);
1817             } else {
1818                 Die(errno, (ti->data ? ti->data : parent_dir));
1819             }
1820             error = 1;
1821         }
1822     }
1823     return error;
1824 }
1825
1826 static int
1827 MakeMountCmd(struct cmd_syndesc *as, char *arock)
1828 {
1829     afs_int32 code;
1830     char *cellName, *volName, *tmpName;
1831 #ifdef WIN32
1832     char localCellName[128];
1833 #endif
1834     char path[1024] = "";
1835     struct afsconf_cell info;
1836     struct vldbentry vldbEntry;
1837     struct ViceIoctl blob;
1838     char * parent;
1839
1840     if (as->parms[2].items)     /* cell name specified */
1841         cellName = as->parms[2].items->data;
1842     else
1843         cellName = NULL;
1844     volName = as->parms[1].items->data;
1845
1846     if (strlen(volName) >= 64) {
1847         fprintf(stderr,"%s: volume name too long (length must be < 64 characters)\n", pn);
1848         return 1;
1849     }
1850
1851     /* Check for a cellname in the volume specification, and complain
1852      * if it doesn't match what was specified with -cell */
1853     if (tmpName = strchr(volName, ':')) {
1854         *tmpName = '\0';
1855         if (cellName) {
1856             if (strcasecmp(cellName,volName)) {
1857                 fprintf(stderr,"fs: cellnames do not match.\n");
1858                 return 1;
1859             }
1860         }
1861         cellName = volName;
1862         volName = ++tmpName;
1863     }
1864
1865     parent = Parent(as->parms[0].items->data);
1866     if (!InAFS(parent)) {
1867 #ifdef WIN32
1868         const char * nbname = NetbiosName();
1869         int len = strlen(nbname);
1870
1871         if (parent[0] == '\\' && parent[1] == '\\' &&
1872             parent[len+2] == '\\' &&
1873             parent[len+3] == '\0' &&
1874             !strnicmp(nbname,&parent[2],len))
1875         {
1876             sprintf(path,"%sall\\%s", parent, &as->parms[0].items->data[strlen(parent)]);
1877             parent = Parent(path);
1878             if (!InAFS(parent)) {
1879                 fprintf(stderr,"%s: mount points must be created within the AFS file system\n", pn);
1880                 return 1;
1881             }
1882         } else 
1883 #endif
1884         {
1885             fprintf(stderr,"%s: mount points must be created within the AFS file system\n", pn);
1886             return 1;
1887         }
1888     }
1889
1890     if ( strlen(path) == 0 )
1891         strcpy(path, as->parms[0].items->data);
1892
1893     if ( IsFreelanceRoot(parent) ) {
1894         if ( !IsAdmin() ) {
1895             fprintf(stderr,"%s: Only AFS Client Administrators may alter the root.afs volume\n", pn);
1896             return 1;
1897         }
1898
1899         if (!cellName) {
1900             blob.in_size = 0;
1901             blob.out_size = sizeof(localCellName);
1902             blob.out = localCellName;
1903             code = pioctl(parent, VIOC_GET_WS_CELL, &blob, 1);
1904             if (!code)
1905                 cellName = localCellName;
1906         }
1907     } else {
1908         if (!cellName)
1909             GetCell(parent,space);
1910     }
1911
1912     code = GetCellName(cellName?cellName:space, &info);
1913     if (code) {
1914         return 1;
1915     }
1916 #ifndef WIN32
1917     if (!(as->parms[4].items)) {
1918       /* not fast, check which cell the mountpoint is being created in */
1919       code = 0;
1920         /* not fast, check name with VLDB */
1921       if (!code)
1922         code = VLDBInit(1, &info);
1923       if (code == 0) {
1924           /* make the check.  Don't complain if there are problems with init */
1925           code = ubik_Call(VL_GetEntryByNameO, uclient, 0, volName, &vldbEntry);
1926           if (code == VL_NOENT) {
1927               fprintf(stderr,"%s: warning, volume %s does not exist in cell %s.\n",
1928                       pn, volName, cellName ? cellName : space);
1929           }
1930       }
1931     }
1932 #endif /* not WIN32 */
1933
1934     if (as->parms[3].items)     /* if -rw specified */
1935         strcpy(space, "%");
1936     else
1937         strcpy(space, "#");
1938     if (cellName) {
1939         /* cellular mount point, prepend cell prefix */
1940         strcat(space, info.name);
1941         strcat(space, ":");
1942     }
1943     strcat(space, volName);     /* append volume name */
1944     strcat(space, ".");         /* stupid convention; these end with a period */
1945 #ifdef WIN32
1946     /* create symlink with a special pioctl for Windows NT, since it doesn't
1947      * have a symlink system call.
1948      */
1949     blob.out_size = 0;
1950     blob.in_size = 1 + strlen(space);
1951     blob.in = space;
1952     blob.out = NULL;
1953     code = pioctl(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
1954 #else /* not WIN32 */
1955     code = symlink(space, path);
1956 #endif /* not WIN32 */
1957     if (code) {
1958         Die(errno, path);
1959         return 1;
1960     }
1961     return 0;
1962 }
1963
1964 /*
1965  * Delete AFS mount points.  Variables are used as follows:
1966  *       tbuffer: Set to point to the null-terminated directory name of the mount point
1967  *          (or ``.'' if none is provided)
1968  *      tp: Set to point to the actual name of the mount point to nuke.
1969  */
1970 static int
1971 RemoveMountCmd(struct cmd_syndesc *as, char *arock) {
1972     afs_int32 code=0;
1973     struct ViceIoctl blob;
1974     struct cmd_item *ti;
1975     char tbuffer[1024];
1976     char lsbuffer[1024];
1977     char *tp;
1978     int error = 0;
1979     
1980     for(ti=as->parms[0].items; ti; ti=ti->next) {
1981         /* once per file */
1982         tp = (char *) strrchr(ti->data, '\\');
1983         if (!tp)
1984             tp = (char *) strrchr(ti->data, '/');
1985         if (tp) {
1986             strncpy(tbuffer, ti->data, code=tp-ti->data+1);  /* the dir name */
1987             tbuffer[code] = 0;
1988             tp++;   /* skip the slash */
1989
1990 #ifdef WIN32
1991             if (!InAFS(tbuffer)) {
1992                 const char * nbname = NetbiosName();
1993                 int len = strlen(nbname);
1994
1995                 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
1996                     tbuffer[len+2] == '\\' &&
1997                     tbuffer[len+3] == '\0' &&
1998                     !strnicmp(nbname,&tbuffer[2],len))
1999                 {
2000                     sprintf(tbuffer,"\\\\%s\\all\\", nbname);
2001                 }
2002             }
2003 #endif
2004         } else {
2005             fs_ExtractDriveLetter(ti->data, tbuffer);
2006             strcat(tbuffer, ".");
2007             tp = ti->data;
2008             fs_StripDriveLetter(tp, tp, 0);
2009         }
2010         blob.in = tp;
2011         blob.in_size = strlen(tp)+1;
2012         blob.out = lsbuffer;
2013         blob.out_size = sizeof(lsbuffer);
2014         code = pioctl(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
2015         if (code) {
2016             if (errno == EINVAL) {
2017                 fprintf(stderr,"%s: '%s' is not a mount point.\n", pn, ti->data);
2018             } else {
2019                 Die(errno, ti->data);
2020             }
2021             error = 1;
2022             continue;   /* don't bother trying */
2023         }
2024
2025         if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
2026             fprintf(stderr,"%s: Only AFS Client Administrators may alter the root.afs volume\n", pn);
2027             error = 1;
2028             continue;   /* skip */
2029         }
2030
2031         blob.out_size = 0;
2032         blob.in = tp;
2033         blob.in_size = strlen(tp)+1;
2034         code = pioctl(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
2035         if (code) {
2036             Die(errno, ti->data);
2037             error = 1;
2038         }
2039     }
2040     return error;
2041 }
2042
2043 /*
2044 */
2045
2046 static int
2047 CheckServersCmd(struct cmd_syndesc *as, char *arock)
2048 {
2049     afs_int32 code;
2050     struct ViceIoctl blob;
2051     afs_int32 j;
2052     afs_int32 temp;
2053     char *tp;
2054     struct afsconf_cell info;
2055     struct chservinfo checkserv;
2056
2057     memset(&checkserv, 0, sizeof(struct chservinfo));
2058     blob.in_size=sizeof(struct chservinfo);
2059     blob.in=(caddr_t)&checkserv;
2060
2061     blob.out_size = MAXSIZE;
2062     blob.out = space;
2063     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
2064
2065     /* prepare flags for checkservers command */
2066     temp = 2;   /* default to checking local cell only */
2067     if (as->parms[2].items) 
2068         temp |= 1;      /* set fast flag */
2069     if (as->parms[1].items) 
2070         temp &= ~2;     /* turn off local cell check */
2071     
2072     checkserv.magic = 0x12345678;       /* XXX */
2073     checkserv.tflags=temp;
2074
2075     /* now copy in optional cell name, if specified */
2076     if (as->parms[0].items) {
2077         code = GetCellName(as->parms[0].items->data, &info);
2078         if (code) {
2079             return 1;
2080         }
2081         strcpy(checkserv.tbuffer,info.name);
2082         checkserv.tsize=strlen(info.name)+1;
2083     } else {
2084         strcpy(checkserv.tbuffer,"\0");
2085         checkserv.tsize=0;
2086     }
2087
2088     if(as->parms[3].items) {
2089         checkserv.tinterval=atol(as->parms[3].items->data);
2090
2091         /* sanity check */
2092         if(checkserv.tinterval<0) {
2093             printf("Warning: The negative -interval is ignored; treated as an inquiry\n");
2094             checkserv.tinterval=0;
2095         } else if(checkserv.tinterval> 600) {
2096             printf("Warning: The maximum -interval value is 10 mins (600 secs)\n");
2097             checkserv.tinterval=600;    /* 10 min max interval */
2098         }       
2099     } else {
2100         checkserv.tinterval = -1;       /* don't change current interval */
2101     }
2102
2103     if ( checkserv.tinterval != 0 ) {
2104 #ifdef WIN32
2105         if ( !IsAdmin() ) {
2106             fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2107             return EACCES;
2108         }
2109 #else /* WIN32 */
2110         if (geteuid()) {
2111             fprintf (stderr,"Permission denied: requires root access.\n");
2112             return EACCES;
2113         }
2114 #endif /* WIN32 */
2115     }
2116
2117     code = pioctl(0, VIOCCKSERV, &blob, 1);
2118     if (code) {
2119         if ((errno == EACCES) && (checkserv.tinterval > 0)) {
2120             printf("Must be root to change -interval\n");
2121             return code;
2122         }
2123         Die(errno, 0);
2124         return 1;
2125     }
2126     memcpy(&temp, space, sizeof(afs_int32));
2127     if (checkserv.tinterval >= 0) {
2128         if (checkserv.tinterval > 0) 
2129             printf("The new down server probe interval (%d secs) is now in effect (old interval was %d secs)\n", 
2130                    checkserv.tinterval, temp);
2131         else 
2132             printf("The current down server probe interval is %d secs\n", temp);
2133         return 0;
2134     }
2135     if (temp == 0) {
2136         printf("All servers are running.\n");
2137     } else {
2138         printf("These servers unavailable due to network or server problems: ");
2139         for(j=0; j < MAXHOSTS; j++) {
2140             memcpy(&temp, space + j*sizeof(afs_int32), sizeof(afs_int32));
2141             if (temp == 0) 
2142                 break;
2143             tp = hostutil_GetNameByINet(temp);
2144             printf(" %s", tp);
2145         }
2146         printf(".\n");
2147         code = 1;       /* XXX */
2148     }
2149     return code;
2150 }
2151
2152 static int
2153 MessagesCmd(struct cmd_syndesc *as, char *arock)
2154 {
2155     afs_int32 code=0;
2156     struct ViceIoctl blob;
2157     struct gaginfo gagflags;
2158     struct cmd_item *show;
2159     
2160     memset(&gagflags, 0, sizeof(struct gaginfo));
2161     blob.in_size = sizeof(struct gaginfo);
2162     blob.in = (caddr_t ) &gagflags;
2163     blob.out_size = MAXSIZE;
2164     blob.out = space;
2165     memset(space, 0, sizeof(afs_int32));        /* so we assure zero when nothing is copied back */
2166
2167     if (show = as->parms[0].items) {
2168         if (!strcasecmp (show->data, "user"))
2169             gagflags.showflags |= GAGUSER;
2170         else if (!strcasecmp (show->data, "console"))
2171             gagflags.showflags |= GAGCONSOLE;
2172         else if (!strcasecmp (show->data, "all"))
2173             gagflags.showflags |= GAGCONSOLE | GAGUSER;
2174         else if (!strcasecmp (show->data, "none"))
2175             /* do nothing */ ;
2176         else {
2177             fprintf(stderr, 
2178                      "unrecognized flag %s: must be in {user,console,all,none}\n", 
2179                      show->data);
2180             code = EINVAL;
2181         }
2182     }
2183  
2184     if (code)
2185         return 1;
2186
2187     code = pioctl(0, VIOC_GAG, &blob, 1);
2188     if (code) {
2189         Die(errno, 0);
2190         return 1;
2191     }
2192     return 0;
2193 }
2194
2195 static int
2196 CheckVolumesCmd(struct cmd_syndesc *as, char *arock)
2197 {
2198     afs_int32 code;
2199     struct ViceIoctl blob;
2200     
2201     blob.in_size = 0;
2202     blob.out_size = 0;
2203     code = pioctl(0, VIOCCKBACK, &blob, 1);
2204     if (code) {
2205         Die(errno, 0);
2206         return 1;
2207     }
2208     printf("All volumeID/name mappings checked.\n");
2209     
2210     return 0;
2211 }
2212
2213 static int
2214 SetCacheSizeCmd(struct cmd_syndesc *as, char *arock)
2215 {
2216     afs_int32 code;
2217     struct ViceIoctl blob;
2218     afs_int32 temp;
2219     
2220 #ifdef WIN32
2221     if ( !IsAdmin() ) {
2222         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2223         return EACCES;
2224     }
2225 #else /* WIN32 */
2226     if (geteuid()) {
2227         fprintf (stderr,"Permission denied: requires root access.\n");
2228         return EACCES;
2229     }
2230 #endif /* WIN32 */
2231
2232     if (!as->parms[0].items && !as->parms[1].items) {
2233         fprintf(stderr,"%s: syntax error in set cache size cmd.\n", pn);
2234         return 1;
2235     }
2236     if (as->parms[0].items) {
2237         code = util_GetInt32(as->parms[0].items->data, &temp);
2238         if (code) {
2239             fprintf(stderr,"%s: bad integer specified for cache size.\n", pn);
2240             return 1;
2241         }
2242     } else
2243         temp = 0;
2244     blob.in = (char *) &temp;
2245     blob.in_size = sizeof(afs_int32);
2246     blob.out_size = 0;
2247     code = pioctl(0, VIOCSETCACHESIZE, &blob, 1);
2248     if (code) {
2249         Die(errno, (char *) 0);
2250         return 1;
2251     } 
2252       
2253     printf("New cache size set.\n");
2254     return 0;
2255 }
2256
2257 #define MAXGCSIZE       16
2258 static int
2259 GetCacheParmsCmd(struct cmd_syndesc *as, char *arock)
2260 {
2261     afs_int32 code;
2262     struct ViceIoctl blob;
2263     afs_int32 parms[MAXGCSIZE];
2264
2265     memset(parms, 0, sizeof(parms));
2266     blob.in = NULL;
2267     blob.in_size = 0;
2268     blob.out_size = sizeof(parms);
2269     blob.out = (char *) parms;
2270     code = pioctl(0, VIOCGETCACHEPARMS, &blob, 1);
2271     if (code) {
2272         Die(errno, NULL);
2273         return 1;
2274     }
2275      
2276     printf("AFS using %d of the cache's available %d 1K byte blocks.\n",
2277            parms[1], parms[0]);
2278     if (parms[1] > parms[0])
2279         printf("[Cache guideline temporarily deliberately exceeded; it will be adjusted down but you may wish to increase the cache size.]\n");
2280     return 0;
2281 }
2282
2283 static int
2284 ListCellsCmd(struct cmd_syndesc *as, char *arock)
2285 {
2286     afs_int32 code;
2287     afs_int32 i, j, *lp, magic, size;
2288     char *tp;
2289     afs_int32 addr, maxa = OMAXHOSTS;
2290     struct ViceIoctl blob;
2291     int resolve;
2292
2293     resolve = !(as->parms[0].items);    /* -numeric */
2294     
2295     for(i=0;i<1000;i++) {
2296         tp = space;
2297         memcpy(tp, &i, sizeof(afs_int32));
2298         tp = (char *)(space + sizeof(afs_int32));
2299         lp = (afs_int32 *)tp;
2300         *lp++ = 0x12345678;
2301         size = sizeof(afs_int32) + sizeof(afs_int32);
2302         blob.out_size = MAXSIZE;
2303         blob.in_size = sizeof(afs_int32);
2304         blob.in = space;
2305         blob.out = space;
2306         code = pioctl(0, VIOCGETCELL, &blob, 1);
2307         if (code < 0) {
2308             if (errno == EDOM) 
2309                 break;  /* done with the list */
2310             Die(errno, 0);
2311             return 1;
2312         }       
2313         tp = space;
2314         memcpy(&magic, tp, sizeof(afs_int32));  
2315         if (magic == 0x12345678) {
2316             maxa = MAXHOSTS;
2317             tp += sizeof(afs_int32);
2318         }
2319         printf("Cell %s on hosts", tp+maxa*sizeof(afs_int32));
2320         for(j=0; j < maxa; j++) {
2321             char *name, tbuffer[20];
2322
2323             memcpy(&addr, tp + j*sizeof(afs_int32), sizeof(afs_int32));
2324             if (addr == 0) 
2325                 break;
2326
2327             if (resolve) {
2328                 name = hostutil_GetNameByINet(addr);
2329             } else {
2330                 addr = ntohl(addr);
2331                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
2332                          (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
2333                 name = tbuffer;
2334             }
2335             printf(" %s", name);
2336         }
2337         printf(".\n");
2338     }
2339     return 0;
2340 }
2341
2342 #ifndef WIN32
2343 static int
2344 ListAliasesCmd(struct cmd_syndesc *as, char *arock)
2345 {
2346     afs_int32 code, i;
2347     char *tp, *aliasName, *realName;
2348     struct ViceIoctl blob;
2349
2350     for (i = 0;; i++) {
2351         tp = space;
2352         memcpy(tp, &i, sizeof(afs_int32));
2353         blob.out_size = MAXSIZE;
2354         blob.in_size = sizeof(afs_int32);
2355         blob.in = space;
2356         blob.out = space;
2357         code = pioctl(0, VIOC_GETALIAS, &blob, 1);
2358         if (code < 0) {
2359             if (errno == EDOM)
2360                 break;          /* done with the list */
2361             Die(errno, 0);
2362             return 1;
2363         }
2364         tp = space;
2365         aliasName = tp;
2366         tp += strlen(aliasName) + 1;
2367         realName = tp;
2368         printf("Alias %s for cell %s\n", aliasName, realName);
2369     }
2370     return 0;
2371 }
2372
2373 static int
2374 CallBackRxConnCmd(struct cmd_syndesc *as, char *arock)
2375 {
2376     afs_int32 code;
2377     struct ViceIoctl blob;
2378     struct cmd_item *ti;
2379     afs_int32 hostAddr;
2380     struct hostent *thp;
2381     char *tp;
2382     int setp;
2383     
2384     ti = as->parms[0].items;
2385     setp = 1;
2386     if (ti) {
2387         thp = hostutil_GetHostByName(ti->data);
2388         if (!thp) {
2389             fprintf(stderr, "host %s not found in host table.\n", ti->data);
2390             return 1;
2391         }
2392         else memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2393     } else {
2394         hostAddr = 0;   /* means don't set host */
2395         setp = 0;       /* aren't setting host */
2396     }
2397     
2398     /* now do operation */
2399     blob.in_size = sizeof(afs_int32);
2400     blob.out_size = sizeof(afs_int32);
2401     blob.in = (char *) &hostAddr;
2402     blob.out = (char *) &hostAddr;
2403     
2404     code = pioctl(0, VIOC_CBADDR, &blob, 1);
2405     if (code < 0) {
2406         Die(errno, 0);
2407         return 1;
2408     }
2409     return 0;
2410 }
2411 #endif /* WIN32 */
2412
2413 static int
2414 NewCellCmd(struct cmd_syndesc *as, char *arock)
2415 {
2416 #ifndef WIN32
2417     afs_int32 code, linkedstate=0, size=0, *lp;
2418     struct ViceIoctl blob;
2419     struct cmd_item *ti;
2420     char *tp, *cellname=0;
2421     struct hostent *thp;
2422     afs_int32 fsport = 0, vlport = 0;
2423
2424     memset(space, 0, MAXHOSTS * sizeof(afs_int32));
2425     tp = space;
2426     lp = (afs_int32 *)tp;
2427     *lp++ = 0x12345678;
2428     tp += sizeof(afs_int32);
2429     for(ti=as->parms[1].items; ti; ti=ti->next) {
2430         thp = hostutil_GetHostByName(ti->data);
2431         if (!thp) {
2432             fprintf(stderr,"%s: Host %s not found in host table, skipping it.\n",
2433                    pn, ti->data);
2434         }
2435         else {
2436             memcpy(tp, thp->h_addr, sizeof(afs_int32));
2437             tp += sizeof(afs_int32);
2438         }
2439     }
2440     if (as->parms[2].items) {
2441         /*
2442          * Link the cell, for the purposes of volume location, to the specified
2443          * cell.
2444          */
2445         cellname = as->parms[2].items->data;
2446         linkedstate = 1;
2447     }
2448 #ifdef FS_ENABLE_SERVER_DEBUG_PORTS
2449     if (as->parms[3].items) {
2450         code = util_GetInt32(as->parms[3].items->data, &vlport);
2451         if (code) {
2452             fprintf(stderr,"fs: bad integer specified for the fileserver port.\n");
2453             return code;
2454         }
2455     }
2456     if (as->parms[4].items) {
2457         code = util_GetInt32(as->parms[4].items->data, &fsport);
2458         if (code) {
2459             fprintf(stderr,"fs: bad integer specified for the vldb server port.\n");
2460             return code;
2461         }
2462     }
2463 #endif
2464     tp = (char *)(space + (MAXHOSTS+1) *sizeof(afs_int32));
2465     lp = (afs_int32 *)tp;    
2466     *lp++ = fsport;
2467     *lp++ = vlport;
2468     *lp = linkedstate;
2469     strcpy(space +  ((MAXHOSTS+4) * sizeof(afs_int32)), as->parms[0].items->data);
2470     size = ((MAXHOSTS+4) * sizeof(afs_int32)) + strlen(as->parms[0].items->data) + 1 /* for null */;
2471     tp = (char *)(space + size);
2472     if (linkedstate) {
2473         strcpy(tp, cellname);
2474         size += strlen(cellname) + 1;
2475     }
2476     blob.in_size = size;
2477     blob.in = space;
2478     blob.out_size = 0;
2479     code = pioctl(0, VIOCNEWCELL, &blob, 1);
2480     if (code < 0)
2481         Die(errno, 0);
2482     return 0;
2483 #else /* WIN32 */
2484     afs_int32 code;
2485     struct ViceIoctl blob;
2486     
2487     if ( !IsAdmin() ) {
2488         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2489         return EACCES;
2490     }
2491
2492     blob.in_size = 0;
2493     blob.in = (char *) 0;
2494     blob.out_size = MAXSIZE;
2495     blob.out = space;
2496
2497     code = pioctl((char *) 0, VIOCNEWCELL, &blob, 1);
2498
2499     if (code) {
2500         Die(errno, (char *) 0);
2501         return 1;
2502     }
2503     
2504     printf("Cell servers information refreshed\n");
2505     return 0;
2506 #endif /* WIN32 */
2507 }
2508
2509 #ifndef WIN32
2510 static int
2511 NewAliasCmd(struct cmd_syndesc *as, char *arock)
2512 {
2513     afs_int32 code;
2514     struct ViceIoctl blob;
2515     char *tp;
2516     char *aliasName, *realName;
2517
2518     /* Setup and do the NEWALIAS pioctl call */
2519     aliasName = as->parms[0].items->data;
2520     realName = as->parms[1].items->data;
2521     tp = space;
2522     strcpy(tp, aliasName);
2523     tp += strlen(aliasName) + 1;
2524     strcpy(tp, realName);
2525     tp += strlen(realName) + 1;
2526
2527     blob.in_size = tp - space;
2528     blob.in = space;
2529     blob.out_size = 0;
2530     blob.out = space;
2531     code = pioctl(0, VIOC_NEWALIAS, &blob, 1);
2532     if (code < 0) {
2533         if (errno == EEXIST) {
2534             fprintf(stderr,
2535                     "%s: cell name `%s' in use by an existing cell.\n", pn,
2536                     aliasName);
2537         } else {
2538             Die(errno, 0);
2539         }
2540         return 1;
2541     }
2542     return 0;
2543 }
2544 #endif /* WIN32 */
2545
2546 static int
2547 WhichCellCmd(struct cmd_syndesc *as, char *arock)
2548 {
2549     afs_int32 code;
2550     struct cmd_item *ti;
2551     int error = 0;
2552     char cell[MAXCELLCHARS]="";
2553     
2554     SetDotDefault(&as->parms[0].items);
2555     for(ti=as->parms[0].items; ti; ti=ti->next) {
2556         code = GetCell(ti->data, cell);
2557         if (code) {
2558             if (errno == ENOENT)
2559                 fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
2560             else
2561                 Die(errno, ti->data);
2562             error = 1;
2563             continue;
2564         }
2565         printf("File %s lives in cell '%s'\n", ti->data, cell);
2566     }
2567     return error;
2568 }
2569
2570 static int
2571 WSCellCmd(struct cmd_syndesc *as, char *arock)
2572 {
2573     afs_int32 code;
2574     struct ViceIoctl blob;
2575     
2576     blob.in_size = 0;
2577     blob.in = NULL;
2578     blob.out_size = MAXSIZE;
2579     blob.out = space;
2580
2581     code = pioctl(NULL, VIOC_GET_WS_CELL, &blob, 1);
2582
2583     if (code) {
2584         Die(errno, NULL);
2585         return 1;
2586     }
2587
2588     printf("This workstation belongs to cell '%s'\n", space);
2589     return 0;
2590 }
2591
2592 /*
2593 static int
2594 PrimaryCellCmd(struct cmd_syndesc *as, char *arock)
2595 {
2596     fprintf(stderr,"This command is obsolete, as is the concept of a primary token.\n");
2597     return 0;
2598 }
2599 */
2600
2601 static int
2602 MonitorCmd(struct cmd_syndesc *as, char *arock)
2603 {
2604     afs_int32 code;
2605     struct ViceIoctl blob;
2606     struct cmd_item *ti;
2607     afs_int32 hostAddr;
2608     struct hostent *thp;
2609     char *tp;
2610     int setp;
2611     
2612     ti = as->parms[0].items;
2613     setp = 1;
2614     if (ti) {
2615         /* set the host */
2616         if (!strcmp(ti->data, "off")) {
2617             hostAddr = 0xffffffff;
2618         } else {
2619             thp = hostutil_GetHostByName(ti->data);
2620             if (!thp) {
2621                 if (!strcmp(ti->data, "localhost")) {
2622                     fprintf(stderr,"localhost not in host table, assuming 127.0.0.1\n");
2623                     hostAddr = htonl(0x7f000001);
2624                 } else {
2625                     fprintf(stderr,"host %s not found in host table.\n", ti->data);
2626                     return 1;
2627                 }
2628             } else {
2629                 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2630             }
2631         }
2632     } else {
2633         hostAddr = 0;   /* means don't set host */
2634         setp = 0;       /* aren't setting host */
2635     }
2636
2637     /* now do operation */
2638     blob.in_size = sizeof(afs_int32);
2639     blob.out_size = sizeof(afs_int32);
2640     blob.in = (char *) &hostAddr;
2641     blob.out = (char *) &hostAddr;
2642     code = pioctl(0, VIOC_AFS_MARINER_HOST, &blob, 1);
2643     if (code) {
2644         Die(errno, 0);
2645         return 1;
2646     }
2647     if (setp) {
2648         printf("%s: new monitor host set.\n", pn);
2649     } else {
2650         /* now decode old address */
2651         if (hostAddr == 0xffffffff) {
2652             printf("Cache monitoring is currently disabled.\n");
2653         } else {
2654             tp = hostutil_GetNameByINet(hostAddr);
2655             printf("Using host %s for monitor services.\n", tp);
2656         }
2657     }
2658     return 0;
2659 }
2660
2661 static int
2662 SysNameCmd(struct cmd_syndesc *as, char *arock)
2663 {
2664     afs_int32 code;
2665     struct ViceIoctl blob;
2666     struct cmd_item *ti;
2667     char *input = space;
2668     afs_int32 setp = 0;
2669     
2670     ti = as->parms[0].items;
2671     if (ti) {
2672 #ifdef WIN32
2673     if ( !IsAdmin() ) {
2674         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2675         return EACCES;
2676     }
2677 #else /* WIN32 */
2678     if (geteuid()) {
2679         fprintf (stderr,"Permission denied: requires root access.\n");
2680         return EACCES;
2681     }
2682 #endif /* WIN32 */
2683     }
2684
2685     blob.in = space;
2686     blob.out = space;
2687     blob.out_size = MAXSIZE;
2688     blob.in_size = sizeof(afs_int32);
2689     memcpy(input, &setp, sizeof(afs_int32));
2690     input += sizeof(afs_int32);
2691     for (; ti; ti = ti->next) {
2692         setp++;
2693         blob.in_size += strlen(ti->data) + 1;
2694         if (blob.in_size > MAXSIZE) {
2695             fprintf(stderr, "%s: sysname%s too long.\n", pn,
2696                      setp > 1 ? "s" : "");
2697             return 1;
2698         }
2699         strcpy(input, ti->data);
2700         input += strlen(ti->data);
2701         *(input++) = '\0';
2702     }
2703     memcpy(space, &setp, sizeof(afs_int32));
2704     code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
2705     if (code) {
2706         Die(errno, 0);
2707         return 1;
2708     }    
2709     if (setp) {
2710         printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
2711         return 0;
2712     }
2713
2714     input = space;
2715     memcpy(&setp, input, sizeof(afs_int32));
2716     input += sizeof(afs_int32);
2717     if (!setp) {
2718         fprintf(stderr,"No sysname name value was found\n");
2719         return 1;
2720     } 
2721     
2722     printf("Current sysname%s is", setp > 1 ? " list" : "");
2723     for (; setp > 0; --setp ) {
2724         printf(" \'%s\'", input);
2725         input += strlen(input) + 1;
2726     }
2727     printf("\n");
2728     return 0;
2729 }
2730
2731 static char *exported_types[] = {"null", "nfs", ""};
2732 static int ExportAfsCmd(struct cmd_syndesc *as, char *arock)
2733 {
2734     afs_int32 code;
2735     struct ViceIoctl blob;
2736     struct cmd_item *ti;
2737     int export = 0, type = 0, mode = 0, exp = 0, gstat = 0;
2738     int exportcall, pwsync = 0, smounts = 0;
2739     
2740 #ifdef WIN32
2741     if ( !IsAdmin() ) {
2742         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2743         return EACCES;
2744     }
2745 #else /* WIN32 */
2746     if (geteuid()) {
2747         fprintf (stderr,"Permission denied: requires root access.\n");
2748         return EACCES;
2749     }
2750 #endif /* WIN32 */
2751
2752     ti = as->parms[0].items;
2753     if (strcmp(ti->data, "nfs") == 0) 
2754         type = 0x71; /* NFS */
2755     else {
2756         fprintf(stderr,
2757                 "Invalid exporter type, '%s', Only the 'nfs' exporter is currently supported\n", ti->data);
2758         return 1;
2759     }
2760     ti = as->parms[1].items;
2761     if (ti) {
2762         if (strcmp(ti->data, "on") == 0) 
2763             export = 3;
2764         else if (strcmp(ti->data, "off") == 0) 
2765             export = 2;
2766         else {
2767             fprintf(stderr, "Illegal argument %s\n", ti->data);
2768             return 1;
2769         }
2770         exp = 1;
2771     }
2772     if (ti = as->parms[2].items) {      /* -noconvert */
2773         if (strcmp(ti->data, "on") == 0) 
2774             mode = 2;
2775         else if (strcmp(ti->data, "off") == 0) 
2776             mode = 3;
2777         else {
2778             fprintf(stderr, "Illegal argument %s\n", ti->data);
2779             return 1;
2780         }
2781     }
2782     if (ti = as->parms[3].items) {      /* -uidcheck */
2783         if (strcmp(ti->data, "on") == 0) 
2784             pwsync = 3;
2785         else if (strcmp(ti->data, "off") == 0) 
2786             pwsync = 2;
2787         else {
2788             fprintf(stderr, "Illegal argument %s\n", ti->data);
2789             return 1;
2790         }
2791     }
2792     if (ti = as->parms[4].items) {      /* -submounts */
2793         if (strcmp(ti->data, "on") == 0) 
2794             smounts = 3;
2795         else if (strcmp(ti->data, "off") == 0) 
2796             smounts = 2;
2797         else {
2798             fprintf(stderr, "Illegal argument %s\n", ti->data);
2799             return 1;
2800         }
2801     }
2802     exportcall =  (type << 24) | (mode << 6) | (pwsync << 4) | (smounts << 2) | export;
2803     type &= ~0x70;
2804     /* make the call */
2805     blob.in = (char *) &exportcall;
2806     blob.in_size = sizeof(afs_int32);
2807     blob.out = (char *) &exportcall;
2808     blob.out_size = sizeof(afs_int32);
2809     code = pioctl(0, VIOC_EXPORTAFS, &blob, 1);
2810     if (code) {
2811         if (errno == ENODEV) {
2812             fprintf(stderr,
2813                     "Sorry, the %s-exporter type is currently not supported on this AFS client\n", exported_types[type]);
2814         } else {
2815             Die(errno, 0);
2816         }
2817         return 1;
2818     } else {
2819         if (!gstat) {
2820             if (exportcall & 1) {
2821                 printf("'%s' translator is enabled with the following options:\n\tRunning in %s mode\n\tRunning in %s mode\n\t%s\n", 
2822                        exported_types[type], (exportcall & 2 ? "strict unix" : "convert owner mode bits to world/other"),
2823                        (exportcall & 4 ? "strict 'passwd sync'" : "no 'passwd sync'"),
2824                        (exportcall & 8 ? "Allow mounts of /afs/.. subdirs" : "Only mounts to /afs allowed"));
2825             } else {
2826                 printf("'%s' translator is disabled\n", exported_types[type]);
2827             }
2828         }
2829     }
2830     return 0;
2831 }
2832
2833
2834 static int
2835 GetCellCmd(struct cmd_syndesc *as, char *arock)
2836 {
2837     afs_int32 code;
2838     struct ViceIoctl blob;
2839     struct afsconf_cell info;
2840     struct cmd_item *ti;
2841     struct a {
2842         afs_int32 stat;
2843         afs_int32 junk;
2844     } args;
2845     int error = 0;
2846
2847     memset(&args, 0, sizeof(args));      /* avoid Purify UMR error */
2848     for(ti=as->parms[0].items; ti; ti=ti->next) {
2849         /* once per cell */
2850         blob.out_size = sizeof(args);
2851         blob.out = (caddr_t) &args;
2852         code = GetCellName(ti->data, &info);
2853         if (code) {
2854             error = 1;
2855             continue;
2856         }
2857         blob.in_size = 1+strlen(info.name);
2858         blob.in = info.name;
2859         code = pioctl(0, VIOC_GETCELLSTATUS, &blob, 1);
2860         if (code) {
2861             if (errno == ENOENT)
2862                 fprintf(stderr,"%s: the cell named '%s' does not exist\n", pn, info.name);
2863             else
2864                 Die(errno, info.name);
2865             error = 1;
2866             continue;
2867         }
2868         printf("Cell %s status: ", info.name);
2869 #ifdef notdef
2870         if (args.stat & 1) 
2871             printf("primary ");
2872 #endif
2873         if (args.stat & 2) 
2874             printf("no setuid allowed");
2875         else 
2876             printf("setuid allowed");
2877         if (args.stat & 4) 
2878             printf(", using old VLDB");
2879         printf("\n");
2880     }
2881     return error;
2882 }
2883
2884 static int SetCellCmd(struct cmd_syndesc *as, char *arock)
2885 {
2886     afs_int32 code;
2887     struct ViceIoctl blob;
2888     struct afsconf_cell info;
2889     struct cmd_item *ti;
2890     struct a {
2891         afs_int32 stat;
2892         afs_int32 junk;
2893         char cname[64];
2894     } args;
2895     int error = 0;
2896
2897     /* Check arguments. */
2898     if (as->parms[1].items && as->parms[2].items) {
2899         fprintf(stderr, "Cannot specify both -suid and -nosuid.\n");
2900         return 1;
2901     }
2902
2903     /* figure stuff to set */
2904     args.stat = 0;
2905     args.junk = 0;
2906
2907 #ifdef WIN32
2908     if ( !IsAdmin() ) {
2909         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2910         return EACCES;
2911     }
2912 #else /* WIN32 */
2913     if (geteuid()) {
2914         fprintf (stderr,"Permission denied: requires root access.\n");
2915         return EACCES;
2916     }
2917 #endif /* WIN32 */
2918
2919     if (! as->parms[1].items) 
2920         args.stat |= CM_SETCELLFLAG_SUID; /* default to -nosuid */
2921
2922     /* set stat for all listed cells */
2923     for(ti=as->parms[0].items; ti; ti=ti->next) {
2924         /* once per cell */
2925         code = GetCellName(ti->data, &info);
2926         if (code) {
2927             error = 1;
2928             continue;
2929         }
2930         strcpy(args.cname, info.name);
2931         blob.in_size = sizeof(args);
2932         blob.in = (caddr_t) &args;
2933         blob.out_size = 0;
2934         blob.out = (caddr_t) 0;
2935         code = pioctl(0, VIOC_SETCELLSTATUS, &blob, 1);
2936         if (code) {
2937             Die(errno, info.name);      /* XXX added cell name to Die() call */
2938             error = 1;
2939         }
2940     }
2941     return error;
2942 }
2943
2944 #ifdef WIN32
2945 static int
2946 GetCellName(char *cellNamep, struct afsconf_cell *infop)
2947 {
2948     strcpy(infop->name, cellNamep);
2949     return 0;
2950 }
2951
2952 static int
2953 VLDBInit(int noAuthFlag, struct afsconf_cell *infop)
2954 {
2955     return 0;
2956 }
2957 #else /* not WIN32 */
2958 static int
2959 GetCellName(char *cellName, struct afsconf_cell *info)
2960 {
2961     struct afsconf_dir *tdir;
2962     int code;
2963
2964     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_CLIENTNAME);
2965     if (!tdir) {
2966         fprintf(stderr,
2967                 "Could not process files in configuration directory (%s).\n",
2968                  AFSDIR_CLIENT_ETC_CLIENTNAME);
2969         return -1;
2970     }
2971
2972     code = afsconf_GetCellInfo(tdir, cellName, AFSCONF_VLDBSERVICE, info);
2973     if (code) {
2974         fprintf(stderr,"fs: cell %s not in %s/CellServDB\n", cellName, 
2975                 AFSDIR_CLIENT_ETC_CLIENTNAME);
2976         return code;
2977     }
2978
2979     return 0;
2980 }
2981
2982
2983 static int
2984 VLDBInit(int noAuthFlag, struct afsconf_cell *info)
2985 {
2986     afs_int32 code;
2987
2988     code = ugen_ClientInit(noAuthFlag, AFSDIR_CLIENT_ETC_DIRPATH, 
2989                            info->name, 0, &uclient, 
2990                            NULL, pn, rxkad_clear,
2991                            VLDB_MAXSERVERS, AFSCONF_VLDBSERVICE, 50,
2992                            0, 0, USER_SERVICE_ID);
2993     rxInitDone = 1;
2994     return code;
2995 }
2996 #endif /* not WIN32 */
2997
2998 static struct ViceIoctl gblob;
2999 static int debug = 0;
3000 /* 
3001  * here follow some routines in suport of the setserverprefs and
3002  * getserverprefs commands.  They are:
3003  * SetPrefCmd  "top-level" routine
3004  * addServer   adds a server to the list of servers to be poked into the
3005  *             kernel.  Will poke the list into the kernel if it threatens
3006  *             to get too large.
3007  * pokeServers pokes the existing list of servers and ranks into the kernel
3008  * GetPrefCmd  reads the Cache Manager's current list of server ranks
3009  */
3010
3011 #ifdef WIN32
3012 static int 
3013 pokeServers(void)
3014 {
3015     int code;
3016     cm_SSetPref_t *ssp;
3017     code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
3018
3019     ssp = (cm_SSetPref_t *)space;
3020     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3021     gblob.in = space;
3022     return code;
3023 }
3024 #else
3025 /*
3026  * returns -1 if error message printed,
3027  * 0 on success,
3028  * errno value if error and no error message printed
3029  */
3030 static int
3031 pokeServers(void)
3032 {
3033     int code;
3034
3035     code = pioctl(0, VIOC_SETSPREFS, &gblob, 1);
3036     if (code && (errno == EINVAL)) {
3037         struct setspref *ssp;
3038         ssp = (struct setspref *)gblob.in;
3039         if (!(ssp->flags & DBservers)) {
3040             gblob.in = (void *)&(ssp->servers[0]);
3041             gblob.in_size -= ((char *)&(ssp->servers[0])) - (char *)ssp;
3042             code = pioctl(0, VIOC_SETSPREFS33, &gblob, 1);
3043             return code ? errno : 0;
3044         }
3045         fprintf(stderr,
3046                 "This cache manager does not support VL server preferences.\n");
3047         return -1;
3048     }
3049
3050     return code ? errno : 0;
3051 }
3052 #endif /* WIN32 */
3053
3054 #ifdef WIN32
3055 static int
3056 addServer(char *name, unsigned short rank)
3057 {  
3058     int code;
3059     cm_SSetPref_t *ssp;
3060     cm_SPref_t *sp;
3061     struct hostent *thostent;
3062
3063 #ifndef MAXUSHORT
3064 #ifdef MAXSHORT
3065 #define MAXUSHORT ((unsigned short) 2*MAXSHORT+1)  /* assumes two's complement binary system */
3066 #else
3067 #define MAXUSHORT ((unsigned short) ~0)
3068 #endif
3069 #endif
3070
3071     code = 0;
3072     thostent = hostutil_GetHostByName(name);
3073     if (!thostent) {
3074         fprintf (stderr, "%s: couldn't resolve name.\n", name);
3075         return EINVAL;
3076     }
3077
3078     ssp = (cm_SSetPref_t *)(gblob.in);
3079
3080     if (gblob.in_size > MAXINSIZE - sizeof(cm_SPref_t)) {
3081         code = pokeServers();
3082         ssp->num_servers = 0;
3083     }
3084
3085     sp = (cm_SPref_t *)((char*)gblob.in + gblob.in_size);
3086     memcpy (&(sp->host.s_addr), thostent->h_addr, sizeof(afs_uint32));
3087     sp->rank = (rank > MAXUSHORT ? MAXUSHORT : rank);
3088     gblob.in_size += sizeof(cm_SPref_t);
3089     ssp->num_servers++;
3090
3091     if (debug) fprintf(stderr, "adding server %s, rank %d, ip addr 0x%lx\n",name,sp->rank,sp->host.s_addr);
3092
3093     return code;
3094 }
3095 #else
3096 /*
3097  * returns -1 if error message printed,
3098  * 0 on success,
3099  * errno value if error and no error message printed
3100  */
3101 static int
3102 addServer(char *name, afs_int32 rank)
3103 {
3104     int t, code;
3105     struct setspref *ssp;
3106     struct spref *sp;
3107     struct hostent *thostent;
3108     afs_uint32 addr;
3109     int error = 0;
3110
3111 #ifndef MAXUSHORT
3112 #ifdef MAXSHORT
3113 #define MAXUSHORT ((unsigned short) 2*MAXSHORT+1)       /* assumes two's complement binary system */
3114 #else
3115 #define MAXUSHORT ((unsigned short) ~0)
3116 #endif
3117 #endif
3118
3119     thostent = hostutil_GetHostByName(name);
3120     if (!thostent) {
3121         fprintf(stderr, "%s: couldn't resolve name.\n", name);
3122         return -1;
3123     }
3124
3125     ssp = (struct setspref *)(gblob.in);
3126
3127     for (t = 0; thostent->h_addr_list[t]; t++) {
3128         if (gblob.in_size > MAXINSIZE - sizeof(struct spref)) {
3129             code = pokeServers();
3130             if (code)
3131                 error = code;
3132             ssp->num_servers = 0;
3133         }
3134
3135         sp = (struct spref *)(gblob.in + gblob.in_size);
3136         memcpy(&(sp->server.s_addr), thostent->h_addr_list[t],
3137                sizeof(afs_uint32));
3138         sp->rank = (rank > MAXUSHORT ? MAXUSHORT : rank);
3139         gblob.in_size += sizeof(struct spref);
3140         ssp->num_servers++;
3141
3142         if (debug)
3143             fprintf(stderr, "adding server %s, rank %d, ip addr 0x%lx\n",
3144                     name, sp->rank, sp->server.s_addr);
3145     }
3146
3147     return error;
3148 }
3149 #endif /* WIN32 */
3150
3151 #ifdef WIN32
3152 static BOOL IsWindowsNT (void)
3153 {
3154     static BOOL fChecked = FALSE;
3155     static BOOL fIsWinNT = FALSE;
3156
3157     if (!fChecked)
3158     {
3159         OSVERSIONINFO Version;
3160
3161         fChecked = TRUE;
3162
3163         memset (&Version, 0x00, sizeof(Version));
3164         Version.dwOSVersionInfoSize = sizeof(Version);
3165
3166         if (GetVersionEx (&Version))
3167         {
3168             if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT)
3169                 fIsWinNT = TRUE;
3170         }
3171     }
3172     return fIsWinNT;
3173 }
3174 #endif /* WIN32 */
3175
3176 #ifdef WIN32
3177 static int
3178 SetPrefCmd(struct cmd_syndesc *as, char * arock)
3179 {
3180     FILE *infd;
3181     afs_int32 code;
3182     struct cmd_item *ti;
3183     char name[80];
3184     afs_int32 rank;
3185     cm_SSetPref_t *ssp;
3186     
3187     ssp = (cm_SSetPref_t *)space;
3188     ssp->flags = 0;
3189     ssp->num_servers = 0;
3190     gblob.in_size = ((char*)&(ssp->servers[0])) - (char *)ssp;
3191     gblob.in = space;
3192     gblob.out = space;
3193     gblob.out_size = MAXSIZE;
3194
3195     if ( !IsAdmin() ) {
3196         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3197         return EACCES;
3198     }
3199
3200     code = 0;
3201
3202     ti = as->parms[2].items;  /* -file */
3203     if (ti) {
3204         if (debug) fprintf(stderr,"opening file %s\n",ti->data);
3205         if (!(infd = fopen(ti->data,"r" ))) {
3206             code = errno;
3207             Die(errno,ti->data);
3208         }
3209         else
3210             while ( fscanf(infd, "%79s%ld", name, &rank) != EOF) {
3211                 code = addServer (name, (unsigned short) rank);
3212             }
3213     }
3214
3215     ti = as->parms[3].items;  /* -stdin */
3216     if (ti) {
3217         while ( scanf("%79s%ld", name, &rank) != EOF) {
3218             code = addServer (name, (unsigned short) rank);
3219         }
3220     }
3221
3222     for (ti = as->parms[0].items;ti;ti=ti->next) {/*list of servers, ranks */
3223         if (ti) {
3224             if (!ti->next) {
3225                 break;
3226             }
3227             code = addServer (ti->data, (unsigned short) atol(ti->next->data));
3228             if (debug)
3229                 printf("set fs prefs %s %s\n", ti->data, ti->next->data);
3230             ti=ti->next;
3231         }
3232     }
3233     code = pokeServers();
3234     if (debug) 
3235         printf("now working on vlservers, code=%d, errno=%d\n",code,errno);
3236
3237     ssp = (cm_SSetPref_t *)space;
3238     gblob.in_size = ((char*)&(ssp->servers[0])) - (char *)ssp;
3239     gblob.in = space;
3240     ssp->flags = CM_SPREF_VLONLY;
3241     ssp->num_servers = 0;
3242
3243     for (ti = as->parms[1].items;ti;ti=ti->next) { /* list of dbservers, ranks */
3244         if (ti) {
3245             if (!ti->next) {
3246                 break;
3247             }
3248             code = addServer (ti->data, (unsigned short) atol(ti->next->data));
3249             if (debug) 
3250                 printf("set vl prefs %s %s\n", ti->data, ti->next->data);
3251             ti=ti->next;
3252         }
3253     }
3254
3255     if (as->parms[1].items) {
3256         if (debug) 
3257             printf("now poking vlservers\n");
3258         code = pokeServers();
3259     }
3260
3261     if (code) 
3262         Die(errno,0);
3263
3264     return code;
3265 }
3266 #else
3267 static int
3268 SetPrefCmd(struct cmd_syndesc *as, char *arock)
3269 {
3270     FILE *infd;
3271     afs_int32 code;
3272     struct cmd_item *ti;
3273     char name[80];
3274     afs_int32 rank;
3275     struct setspref *ssp;
3276     int error = 0;              /* -1 means error message printed,
3277                                  * >0 means errno value for unprinted message */
3278
3279     ssp = (struct setspref *)space;
3280     ssp->flags = 0;
3281     ssp->num_servers = 0;
3282     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3283     gblob.in = space;
3284     gblob.out = space;
3285     gblob.out_size = MAXSIZE;
3286
3287
3288     if (geteuid()) {
3289         fprintf(stderr, "Permission denied: requires root access.\n");
3290         return 1;
3291     }
3292
3293     ti = as->parms[2].items;    /* -file */
3294     if (ti) {
3295         if (debug)
3296             fprintf(stderr, "opening file %s\n", ti->data);
3297         if (!(infd = fopen(ti->data, "r"))) {
3298             perror(ti->data);
3299             error = -1;
3300         } else {
3301             while (fscanf(infd, "%79s%ld", name, &rank) != EOF) {
3302                 code = addServer(name, (unsigned short)rank);
3303                 if (code)
3304                     error = code;
3305             }
3306         }
3307     }
3308
3309     ti = as->parms[3].items;    /* -stdin */
3310     if (ti) {
3311         while (scanf("%79s%ld", name, &rank) != EOF) {
3312             code = addServer(name, (unsigned short)rank);
3313             if (code)
3314                 error = code;
3315         }
3316     }
3317
3318     for (ti = as->parms[0].items; ti; ti = ti->next) {  /* list of servers, ranks */
3319         if (ti) {
3320             if (!ti->next) {
3321                 break;
3322             }
3323             code = addServer(ti->data, (unsigned short)atol(ti->next->data));
3324             if (code)
3325                 error = code;
3326             if (debug)
3327                 printf("set fs prefs %s %s\n", ti->data, ti->next->data);
3328             ti = ti->next;
3329         }
3330     }
3331     code = pokeServers();
3332     if (code)
3333         error = code;
3334     if (debug)
3335         printf("now working on vlservers, code=%d\n", code);
3336
3337     ssp = (struct setspref *)space;
3338     ssp->flags = DBservers;
3339     ssp->num_servers = 0;
3340     gblob.in_size = ((char *)&(ssp->servers[0])) - (char *)ssp;
3341     gblob.in = space;
3342
3343     for (ti = as->parms[1].items; ti; ti = ti->next) {  /* list of dbservers, ranks */
3344         if (ti) {
3345             if (!ti->next) {
3346                 break;
3347             }
3348             code = addServer(ti->data, (unsigned short)atol(ti->next->data));
3349             if (code)
3350                 error = code;
3351             if (debug)
3352                 printf("set vl prefs %s %s\n", ti->data, ti->next->data);
3353             ti = ti->next;
3354         }
3355     }
3356
3357     if (as->parms[1].items) {
3358         if (debug)
3359             printf("now poking vlservers\n");
3360         code = pokeServers();
3361         if (code)
3362             error = code;
3363     }
3364
3365     if (error > 0)
3366         Die(error, 0);
3367
3368     return error ? 1 : 0;
3369 }
3370 #endif /* WIN32 */
3371
3372 #ifdef WIN32
3373 static int 
3374 GetPrefCmd(struct cmd_syndesc *as, char *arock)
3375 {
3376     afs_int32 code;
3377     struct cmd_item *ti;
3378     char *name, tbuffer[20];
3379     afs_int32 addr;
3380     FILE * outfd;
3381     int resolve;
3382     int vlservers;
3383     struct ViceIoctl blob;
3384     struct cm_SPrefRequest *in;
3385     struct cm_SPrefInfo *out;
3386     int i;
3387     
3388     code = 0;
3389     ti = as->parms[0].items;  /* -file */
3390     if (ti) {
3391         if (debug) fprintf(stderr,"opening file %s\n",ti->data);
3392         if (!(outfd = freopen(ti->data,"w",stdout))) {
3393             Die(errno,ti->data);
3394             return errno;
3395         }
3396     }
3397
3398     ti = as->parms[1].items;  /* -numeric */
3399     resolve = !(ti);
3400     ti = as->parms[2].items;  /* -vlservers */
3401     vlservers = (ti ? CM_SPREF_VLONLY : 0);
3402     /*  ti = as->parms[3].items;   -cell */
3403
3404     in = (struct cm_SPrefRequest *)space;
3405     in->offset = 0;
3406
3407     do {
3408         blob.in_size=sizeof(struct cm_SPrefRequest);
3409         blob.in = (char *)in;
3410         blob.out = space;
3411         blob.out_size = MAXSIZE;
3412
3413         in->num_servers = (MAXSIZE - 2*sizeof(short))/sizeof(struct cm_SPref);
3414         in->flags = vlservers; 
3415
3416         code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
3417         if (code){
3418             perror("getserverprefs pioctl");
3419             Die (errno,0);
3420         }
3421         else {
3422             out = (struct cm_SPrefInfo *) blob.out;
3423
3424             for (i=0;i<out->num_servers;i++) {
3425                 if (resolve) {
3426                     name = hostutil_GetNameByINet(out->servers[i].host.s_addr);
3427                 }
3428                 else {
3429                     addr = ntohl(out->servers[i].host.s_addr);
3430                     sprintf(tbuffer, "%d.%d.%d.%d", (addr>>24) & 0xff, (addr>>16) & 0xff,
3431                              (addr>>8) & 0xff, addr & 0xff);
3432                     name=tbuffer;
3433                 }
3434                 printf ("%-50s %5u\n",name,out->servers[i].rank);      
3435             }
3436
3437             in->offset = out->next_offset;
3438         }
3439     } while (!code && out->next_offset > 0);
3440
3441     return code;
3442 }
3443 #else
3444 static int
3445 GetPrefCmd(struct cmd_syndesc *as, char *arock)
3446 {
3447     afs_int32 code;
3448     struct cmd_item *ti;
3449     char *name, tbuffer[20];
3450     afs_int32 rank, addr;
3451     FILE *outfd;
3452     int resolve;
3453     int vlservers = 0;
3454     struct ViceIoctl blob;
3455     struct sprefrequest *in;
3456     struct sprefinfo *out;
3457     int i;
3458
3459     ti = as->parms[0].items;    /* -file */
3460     if (ti) {
3461         if (debug)
3462             fprintf(stderr, "opening file %s\n", ti->data);
3463         if (!(outfd = freopen(ti->data, "w", stdout))) {
3464             perror(ti->data);
3465             return 1;
3466         }
3467     }
3468
3469     ti = as->parms[1].items;    /* -numeric */
3470     resolve = !(ti);
3471     ti = as->parms[2].items;    /* -vlservers */
3472     vlservers |= (ti ? DBservers : 0);
3473     /*  ti = as->parms[3].items;   -cell */
3474
3475     in = (struct sprefrequest *)space;
3476     in->offset = 0;
3477
3478     do {
3479         blob.in_size = sizeof(struct sprefrequest);
3480         blob.in = (char *)in;
3481         blob.out = space;
3482         blob.out_size = MAXSIZE;
3483
3484         in->num_servers =
3485             (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
3486         in->flags = vlservers;
3487
3488         code = pioctl(0, VIOC_GETSPREFS, &blob, 1);
3489         if (code) {
3490             perror("getserverprefs pioctl");
3491             return 1;
3492         }
3493
3494         out = (struct sprefinfo *)blob.out;
3495
3496         for (i = 0; i < out->num_servers; i++) {
3497             if (resolve) {
3498                 name = hostutil_GetNameByINet(out->servers[i].server.s_addr);
3499             } else {
3500                 addr = ntohl(out->servers[i].server.s_addr);
3501                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
3502                         (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
3503                 name = tbuffer;
3504             }
3505             printf("%-50s %5u\n", name, out->servers[i].rank);
3506         }
3507
3508         in->offset = out->next_offset;
3509     } while (out->next_offset > 0);
3510
3511     return 0;
3512 }
3513 #endif /* WIN32 */
3514
3515 static int
3516 TraceCmd(struct cmd_syndesc *asp, char *arock)
3517 {
3518     long code;
3519     struct ViceIoctl blob;
3520     long inValue;
3521     long outValue;
3522     
3523 #ifdef WIN32
3524     if ( !IsAdmin() ) {
3525         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3526         return EACCES;
3527     }
3528 #else /* WIN32 */
3529         if (geteuid()) {
3530             fprintf (stderr,"Permission denied: requires root access.\n");
3531             return EACCES;
3532         }
3533 #endif /* WIN32 */
3534
3535     if ((asp->parms[0].items && asp->parms[1].items)) {
3536         fprintf(stderr, "fs trace: must use at most one of '-off' or '-on'\n");
3537         return EINVAL;
3538     }
3539         
3540     /* determine if we're turning this tracing on or off */
3541     inValue = 0;
3542     if (asp->parms[0].items)
3543         inValue = 3;            /* enable */
3544     else if (asp->parms[1].items) 
3545         inValue = 2;    /* disable */
3546     if (asp->parms[2].items) 
3547         inValue |= 4;           /* do reset */
3548     if (asp->parms[3].items) 
3549         inValue |= 8;           /* dump */
3550         
3551     blob.in_size = sizeof(long);
3552     blob.in = (char *) &inValue;
3553     blob.out_size = sizeof(long);
3554     blob.out = (char *) &outValue;
3555         
3556     code = pioctl(NULL, VIOC_TRACECTL, &blob, 1);
3557     if (code) {
3558         Die(errno, NULL);
3559         return code;
3560     }
3561
3562     if (outValue) 
3563         printf("AFS tracing enabled.\n");
3564     else 
3565         printf("AFS tracing disabled.\n");
3566
3567     return 0;
3568 }
3569
3570 static void sbusage(void)
3571 {
3572     fprintf(stderr, "example usage: %s storebehind -files *.o -kb 99999 -default 0\n", pn);
3573     fprintf(stderr, "               %s sb 50000 *.[ao] -default 10\n", pn);
3574 }       
3575
3576 /* fs sb -kbytes 9999 -files *.o -default 64 */
3577 static int
3578 StoreBehindCmd(struct cmd_syndesc *as, char *arock)
3579 {
3580     afs_int32 code = 0;
3581     struct ViceIoctl blob;
3582     struct cmd_item *ti;
3583     struct sbstruct tsb, tsb2;
3584     int verbose = 0;
3585     afs_int32 allfiles;
3586     char *t;
3587     int error = 0;
3588
3589 #ifdef WIN32
3590     if ( !IsAdmin() ) {
3591         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");  
3592         return EACCES;
3593     }
3594 #endif /* WIN32 */
3595
3596     tsb.sb_thisfile = -1;
3597     ti = as->parms[0].items;    /* -kbytes */
3598     if (ti) {
3599         if (!as->parms[1].items) {
3600             fprintf(stderr, "%s: you must specify -files with -kbytes.\n",
3601                     pn);
3602             return 1;
3603         }
3604         tsb.sb_thisfile = strtol(ti->data, &t, 10) * 1024;
3605         if ((tsb.sb_thisfile < 0) || (t != ti->data + strlen(ti->data))) {
3606             fprintf(stderr, "%s: %s must be 0 or a positive number.\n", pn,
3607                     ti->data);
3608             return 1;
3609         }
3610     }
3611
3612     allfiles = tsb.sb_default = -1;     /* Don't set allfiles yet */
3613     ti = as->parms[2].items;    /* -allfiles */
3614     if (ti) {
3615         allfiles = strtol(ti->data, &t, 10) * 1024;
3616         if ((allfiles < 0) || (t != ti->data + strlen(ti->data))) {
3617             fprintf(stderr, "%s: %s must be 0 or a positive number.\n", pn,
3618                     ti->data);
3619             return 1;
3620         }
3621     }
3622
3623     /* -verbose or -file only or no options */
3624     if (as->parms[3].items || (as->parms[1].items && !as->parms[0].items)
3625         || (!as->parms[0].items && !as->parms[1].items
3626             && !as->parms[2].items))
3627         verbose = 1;
3628
3629     blob.in = (char *)&tsb;
3630     blob.out = (char *)&tsb2;
3631     blob.in_size = blob.out_size = sizeof(struct sbstruct);
3632     memset(&tsb2, 0, sizeof(tsb2));
3633
3634     /* once per -file */
3635     for (ti = as->parms[1].items; ti; ti = ti->next) {
3636         /* Do this solely to see if the file is there */
3637         code = pioctl(ti->data, VIOCWHEREIS, &blob, 1);
3638         if (code) {
3639             Die(errno, ti->data);
3640             error = 1;
3641             continue;
3642         }
3643
3644         code = pioctl(ti->data, VIOC_STOREBEHIND, &blob, 1);
3645         if (code) {
3646             Die(errno, ti->data);
3647             error = 1;
3648             continue;
3649         }
3650
3651         if (verbose && (blob.out_size == sizeof(tsb2))) {
3652             if (tsb2.sb_thisfile == -1) {
3653                 fprintf(stdout, "Will store %s according to default.\n",
3654                         ti->data);
3655             } else {
3656                 fprintf(stdout,
3657                         "Will store up to %d kbytes of %s asynchronously.\n",
3658                         (tsb2.sb_thisfile / 1024), ti->data);
3659             }
3660         }
3661     }
3662
3663     /* If no files - make at least one pioctl call, or
3664      * set the allfiles default if we need to.
3665      */
3666     if (!as->parms[1].items || (allfiles != -1)) {
3667         tsb.sb_default = allfiles;
3668         code = pioctl(0, VIOC_STOREBEHIND, &blob, 1);
3669         if (code) {
3670             Die(errno, ((allfiles == -1) ? 0 : "-allfiles"));
3671             error = 1;
3672         }
3673     }
3674
3675     /* Having no arguments also reports the default store asynchrony */
3676     if (verbose && (blob.out_size == sizeof(tsb2))) {
3677         fprintf(stdout, "Default store asynchrony is %d kbytes.\n",
3678                 (tsb2.sb_default / 1024));
3679     }
3680
3681     return error;
3682 }
3683
3684 static afs_int32 
3685 SetCryptCmd(struct cmd_syndesc *as, char *arock)
3686 {
3687     afs_int32 code = 0, flag;
3688     struct ViceIoctl blob;
3689     char *tp;
3690  
3691 #ifdef WIN32
3692     if ( !IsAdmin() ) {
3693         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3694         return EACCES;
3695     }
3696 #endif /* WIN32 */
3697
3698     tp = as->parms[0].items->data;
3699     if (strcmp(tp, "on") == 0)
3700       flag = 1;
3701     else if (strcmp(tp, "off") == 0)
3702       flag = 0;
3703     else {
3704       fprintf (stderr, "%s: %s must be \"on\" or \"off\".\n", pn, tp);
3705       return EINVAL;
3706     }
3707
3708     blob.in = (char *) &flag;
3709     blob.in_size = sizeof(flag);
3710     blob.out_size = 0;
3711     code = pioctl(0, VIOC_SETRXKCRYPT, &blob, 1);
3712     if (code)
3713         Die(code, NULL);
3714     return 0;
3715 }
3716
3717 static afs_int32 
3718 GetCryptCmd(struct cmd_syndesc *as, char *arock)
3719 {
3720     afs_int32 code = 0, flag;
3721     struct ViceIoctl blob;
3722     char *tp;
3723  
3724     blob.in = NULL;
3725     blob.in_size = 0;
3726     blob.out_size = sizeof(flag);
3727     blob.out = space;
3728
3729     code = pioctl(0, VIOC_GETRXKCRYPT, &blob, 1);
3730
3731     if (code) 
3732         Die(code, NULL);
3733     else {
3734       tp = space;
3735       memcpy(&flag, tp, sizeof(afs_int32));
3736       printf("Security level is currently ");
3737       if (flag == 1)
3738         printf("crypt (data security).\n");
3739       else
3740         printf("clear.\n");
3741     }
3742     return 0;
3743 }
3744
3745 static int
3746 MemDumpCmd(struct cmd_syndesc *asp, char *arock)
3747 {
3748     long code;
3749     struct ViceIoctl blob;
3750     long inValue = 0;
3751     long outValue;
3752
3753     if ( !IsAdmin() ) {
3754         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3755         return EACCES;
3756     }
3757
3758     if ((asp->parms[0].items && asp->parms[1].items)) {
3759         fprintf(stderr, "%s trace: must use at most one of '-begin' or '-end'\n", pn);
3760         return EINVAL;
3761     }
3762
3763     /* determine if we're turning this tracing on or off */
3764     if (asp->parms[0].items)
3765         inValue = 1;            /* begin */
3766     else if (asp->parms[1].items)
3767         inValue = 0;            /* end */
3768
3769
3770     blob.in_size = sizeof(long);
3771     blob.in = (char *) &inValue;
3772     blob.out_size = sizeof(long);
3773     blob.out = (char *) &outValue;
3774
3775     code = pioctl(NULL, VIOC_TRACEMEMDUMP, &blob, 1);
3776     if (code) {
3777         Die(errno, NULL);
3778         return code;
3779     }
3780
3781     if (outValue) { 
3782         printf("AFS memdump created.\n");
3783         return 0;
3784     } else {
3785         printf("AFS memdump failed.\n");
3786         return -1;
3787     }
3788 }
3789
3790 static int
3791 MiniDumpCmd(struct cmd_syndesc *asp, char *arock)
3792 {
3793     BOOL success = 0;
3794     SERVICE_STATUS status;
3795     SC_HANDLE hManager = NULL;
3796     SC_HANDLE hService = NULL;
3797
3798     if ( !IsAdmin() ) {
3799         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3800         return EACCES;
3801     }
3802
3803     hManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
3804     if (!hManager)
3805         goto failure;
3806
3807     hService = OpenService(hManager, "TransarcAFSDaemon", SERVICE_USER_DEFINED_CONTROL);
3808     if (!hService)
3809         goto failure;
3810
3811     success = ControlService(hService, SERVICE_CONTROL_CUSTOM_DUMP, &status);
3812
3813     if (success) {
3814         CloseServiceHandle(hService);
3815         CloseServiceHandle(hManager);
3816
3817         printf("AFS minidump generated.\n");
3818         return 0;
3819     }
3820
3821   failure: 
3822     if (hService)
3823         CloseServiceHandle(hService);
3824     if (hManager)
3825         CloseServiceHandle(hManager);
3826
3827     printf("AFS minidump failed.\n");
3828     return -1;
3829 }
3830
3831 static int
3832 CSCPolicyCmd(struct cmd_syndesc *asp, char *arock)
3833 {
3834     struct cmd_item *ti;
3835     char *share = NULL;
3836     HKEY hkCSCPolicy;
3837
3838     if ( !IsAdmin() ) {
3839         fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3840         return EACCES;
3841     }
3842
3843     for(ti=asp->parms[0].items; ti;ti=ti->next) {
3844         share = ti->data;
3845         if (share)
3846         {
3847             break;
3848         }
3849     }
3850
3851     if (share)
3852     {
3853         char *policy;
3854
3855         RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
3856                          AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
3857                         0, 
3858                         "AFS", 
3859                         REG_OPTION_NON_VOLATILE,
3860                         KEY_WRITE,
3861                         NULL, 
3862                         &hkCSCPolicy,
3863                         NULL );
3864
3865         if ( hkCSCPolicy == NULL ) {
3866             fprintf (stderr,"Permission denied: requires Administrator access.\n");
3867             return EACCES;
3868         }
3869
3870         if ( !IsAdmin() ) {
3871             fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3872             RegCloseKey(hkCSCPolicy);
3873             return EACCES;
3874         }
3875
3876         policy = "manual";
3877                 
3878         if (asp->parms[1].items)
3879             policy = "manual";
3880         if (asp->parms[2].items)
3881             policy = "programs";
3882         if (asp->parms[3].items)
3883             policy = "documents";
3884         if (asp->parms[4].items)
3885             policy = "disable";
3886                 
3887         RegSetValueEx( hkCSCPolicy, share, 0, REG_SZ, policy, strlen(policy)+1);
3888                 
3889         printf("CSC policy on share \"%s\" changed to \"%s\".\n\n", share, policy);
3890         printf("Close all applications that accessed files on this share or restart AFS Client for the change to take effect.\n"); 
3891     }
3892     else
3893     {
3894         DWORD dwIndex, dwPolicies;
3895         char policyName[256];
3896         DWORD policyNameLen;
3897         char policy[256];
3898         DWORD policyLen;
3899         DWORD dwType;
3900
3901         /* list current csc policies */
3902
3903         RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
3904                         AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
3905                         0, 
3906                         "AFS", 
3907                         REG_OPTION_NON_VOLATILE,
3908                         KEY_READ|KEY_QUERY_VALUE,
3909                         NULL, 
3910                         &hkCSCPolicy,
3911                         NULL );
3912
3913         RegQueryInfoKey( hkCSCPolicy,
3914                          NULL,  /* lpClass */
3915                          NULL,  /* lpcClass */
3916                          NULL,  /* lpReserved */
3917                          NULL,  /* lpcSubKeys */
3918                          NULL,  /* lpcMaxSubKeyLen */
3919                          NULL,  /* lpcMaxClassLen */
3920                          &dwPolicies, /* lpcValues */
3921                          NULL,  /* lpcMaxValueNameLen */
3922                          NULL,  /* lpcMaxValueLen */
3923                          NULL,  /* lpcbSecurityDescriptor */
3924                          NULL   /* lpftLastWriteTime */
3925                          );
3926                 
3927         printf("Current CSC policies:\n");
3928         for ( dwIndex = 0; dwIndex < dwPolicies; dwIndex ++ ) {
3929
3930             policyNameLen = sizeof(policyName);
3931             policyLen = sizeof(policy);
3932             RegEnumValue( hkCSCPolicy, dwIndex, policyName, &policyNameLen, NULL,
3933                           &dwType, policy, &policyLen);
3934
3935             printf("  %s = %s\n", policyName, policy);
3936         }
3937     }
3938
3939     RegCloseKey(hkCSCPolicy);
3940     return (0);
3941 }
3942
3943 #ifndef WIN32
3944 /* get clients interface addresses */
3945 static int
3946 GetClientAddrsCmd(struct cmd_syndesc *as, char *arock)
3947 {
3948     afs_int32 code;
3949     struct cmd_item *ti;
3950     char *name;
3951     struct ViceIoctl blob;
3952     struct sprefrequest *in;
3953     struct sprefinfo *out;
3954
3955     in = (struct sprefrequest *)space;
3956     in->offset = 0;
3957
3958     do {
3959         blob.in_size = sizeof(struct sprefrequest);
3960         blob.in = (char *)in;
3961         blob.out = space;
3962         blob.out_size = MAXSIZE;
3963
3964         in->num_servers =
3965             (MAXSIZE - 2 * sizeof(short)) / sizeof(struct spref);
3966         /* returns addr in network byte order */
3967         code = pioctl(0, VIOC_GETCPREFS, &blob, 1);
3968         if (code) {
3969             perror("getClientInterfaceAddr pioctl");
3970             return 1;
3971         }
3972
3973         {
3974             int i;
3975             out = (struct sprefinfo *)blob.out;
3976             for (i = 0; i < out->num_servers; i++) {
3977                 afs_int32 addr;
3978                 char tbuffer[32];
3979                 addr = ntohl(out->servers[i].server.s_addr);
3980                 sprintf(tbuffer, "%d.%d.%d.%d", (addr >> 24) & 0xff,
3981                         (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
3982                 printf("%-50s\n", tbuffer);
3983             }
3984             in->offset = out->next_offset;
3985         }
3986     } while (out->next_offset > 0);
3987
3988     return 0;
3989 }
3990
3991 static int
3992 SetClientAddrsCmd(struct cmd_syndesc *as, char *arock)
3993 {
3994     afs_int32 code, addr;
3995     struct cmd_item *ti;
3996     char name[80];
3997     struct ViceIoctl blob;
3998     struct setspref *ssp;
3999     int sizeUsed = 0, i, flag;
4000     afs_int32 existingAddr[1024];       /* existing addresses on this host */
4001     int existNu;
4002     int error = 0;
4003
4004     ssp = (struct setspref *)space;
4005     ssp->num_servers = 0;
4006     blob.in = space;
4007     blob.out = space;
4008     blob.out_size = MAXSIZE;
4009
4010     if (geteuid()) {
4011         fprintf(stderr, "Permission denied: requires root access.\n");
4012         return 1;
4013     }
4014
4015     /* extract all existing interface addresses */
4016     existNu = rx_getAllAddr(existingAddr, 1024);
4017     if (existNu < 0)
4018         return 1;
4019
4020     sizeUsed = sizeof(struct setspref); /* space used in ioctl buffer */
4021     for (ti = as->parms[0].items; ti; ti = ti->next) {
4022         if (sizeUsed >= sizeof(space)) {
4023             fprintf(stderr, "No more space\n");
4024             return 1;
4025         }
4026         addr = extractAddr(ti->data, 20);       /* network order */
4027         if ((addr == AFS_IPINVALID) || (addr == AFS_IPINVALIDIGNORE)) {
4028             fprintf(stderr, "Error in specifying address: %s..ignoring\n",
4029                     ti->data);
4030             error = 1;
4031             continue;
4032         }
4033         /* see if it is an address that really exists */
4034         for (flag = 0, i = 0; i < existNu; i++)
4035             if (existingAddr[i] == addr) {
4036                 flag = 1;
4037                 break;
4038             }
4039         if (!flag) {            /* this is an nonexistent address */
4040             fprintf(stderr, "Nonexistent address: 0x%08x..ignoring\n", addr);
4041             error = 1;
4042             continue;
4043         }
4044         /* copy all specified addr into ioctl buffer */
4045         (ssp->servers[ssp->num_servers]).server.s_addr = addr;
4046         printf("Adding 0x%08x\n", addr);
4047         ssp->num_servers++;
4048         sizeUsed += sizeof(struct spref);
4049     }
4050     if (ssp->num_servers < 1) {
4051         fprintf(stderr, "No addresses specified\n");
4052         return 1;
4053     }
4054     blob.in_size = sizeUsed - sizeof(struct spref);
4055
4056     code = pioctl(0, VIOC_SETCPREFS, &blob, 1); /* network order */
4057     if (code) {
4058         Die(errno, 0);
4059         error = 1;
4060     }
4061
4062     return error;
4063 }
4064
4065 static int
4066 FlushMountCmd(struct cmd_syndesc *as, char *arock)
4067 {
4068     afs_int32 code;
4069     struct ViceIoctl blob;
4070     struct cmd_item *ti;
4071     char orig_name[1024];       /*Original name, may be modified */
4072     char true_name[1024];       /*``True'' dirname (e.g., symlink target) */
4073     char parent_dir[1024];      /*Parent directory of true name */
4074     char *last_component;       /*Last component of true name */
4075     struct stat statbuff;       /*Buffer for status info */
4076     int link_chars_read;        /*Num chars read in readlink() */
4077     int thru_symlink;           /*Did we get to a mount point via a symlink? */
4078     int error = 0;
4079
4080     for (ti = as->parms[0].items; ti; ti = ti->next) {
4081         /* once per file */
4082         thru_symlink = 0;
4083         sprintf(orig_name, "%s%s", (ti->data[0] == '/') ? "" : "./",
4084                 ti->data);
4085
4086         if (lstat(orig_name, &statbuff) < 0) {
4087             /* if lstat fails, we should still try the pioctl, since it
4088              * may work (for example, lstat will fail, but pioctl will
4089              * work if the volume of offline (returning ENODEV). */
4090             statbuff.st_mode = S_IFDIR; /* lie like pros */
4091         }
4092
4093         /*
4094          * The lstat succeeded.  If the given file is a symlink, substitute
4095          * the file name with the link name.
4096          */
4097         if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
4098             thru_symlink = 1;
4099             /*
4100              * Read name of resolved file.
4101              */
4102             link_chars_read = readlink(orig_name, true_name, 1024);
4103             if (link_chars_read <= 0) {
4104                 fprintf(stderr,
4105                         "%s: Can't read target name for '%s' symbolic link!\n",
4106                         pn, orig_name);
4107                 error = 1;
4108                 continue;
4109             }
4110
4111             /*
4112              * Add a trailing null to what was read, bump the length.
4113              */
4114             true_name[link_chars_read++] = 0;
4115
4116             /*
4117              * If the symlink is an absolute pathname, we're fine.  Otherwise, we
4118              * have to create a full pathname using the original name and the
4119              * relative symlink name.  Find the rightmost slash in the original
4120              * name (we know there is one) and splice in the symlink value.
4121              */
4122             if (true_name[0] != '/') {
4123                 last_component = (char *)strrchr(orig_name, '/');
4124                 strcpy(++last_component, true_name);
4125                 strcpy(true_name, orig_name);
4126             }
4127         } else
4128             strcpy(true_name, orig_name);
4129
4130         /*
4131          * Find rightmost slash, if any.
4132          */
4133         last_component = (char *)strrchr(true_name, '/');
4134         if (last_component) {
4135             /*
4136              * Found it.  Designate everything before it as the parent directory,
4137              * everything after it as the final component.
4138              */
4139             strncpy(parent_dir, true_name, last_component - true_name);
4140             parent_dir[last_component - true_name] = 0;
4141             last_component++;   /*Skip the slash */
4142         } else {
4143             /*
4144              * No slash appears in the given file name.  Set parent_dir to the current
4145              * directory, and the last component as the given name.
4146              */
4147             strcpy(parent_dir, ".");
4148             last_component = true_name;
4149         }
4150
4151         if (strcmp(last_component, ".") == 0
4152             || strcmp(last_component, "..") == 0) {
4153             fprintf(stderr,
4154                     "%s: you may not use '.' or '..' as the last component\n",
4155                     pn);
4156             fprintf(stderr, "%s: of a name in the 'fs flushmount' command.\n",
4157                     pn);
4158             error = 1;
4159             continue;
4160         }
4161
4162         blob.in = last_component;
4163         blob.in_size = strlen(last_component) + 1;
4164         blob.out_size = 0;
4165         memset(space, 0, MAXSIZE);
4166
4167         code = pioctl(parent_dir, VIOC_AFS_FLUSHMOUNT, &blob, 1);
4168
4169         if (code != 0) {
4170             if (errno == EINVAL) {
4171                 fprintf(stderr, "'%s' is not a mount point.\n", ti->data);
4172             } else {
4173                 Die(errno, (ti->data ? ti->data : parent_dir));
4174             }
4175             error = 1;
4176         }
4177     }
4178     return error;
4179 }
4180
4181 static int
4182 RxStatProcCmd(struct cmd_syndesc *as, char *arock)
4183 {
4184     afs_int32 code;
4185     afs_int32 flags = 0;
4186     struct ViceIoctl blob;
4187     struct cmd_item *ti;
4188
4189     if (as->parms[0].items) {   /* -enable */
4190         flags |= AFSCALL_RXSTATS_ENABLE;
4191     }
4192     if (as->parms[1].items) {   /* -disable */
4193         flags |= AFSCALL_RXSTATS_DISABLE;
4194     }
4195     if (as->parms[2].items) {   /* -clear */
4196         flags |= AFSCALL_RXSTATS_CLEAR;
4197     }
4198     if (flags == 0) {
4199         fprintf(stderr, "You must specify at least one argument\n");
4200         return 1;
4201     }
4202
4203     blob.in = (char *)&flags;
4204     blob.in_size = sizeof(afs_int32);
4205     blob.out_size = 0;
4206
4207     code = pioctl(NULL, VIOC_RXSTAT_PROC, &blob, 1);
4208     if (code != 0) {
4209         Die(errno, NULL);
4210         return 1;
4211     }
4212
4213     return 0;
4214 }
4215
4216 static int
4217 RxStatPeerCmd(struct cmd_syndesc *as, char *arock)
4218 {
4219     afs_int32 code;
4220     afs_int32 flags = 0;
4221     struct ViceIoctl blob;
4222     struct cmd_item *ti;
4223
4224     if (as->parms[0].items) {   /* -enable */
4225         flags |= AFSCALL_RXSTATS_ENABLE;
4226     }
4227     if (as->parms[1].items) {   /* -disable */
4228         flags |= AFSCALL_RXSTATS_DISABLE;
4229     }
4230     if (as->parms[2].items) {   /* -clear */
4231         flags |= AFSCALL_RXSTATS_CLEAR;
4232     }
4233     if (flags == 0) {
4234         fprintf(stderr, "You must specify at least one argument\n");
4235         return 1;
4236     }
4237
4238     blob.in = (char *)&flags;
4239     blob.in_size = sizeof(afs_int32);
4240     blob.out_size = 0;
4241
4242     code = pioctl(NULL, VIOC_RXSTAT_PEER, &blob, 1);
4243     if (code != 0) {
4244         Die(errno, NULL);
4245         return 1;
4246     }
4247
4248     return 0;
4249 }
4250 #endif /* WIN32 */
4251
4252 #ifndef WIN32
4253 #include "AFS_component_version_number.c"
4254 #endif
4255
4256 main(int argc, char **argv)
4257 {
4258     afs_int32 code;
4259     struct cmd_syndesc *ts;
4260
4261 #ifdef  AFS_AIX32_ENV
4262     /*
4263      * The following signal action for AIX is necessary so that in case of a 
4264      * crash (i.e. core is generated) we can include the user's data section 
4265      * in the core dump. Unfortunately, by default, only a partial core is
4266      * generated which, in many cases, isn't too useful.
4267      */
4268     struct sigaction nsa;
4269     
4270     sigemptyset(&nsa.sa_mask);
4271     nsa.sa_handler = SIG_DFL;
4272     nsa.sa_flags = SA_FULLDUMP;
4273     sigaction(SIGSEGV, &nsa, NULL);
4274 #endif
4275
4276 #ifdef WIN32
4277     WSADATA WSAjunk;
4278     WSAStartup(0x0101, &WSAjunk);
4279 #endif /* WIN32 */
4280
4281     /* try to find volume location information */
4282     osi_Init();
4283
4284 #ifndef WIN32
4285     ts = cmd_CreateSyntax("getclientaddrs", GetClientAddrsCmd, 0,
4286                           "get client network interface addresses");
4287     cmd_CreateAlias(ts, "gc");
4288
4289     ts = cmd_CreateSyntax("setclientaddrs", SetClientAddrsCmd, 0,
4290                           "set client network interface addresses");
4291     cmd_AddParm(ts, "-address", CMD_LIST, CMD_OPTIONAL | CMD_EXPANDS,
4292                 "client network interfaces");
4293     cmd_CreateAlias(ts, "sc");
4294 #endif /* WIN32 */
4295
4296     ts = cmd_CreateSyntax("setserverprefs", SetPrefCmd, 0, "set server ranks");
4297     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL|CMD_EXPANDS, "fileserver names and ranks");
4298     cmd_AddParm(ts, "-vlservers", CMD_LIST, CMD_OPTIONAL|CMD_EXPANDS, "VL server names and ranks");
4299     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "input from named file");
4300     cmd_AddParm(ts, "-stdin", CMD_FLAG, CMD_OPTIONAL, "input from stdin");
4301     cmd_CreateAlias(ts, "sp");
4302
4303     ts = cmd_CreateSyntax("getserverprefs", GetPrefCmd, 0, "get server ranks");
4304     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "output to named file");
4305     cmd_AddParm(ts, "-numeric", CMD_FLAG, CMD_OPTIONAL, "addresses only");
4306     cmd_AddParm(ts, "-vlservers", CMD_FLAG, CMD_OPTIONAL, "VL servers");
4307     /* cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */
4308     cmd_CreateAlias(ts, "gp");
4309
4310     ts = cmd_CreateSyntax("setacl", SetACLCmd, 0, "set access control list");
4311     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
4312     cmd_AddParm(ts, "-acl", CMD_LIST, 0, "access list entries");
4313     cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, "clear access list");
4314     cmd_AddParm(ts, "-negative", CMD_FLAG, CMD_OPTIONAL, "apply to negative rights");
4315     parm_setacl_id = ts->nParms;
4316     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl (DFS only)");
4317     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl (DFS only)");
4318     cmd_CreateAlias(ts, "sa");
4319     
4320     ts = cmd_CreateSyntax("listacl", ListACLCmd, 0, "list access control list");
4321     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4322     parm_listacl_id = ts->nParms;
4323     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl");
4324     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl");
4325     cmd_CreateAlias(ts, "la");
4326     
4327     ts = cmd_CreateSyntax("cleanacl", CleanACLCmd, 0, "clean up access control list");
4328     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4329     
4330     ts = cmd_CreateSyntax("copyacl", CopyACLCmd, 0, "copy access control list");
4331     cmd_AddParm(ts, "-fromdir", CMD_SINGLE, 0, "source directory (or DFS file)");
4332     cmd_AddParm(ts, "-todir", CMD_LIST, 0, "destination directory (or DFS file)");
4333     cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, "first clear dest access list");
4334     parm_copyacl_id = ts->nParms;
4335     cmd_AddParm(ts, "-id", CMD_FLAG, CMD_OPTIONAL, "initial directory acl");
4336     cmd_AddParm(ts, "-if", CMD_FLAG, CMD_OPTIONAL, "initial file acl");
4337     
4338     cmd_CreateAlias(ts, "ca");
4339
4340     ts = cmd_CreateSyntax("flush", FlushCmd, 0, "flush file from cache");
4341     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4342     
4343 #ifndef WIN32
4344     ts = cmd_CreateSyntax("flushmount", FlushMountCmd, 0,
4345                            "flush mount symlink from cache");
4346     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4347 #endif
4348
4349     ts = cmd_CreateSyntax("setvol", SetVolCmd, 0, "set volume status");
4350     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4351     cmd_AddParm(ts, "-max", CMD_SINGLE, CMD_OPTIONAL, "disk space quota in 1K units");
4352 #ifdef notdef
4353     cmd_AddParm(ts, "-min", CMD_SINGLE, CMD_OPTIONAL, "disk space guaranteed");
4354 #endif
4355     cmd_AddParm(ts, "-motd", CMD_SINGLE, CMD_OPTIONAL, "message of the day");
4356     cmd_AddParm(ts, "-offlinemsg", CMD_SINGLE, CMD_OPTIONAL, "offline message");
4357     cmd_CreateAlias(ts, "sv");
4358     
4359     ts = cmd_CreateSyntax("messages", MessagesCmd, 0, "control Cache Manager messages");
4360     cmd_AddParm(ts, "-show", CMD_SINGLE, CMD_OPTIONAL, "[user|console|all|none]");
4361
4362     ts = cmd_CreateSyntax("examine", ExamineCmd, 0, "display file/volume status");
4363     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4364     cmd_CreateAlias(ts, "lv");
4365     cmd_CreateAlias(ts, "listvol");
4366     
4367     ts = cmd_CreateSyntax("listquota", ListQuotaCmd, 0, "list volume quota");
4368     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4369     cmd_CreateAlias(ts, "lq");
4370     
4371     ts = cmd_CreateSyntax("diskfree", DiskFreeCmd, 0, "show server disk space usage");
4372     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4373     cmd_CreateAlias(ts, "df");
4374     
4375     ts = cmd_CreateSyntax("quota", QuotaCmd, 0, "show volume quota usage");
4376     cmd_AddParm(ts, "-path", CMD_LIST, CMD_OPTIONAL, "dir/file path");
4377     
4378     ts = cmd_CreateSyntax("lsmount", ListMountCmd, 0, "list mount point");    
4379     cmd_AddParm(ts, "-dir", CMD_LIST, 0, "directory");
4380     
4381     ts = cmd_CreateSyntax("mkmount", MakeMountCmd, 0, "make mount point");
4382     cmd_AddParm(ts, "-dir", CMD_SINGLE, 0, "directory");
4383     cmd_AddParm(ts, "-vol", CMD_SINGLE, 0, "volume name");
4384     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
4385     cmd_AddParm(ts, "-rw", CMD_FLAG, CMD_OPTIONAL, "force r/w volume");
4386     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL, "don't check name with VLDB");
4387