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