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