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