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