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