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