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