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