2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
15 #include <afs/com_err.h>
28 #include <afs/afs_assert.h>
29 #include <rx/rx_globals.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>
45 #include "parsemode.h"
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
53 static char space[AFS_PIOCTL_MAXSIZE];
54 static char tspace[1024];
56 static struct ubik_client *uclient;
58 /* some forward references */
59 static void ZapList (struct AclEntry *alist);
61 static int PruneList (struct AclEntry **ae, int dfs);
63 static int CleanAcl(struct Acl *aa, char *fname);
65 static int SetVolCmd(struct cmd_syndesc *as, void *arock);
67 static int GetCellName(char *cellNamep, struct afsconf_cell *infop);
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);
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);
80 static char pn[] = "fs";
81 static int rxInitDone = 0;
84 * Character to use between name and rights in printed representation for
87 #define DFS_SEPARATOR ' '
89 typedef char sec_rgy_name_t[1025]; /* A DCE definition */
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 */
98 struct AclEntry *pluslist;
99 struct AclEntry *minuslist;
103 struct AclEntry *next;
109 ZapAcl (struct Acl *acl)
114 ZapList(acl->pluslist);
115 ZapList(acl->minuslist);
120 * Mods for the AFS/DFS protocol translator.
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.
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
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)
147 * Offset of -id switch in command structure for various commands.
148 * The -if switch is the next switch always.
150 static int parm_setacl_id, parm_copyacl_id, parm_listacl_id;
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.
156 /* int id; Offset of -id switch; -if is next switch */
158 getidf(struct cmd_syndesc *as, int id)
162 if (as->parms[id].items) {
165 if (as->parms[id + 1].items) {
170 "%s: you may specify either -id or -if, but not both switches\n",
178 PRights(afs_int32 arights, int dfs)
181 if (arights & PRSFS_READ)
183 if (arights & PRSFS_LOOKUP)
185 if (arights & PRSFS_INSERT)
187 if (arights & PRSFS_DELETE)
189 if (arights & PRSFS_WRITE)
191 if (arights & PRSFS_LOCK)
193 if (arights & PRSFS_ADMINISTER)
195 if (arights & PRSFS_USR0)
197 if (arights & PRSFS_USR1)
199 if (arights & PRSFS_USR2)
201 if (arights & PRSFS_USR3)
203 if (arights & PRSFS_USR4)
205 if (arights & PRSFS_USR5)
207 if (arights & PRSFS_USR6)
209 if (arights & PRSFS_USR7)
212 if (arights & DFS_READ)
216 if (arights & DFS_WRITE)
220 if (arights & DFS_EXECUTE)
224 if (arights & DFS_CONTROL)
228 if (arights & DFS_INSERT)
232 if (arights & DFS_DELETE)
236 if (arights & (DFS_USRALL))
238 if (arights & DFS_USR0)
240 if (arights & DFS_USR1)
242 if (arights & DFS_USR2)
244 if (arights & DFS_USR3)
246 if (arights & DFS_USR4)
248 if (arights & DFS_USR5)
250 if (arights & DFS_USR6)
252 if (arights & DFS_USR7)
258 /* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */
262 struct ViceIoctl blob;
263 cm_ioctlQueryOptions_t options;
267 memset(&options, 0, sizeof(options));
268 options.size = sizeof(options);
269 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
271 blob.in_size = options.size; /* no variable length data */
273 blob.out_size = sizeof(cm_fid_t);
274 blob.out = (char *) &fid;
276 code = pioctl_utf8(apath, VIOCGETFID, &blob, 1);
278 if ((errno == EINVAL) || (errno == ENOENT))
285 IsFreelanceRoot(char *apath)
287 struct ViceIoctl blob;
291 blob.out_size = AFS_PIOCTL_MAXSIZE;
294 code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
296 return !cm_strnicmp_utf8N("Freelance.Local.Root",space, blob.out_size);
298 return 1; /* assume it is because it is more restrictive that way */
301 /* return a static pointer to a buffer */
306 if( FAILED(StringCbCopy(tspace, sizeof(tspace), apath))) {
307 fprintf (stderr, "tspace - not enough space");
310 tp = strrchr(tspace, '\\');
312 if (tp - tspace > 2 &&
315 *(tp+1) = 0; /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
320 fs_ExtractDriveLetter(apath, tspace);
321 if( FAILED(StringCbCat(tspace, sizeof(tspace), "."))) {
322 fprintf (stderr, "tspace - not enough space");
329 /* added relative add resp. delete */
330 /* (so old add really means to set) */
331 enum rtype { add, destroy, deny, reladd, reldel };
334 Convert(char *arights, int dfs, enum rtype *rtypep)
340 *rtypep = add; /* add rights, by default */
342 /* analyze last character of string */
343 tcp = arights + strlen(arights);
344 if ( tcp-- > arights ) { /* assure non-empty string */
346 *rtypep = reladd; /* '+' indicates more rights */
347 else if ( *tcp == '-' )
348 *rtypep = reldel; /* '-' indicates less rights */
349 else if ( *tcp == '=' )
350 *rtypep = add; /* '=' also allows old behaviour */
352 tcp++; /* back to original null byte */
353 *tcp = '\0'; /* do not disturb old strcmp-s */
357 if (!strcmp(arights, "null")) {
361 if (!strcmp(arights,"read"))
362 return DFS_READ | DFS_EXECUTE;
363 if (!strcmp(arights, "write"))
364 return DFS_READ | DFS_EXECUTE | DFS_INSERT | DFS_DELETE |
366 if (!strcmp(arights, "all"))
367 return DFS_READ | DFS_EXECUTE | DFS_INSERT | DFS_DELETE |
368 DFS_WRITE | DFS_CONTROL;
370 if (!strcmp(arights,"read"))
371 return PRSFS_READ | PRSFS_LOOKUP;
372 if (!strcmp(arights, "write"))
373 return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
374 PRSFS_WRITE | PRSFS_LOCK;
375 if (!strcmp(arights, "mail"))
376 return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
377 if (!strcmp(arights, "all"))
378 return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
379 PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
381 if (!strcmp(arights, "none")) {
382 *rtypep = destroy; /* Remove entire entry */
387 while ((tc = *tcp++)) {
420 fprintf(stderr, "%s: illegal DFS rights character '%c'.\n",
428 mode |= PRSFS_LOOKUP;
430 mode |= PRSFS_INSERT;
432 mode |= PRSFS_DELETE;
438 mode |= PRSFS_ADMINISTER;
456 fprintf(stderr, "%s: illegal rights character '%c'.\n", pn,
465 static struct AclEntry *
466 FindList (struct AclEntry *alist, char *aname)
469 if (!strcasecmp(alist->name, aname))
476 /* if no parm specified in a particular slot, set parm to be "." instead */
478 SetDotDefault(struct cmd_item **aitemp)
484 return; /* already has value */
485 /* otherwise, allocate an item representing "." */
486 ti = (struct cmd_item *) malloc(sizeof(struct cmd_item));
488 ti->next = (struct cmd_item *) 0;
489 ti->data = (char *) malloc(len_data);
491 if( FAILED(StringCbCopy(ti->data, len_data, "."))) {
492 fprintf (stderr, "data - not enough space");
499 ChangeList (struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights,
502 struct AclEntry *tlist;
503 tlist = (plus ? al->pluslist : al->minuslist);
504 tlist = FindList (tlist, aname);
506 /* Found the item already in the list. */
507 /* modify rights in case of reladd */
508 /* and reladd only, use standard - */
509 /* add, ie. set - otherwise */
510 if ( artypep == NULL )
511 tlist->rights = arights;
512 else if ( *artypep == reladd )
513 tlist->rights |= arights;
514 else if ( *artypep == reldel )
515 tlist->rights &= ~arights;
517 tlist->rights = arights;
520 al->nplus -= PruneList(&al->pluslist, al->dfs);
522 al->nminus -= PruneList(&al->minuslist, al->dfs);
525 if ( artypep != NULL && *artypep == reldel )
526 /* can't reduce non-existing rights */
529 /* Otherwise we make a new item and plug in the new data. */
530 tlist = (struct AclEntry *) malloc(sizeof (struct AclEntry));
532 if( FAILED(StringCbCopy(tlist->name, sizeof(tlist->name), aname))) {
533 fprintf (stderr, "name - not enough space");
536 tlist->rights = arights;
538 tlist->next = al->pluslist;
539 al->pluslist = tlist;
541 if (arights == 0 || arights == -1)
542 al->nplus -= PruneList(&al->pluslist, al->dfs);
544 tlist->next = al->minuslist;
545 al->minuslist = tlist;
548 al->nminus -= PruneList(&al->minuslist, al->dfs);
553 ZapList (struct AclEntry *alist)
555 struct AclEntry *tp, *np;
556 for (tp = alist; tp; tp = np) {
563 PruneList (struct AclEntry **ae, int dfs)
565 struct AclEntry **lp;
566 struct AclEntry *te, *ne;
570 for(te = *ae;te;te=ne) {
571 if ((!dfs && te->rights == 0) || te->rights == -1) {
585 SkipLine (char *astr)
594 * Create an empty acl, taking into account whether the acl pointed
595 * to by astr is an AFS or DFS acl. Only parse this minimally, so we
596 * can recover from problems caused by bogus ACL's (in that case, always
597 * assume that the acl is AFS: for DFS, the user can always resort to
598 * acl_edit, but for AFS there may be no other way out).
606 tp = (struct Acl *)malloc(sizeof (struct Acl));
608 tp->nplus = tp->nminus = 0;
609 tp->pluslist = tp->minuslist = 0;
612 if (astr == NULL || sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell) <= 0) {
617 if (astr == NULL || sscanf_s(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell, sizeof(tp->cell)) <= 0) {
626 ParseAcl (char *astr, int astr_size)
628 int nplus, nminus, i, trights, ret;
631 struct AclEntry *first, *next, *last, *tl;
635 if( FAILED(StringCbLength(astr, astr_size, &len))) {
636 fprintf (stderr, "StringCbLength failure on astr");
639 if (astr == NULL || len == 0)
643 ret = sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
645 ret = sscanf_s(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell, sizeof(ta->cell));
651 astr = SkipLine(astr);
653 ret = sscanf(astr, "%d", &ta->nminus);
655 ret = sscanf_s(astr, "%d", &ta->nminus);
661 astr = SkipLine(astr);
668 for(i=0;i<nplus;i++) {
670 ret = sscanf(astr, "%100s %d", tname, &trights);
672 ret = sscanf_s(astr, "%100s %d", tname, sizeof(tname), &trights);
676 astr = SkipLine(astr);
677 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
682 if( FAILED(StringCbCopy(tl->name, sizeof(tl->name), tname))) {
683 fprintf (stderr, "name - not enough space");
686 tl->rights = trights;
692 ta->pluslist = first;
696 for(i=0;i<nminus;i++) {
698 ret = sscanf(astr, "%100s %d", tname, &trights);
700 ret = sscanf_s(astr, "%100s %d", tname, sizeof(tname), &trights);
704 astr = SkipLine(astr);
705 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
710 if( FAILED(StringCbCopy(tl->name, sizeof(tl->name), tname))) {
711 fprintf (stderr, "name - not enough space");
714 tl->rights = trights;
720 ta->minuslist = first;
725 for (;first; first = next) {
729 first = ta->pluslist;
732 for (;first; first = next) {
741 PrintStatus(VolumeStatus *status, char *name, char *motd, char *offmsg)
743 printf("Volume status for vid = %u named %s is\n",status->Vid, name);
745 printf("Current offline message is %s\n",offmsg);
747 printf("Current message of the day is %s\n",motd);
748 printf("Current disk quota is ");
749 if (status->MaxQuota != 0)
750 printf("%d\n", status->MaxQuota);
752 printf("unlimited\n");
753 printf("Current blocks used are %d\n",status->BlocksInUse);
754 printf("The partition has %d blocks available out of %d\n",
755 status->PartBlocksAvail, status->PartMaxBlocks);
760 QuickPrintStatus(VolumeStatus *status, char *name)
762 double QuotaUsed =0.0;
763 double PartUsed =0.0;
765 printf("%-25.25s",name);
767 if (status->MaxQuota != 0) {
768 printf(" %10d %10d", status->MaxQuota, status->BlocksInUse);
769 QuotaUsed = ((((double)status->BlocksInUse)/status->MaxQuota) * 100.0);
771 printf(" no limit %10d", status->BlocksInUse);
773 if (QuotaUsed > 90.0){
774 printf(" %5.0f%%<<", QuotaUsed);
777 printf(" %5.0f%% ", QuotaUsed);
778 PartUsed = (100.0 - ((((double)status->PartBlocksAvail)/status->PartMaxBlocks) * 100.0));
779 if (PartUsed > 97.0){
780 printf(" %9.0f%%<<", PartUsed);
783 printf(" %9.0f%% ", PartUsed);
785 printf(" <<WARNING\n");
792 QuickPrintSpace(VolumeStatus *status, char *name)
794 double PartUsed =0.0;
796 printf("%-25.25s",name);
798 printf("%10d%10d%10d", status->PartMaxBlocks, status->PartMaxBlocks - status->PartBlocksAvail, status->PartBlocksAvail);
800 PartUsed = (100.0 - ((((double)status->PartBlocksAvail)/status->PartMaxBlocks) * 100.0));
801 if (PartUsed > 90.0){
802 printf(" %4.0f%%<<", PartUsed);
805 printf(" %4.0f%% ", PartUsed);
807 printf(" <<WARNING\n");
814 AclToString(struct Acl *acl)
816 static char mydata[AFS_PIOCTL_MAXSIZE];
817 char tstring[AFS_PIOCTL_MAXSIZE];
822 if( FAILED(StringCbPrintf(dfsstring, sizeof(dfsstring), " dfs:%d %s", acl->dfs, acl->cell))) {
823 fprintf (stderr, "dfsstring - cannot be populated");
829 if( FAILED(StringCbPrintf(mydata, sizeof(mydata), "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus))) {
830 fprintf (stderr, "mydata - cannot be populated");
833 for (tp = acl->pluslist;tp;tp=tp->next) {
834 if( FAILED(StringCbPrintf(tstring, sizeof(tstring), "%s %d\n", tp->name, tp->rights))) {
835 fprintf (stderr, "tstring - cannot be populated");
838 if( FAILED(StringCbCat(mydata, sizeof(mydata), tstring))) {
839 fprintf (stderr, "mydata - not enough space");
843 for (tp = acl->minuslist;tp;tp=tp->next) {
844 if( FAILED(StringCbPrintf(tstring, sizeof(tstring), "%s %d\n", tp->name, tp->rights))) {
845 fprintf (stderr, "tstring - cannot be populated");
848 if( FAILED(StringCbCat(mydata, sizeof(mydata), tstring))) {
849 fprintf (stderr, "mydata - not enough space");
856 static DWORD IsFreelance(void)
863 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
864 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
865 if (code == ERROR_SUCCESS) {
866 dummyLen = sizeof(cm_freelanceEnabled);
867 code = RegQueryValueEx(parmKey, "FreelanceClient", NULL, NULL,
868 (BYTE *) &enabled, &dummyLen);
869 RegCloseKey (parmKey);
874 #define NETBIOSNAMESZ 1024
875 static const char * NetbiosName(void)
877 static char buffer[NETBIOSNAMESZ] = "AFS";
883 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
884 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
885 if (code == ERROR_SUCCESS) {
886 dummyLen = sizeof(buffer);
887 code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
889 RegCloseKey (parmKey);
891 if( FAILED(StringCbCopy(buffer, sizeof(buffer), "AFS"))) {
892 fprintf (stderr, "buffer - not enough space");
899 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
901 static BOOL IsAdmin (void)
903 static BOOL fAdmin = FALSE;
904 static BOOL fTested = FALSE;
908 /* Obtain the SID for the AFS client admin group. If the group does
909 * not exist, then assume we have AFS client admin privileges.
911 PSID psidAdmin = NULL;
912 DWORD dwSize, dwSize2;
913 char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
914 char *pszRefDomain = NULL;
915 SID_NAME_USE snu = SidTypeGroup;
917 dwSize = sizeof(pszAdminGroup);
919 if (!GetComputerName(pszAdminGroup, &dwSize)) {
920 /* Can't get computer name. We return false in this case.
921 Retain fAdmin and fTested. This shouldn't happen.*/
928 if( FAILED(StringCbCat(pszAdminGroup, MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2,"\\"))) {
929 fprintf (stderr, "pszAdminGroup - not enough space");
932 if( FAILED(StringCbCat(pszAdminGroup, MAX_COMPUTERNAME_LENGTH +
933 sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2, AFSCLIENT_ADMIN_GROUPNAME))) {
934 fprintf (stderr, "pszAdminGroup - not enough space");
938 LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
939 /* that should always fail. */
941 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
942 /* if we can't find the group, then we allow the operation */
947 if (dwSize == 0 || dwSize2 == 0) {
953 psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
955 pszRefDomain = (char *)malloc(dwSize2);
956 assert(pszRefDomain);
958 if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
959 /* We can't lookup the group now even though we looked it up earlier.
960 Could this happen? */
963 /* Then open our current ProcessToken */
966 if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
969 if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
970 /* We'll have to allocate a chunk of memory to store the list of
971 * groups to which this user belongs; find out how much memory
975 PTOKEN_GROUPS pGroups;
977 GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
979 pGroups = (PTOKEN_GROUPS)malloc(dwSize);
982 /* Allocate that buffer, and read in the list of groups. */
983 if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
985 /* Look through the list of group SIDs and see if any of them
986 * matches the AFS Client Admin group SID.
989 for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
991 if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
1001 /* if do not have permission because we were not explicitly listed
1002 * in the Admin Client Group let's see if we are the SYSTEM account
1005 PTOKEN_USER pTokenUser;
1006 SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
1007 PSID pSidLocalSystem = 0;
1010 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
1012 pTokenUser = (PTOKEN_USER)malloc(dwSize);
1015 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
1016 gle = GetLastError();
1018 if (AllocateAndInitializeSid( &SIDAuth, 1,
1019 SECURITY_LOCAL_SYSTEM_RID,
1020 0, 0, 0, 0, 0, 0, 0,
1023 if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
1027 FreeSid(pSidLocalSystem);
1046 SetACLCmd(struct cmd_syndesc *as, void *arock)
1049 struct ViceIoctl blob;
1051 struct cmd_item *ti, *ui;
1055 int idf = getidf(as, parm_setacl_id);
1059 if (as->parms[2].items)
1063 plusp = !(as->parms[3].items);
1064 for(ti=as->parms[0].items; ti;ti=ti->next) {
1065 if ( IsFreelanceRoot(ti->data) ) {
1066 fprintf(stderr,"%s: ACLs cannot be set on the Freelance root.afs volume.\n", pn);
1070 blob.out_size = AFS_PIOCTL_MAXSIZE;
1072 blob.in = blob.out = space;
1073 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1075 Die(errno, ti->data);
1081 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1084 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1089 if (!plusp && ta->dfs) {
1091 "fs: %s: you may not use the -negative switch with DFS acl's.\n%s",
1093 "(you may specify \"null\" to revoke all rights, however)\n");
1100 ta = EmptyAcl(space);
1102 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1105 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1110 CleanAcl(ta, ti->data);
1111 for(ui=as->parms[1].items; ui; ui=ui->next->next) {
1115 "%s: Missing second half of user/access pair.\n", pn);
1119 rights = Convert(ui->next->data, ta->dfs, &rtype);
1120 if (rtype == destroy && !ta->dfs) {
1121 struct AclEntry *tlist;
1123 tlist = (plusp ? ta->pluslist : ta->minuslist);
1124 if (!FindList(tlist, ui->data))
1127 if (rtype == deny && !ta->dfs)
1129 if (rtype == destroy && ta->dfs)
1131 ChangeList(ta, plusp, ui->data, rights, &rtype);
1133 blob.in = AclToString(ta);
1135 if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
1136 fprintf (stderr, "StringCbLength failure on blob.in");
1139 blob.in_size = 1+(long)len;
1140 code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
1142 if (errno == EINVAL) {
1144 static char *fsenv = 0;
1146 fsenv = (char *)getenv("FS_EXPERT");
1148 fprintf(stderr, "fs: \"Invalid argument\" was returned when you tried to store a DFS access list.\n");
1151 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1152 "\nPossible reasons for this include:\n\n",
1153 " -You may have specified an inappropriate combination of rights.\n",
1154 " For example, some DFS-supported filesystems may not allow you to\n",
1155 " drop the \"c\" right from \"user_obj\".\n\n",
1156 " -A mask_obj may be required (it is likely required by the underlying\n",
1157 " filesystem if you try to set anything other than the basic \"user_obj\"\n",
1158 " \"mask_obj\", or \"group_obj\" entries). Unlike acl_edit, the fs command\n",
1159 " does not automatically create or update the mask_obj. Try setting\n",
1160 " the rights \"mask_obj all\" with \"fs sa\" before adding any explicit\n",
1161 " users or groups. You can do this with a single command, such as\n",
1162 " \"fs sa mask_obj all user:somename read\"\n\n",
1163 " -A specified user or group may not exist.\n\n",
1164 " -You may have tried to delete \"user_obj\", \"group_obj\", or \"other_obj\".\n",
1165 " This is probably not allowed by the underlying file system.\n\n",
1166 " -If you add a user or group to a DFS ACL, remember that it must be\n",
1167 " fully specified as \"user:username\" or \"group:groupname\". In addition, there\n",
1168 " may be local requirements on the format of the user or group name.\n",
1169 " Check with your cell administrator.\n\n",
1170 " -Or numerous other possibilities. It would be great if we could be more\n",
1171 " precise about the actual problem, but for various reasons, this is\n",
1172 " impractical via this interface. If you can't figure it out, you\n",
1173 " might try logging into a DCE-equipped machine and use acl_edit (or\n",
1174 " whatever is provided). You may get better results. Good luck!\n\n",
1175 " (You may inhibit this message by setting \"FS_EXPERT\" in your environment)\n");
1179 "%s: Invalid argument, possible reasons include:\n",
1181 fprintf(stderr,"\t-File not in AFS\n");
1183 "\t-Too many users on access control list\n");
1185 "\t-Tried to add non-existent user to access control list\n");
1188 Die(errno, ti->data);
1199 CopyACLCmd(struct cmd_syndesc *as, void *arock)
1202 struct ViceIoctl blob;
1203 struct Acl *fa, *ta = 0;
1204 struct AclEntry *tp;
1205 struct cmd_item *ti;
1207 int idf = getidf(as, parm_copyacl_id);
1211 if (as->parms[2].items)
1215 blob.out_size = AFS_PIOCTL_MAXSIZE;
1217 blob.in = blob.out = space;
1218 code = pioctl_utf8(as->parms[0].items->data, VIOCGETAL, &blob, 1);
1220 Die(errno, as->parms[0].items->data);
1223 fa = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1226 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1227 as->parms[0].items->data);
1230 CleanAcl(fa, as->parms[0].items->data);
1231 for (ti=as->parms[1].items; ti;ti=ti->next) {
1232 blob.out_size = AFS_PIOCTL_MAXSIZE;
1234 blob.in = blob.out = space;
1235 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1237 Die(errno, ti->data);
1244 ta = EmptyAcl(space);
1246 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1249 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1254 CleanAcl(ta, ti->data);
1255 if (ta->dfs != fa->dfs) {
1257 "%s: incompatible file system types: acl not copied to %s; aborted\n",
1263 if (! clear && strcmp(ta->cell, fa->cell) != 0) {
1265 "%s: default DCE cell differs for file %s: use \"-clear\" switch; acl not merged\n",
1270 if( FAILED(StringCbCopy(ta->cell, sizeof(ta->cell), fa->cell))) {
1271 fprintf (stderr, "cell - not enough space");
1275 for (tp = fa->pluslist;tp;tp=tp->next)
1276 ChangeList(ta, 1, tp->name, tp->rights, NULL);
1277 for (tp = fa->minuslist;tp;tp=tp->next)
1278 ChangeList(ta, 0, tp->name, tp->rights, NULL);
1279 blob.in = AclToString(ta);
1281 if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
1282 fprintf (stderr, "StringCbLength failure on blob.in");
1285 blob.in_size = 1+(long)len;
1286 code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
1288 if (errno == EINVAL) {
1290 "%s: Invalid argument, possible reasons include:\n", pn);
1291 fprintf(stderr,"\t-File not in AFS\n");
1293 Die(errno, ti->data);
1304 /* pioctl_utf8() call to get the cellname of a pathname */
1306 GetCell(char *fname, char *cellname)
1309 struct ViceIoctl blob;
1312 blob.out_size = CELL_MAXNAMELEN;
1313 blob.out = cellname;
1315 code = pioctl_utf8(fname, VIOC_FILE_CELL_NAME, &blob, 1);
1317 cellname[blob.out_size - 1] = '\0';
1321 /* Check if a username is valid: If it contains only digits (or a
1322 * negative sign), then it might be bad. We then query the ptserver
1326 BadName(char *aname, char *fname)
1328 afs_int32 tc, code, id;
1330 char cell[CELL_MAXNAMELEN];
1333 for ( nm = aname; tc = *nm; nm++) {
1334 /* all must be '-' or digit to be bad */
1335 if (tc != '-' && (tc < '0' || tc > '9'))
1339 /* Go to the PRDB and see if this all number username is valid */
1340 code = GetCell(fname, cell);
1344 cm_GetConfigDir(confDir, sizeof(confDir));
1346 pr_Initialize(1, confDir, cell);
1347 code = pr_SNameToId(aname, &id);
1350 /* 1=>Not-valid; 0=>Valid */
1351 return ((!code && (id == ANONYMOUSID)) ? 1 : 0);
1355 /* clean up an access control list of its bad entries; return 1 if we made
1356 any changes to the list, and 0 otherwise */
1358 CleanAcl(struct Acl *aa, char *fname)
1360 struct AclEntry *te, **le, *ne;
1363 /* Don't correct DFS ACL's for now */
1367 /* prune out bad entries */
1368 changes = 0; /* count deleted entries */
1370 for(te = aa->pluslist; te; te=ne) {
1372 if (BadName(te->name, fname)) {
1382 le = &aa->minuslist;
1383 for(te = aa->minuslist; te; te=ne) {
1385 if (BadName(te->name, fname)) {
1399 /* clean up an acl to not have bogus entries */
1401 CleanACLCmd(struct cmd_syndesc *as, void *arock)
1405 struct ViceIoctl blob;
1407 struct cmd_item *ti;
1408 struct AclEntry *te;
1412 SetDotDefault(&as->parms[0].items);
1413 for(ti=as->parms[0].items; ti; ti=ti->next) {
1414 blob.out_size = AFS_PIOCTL_MAXSIZE;
1417 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1419 Die(errno, ti->data);
1425 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1428 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1435 "%s: cleanacl is not supported for DFS access lists.\n",
1441 changes = CleanAcl(ta, ti->data);
1444 /* now set the acl */
1445 blob.in=AclToString(ta);
1446 if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
1447 fprintf (stderr, "StringCbLength failure on blob.in");
1450 blob.in_size = (long)len+1;
1452 code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
1454 if (errno == EINVAL) {
1456 "%s: Invalid argument, possible reasons include\n",
1458 fprintf(stderr,"%s: File not in vice or\n", pn);
1460 "%s: Too many users on access control list or\n",
1463 Die(errno, ti->data);
1469 /* now list the updated acl */
1470 printf("Access list for %s is now\n", ti->data);
1471 if (ta->nplus > 0) {
1473 printf("Normal rights:\n");
1474 for(te = ta->pluslist;te;te=te->next) {
1475 printf(" %s ", te->name);
1476 PRights(te->rights, ta->dfs);
1480 if (ta->nminus > 0) {
1481 printf("Negative rights:\n");
1482 for(te = ta->minuslist;te;te=te->next) {
1483 printf(" %s ", te->name);
1484 PRights(te->rights, ta->dfs);
1491 printf("Access list for %s is fine.\n", ti->data);
1499 ListACLCmd(struct cmd_syndesc *as, void *arock)
1503 struct ViceIoctl blob;
1504 struct AclEntry *te;
1505 struct cmd_item *ti;
1506 int idf = getidf(as, parm_listacl_id);
1509 SetDotDefault(&as->parms[0].items);
1510 for(ti=as->parms[0].items; ti; ti=ti->next) {
1513 if ( IsFreelanceRoot(ti->data) ) {
1514 fprintf(stderr,"%s: ACLs are not set on the Freelance root.afs volume.\n", pn);
1519 blob.out_size = AFS_PIOCTL_MAXSIZE;
1521 blob.in = blob.out = space;
1522 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1524 Die(errno, ti->data);
1528 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1531 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1536 if (as->parms[3].items) { /* -cmd */
1537 printf("fs setacl -dir %s -acl ", ti->data);
1538 if (ta->nplus > 0) {
1539 for (te = ta->pluslist; te; te = te->next) {
1540 printf(" %s ", te->name);
1541 PRights(te->rights, ta->dfs);
1545 if (ta->nminus > 0) {
1546 printf("fs setacl -dir %s -acl ", ti->data);
1547 for (te = ta->minuslist; te; te = te->next) {
1548 printf(" %s ", te->name);
1549 PRights(te->rights, ta->dfs);
1551 printf(" -negative\n");
1556 printf("Access list for %s is\n", ti->data);
1559 printf("DFS access list for %s is\n", ti->data);
1562 printf("DFS initial directory access list of %s is\n", ti->data);
1565 printf("DFS initial file access list of %s is\n", ti->data);
1569 printf(" Default cell = %s\n", ta->cell);
1571 separator = ta->dfs? DFS_SEPARATOR : ' ';
1572 if (ta->nplus > 0) {
1574 printf("Normal rights:\n");
1575 for(te = ta->pluslist;te;te=te->next) {
1576 printf(" %s%c", te->name, separator);
1577 PRights(te->rights, ta->dfs);
1581 if (ta->nminus > 0) {
1582 printf("Negative rights:\n");
1583 for(te = ta->minuslist;te;te=te->next) {
1584 printf(" %s ", te->name);
1585 PRights(te->rights, ta->dfs);
1598 FlushAllCmd(struct cmd_syndesc *as, void *arock)
1601 struct ViceIoctl blob;
1603 blob.in_size = blob.out_size = 0;
1604 code = pioctl_utf8(NULL, VIOC_FLUSHALL, &blob, 0);
1606 fprintf(stderr, "Error flushing all ");
1613 FlushVolumeCmd(struct cmd_syndesc *as, void *arock)
1616 struct ViceIoctl blob;
1617 struct cmd_item *ti;
1620 SetDotDefault(&as->parms[0].items);
1621 for(ti=as->parms[0].items; ti; ti=ti->next) {
1622 blob.in_size = blob.out_size = 0;
1623 code = pioctl_utf8(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
1625 fprintf(stderr, "Error flushing volume ");
1635 FlushCmd(struct cmd_syndesc *as, void *arock)
1638 struct ViceIoctl blob;
1639 struct cmd_item *ti;
1642 cm_ioctlQueryOptions_t options;
1644 if (as->parms[1].items)
1647 for(ti=as->parms[0].items; ti; ti=ti->next) {
1649 memset(&options, 0, sizeof(options));
1650 options.size = sizeof(options);
1651 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
1652 options.literal = literal;
1653 blob.in_size = options.size; /* no variable length data */
1657 code = pioctl_utf8(ti->data, VIOCFLUSH, &blob, 0);
1659 if (errno == EMFILE) {
1660 fprintf(stderr, "%s: Can't flush active file %s\n", pn,
1663 fprintf(stderr, "%s: Error flushing file ", pn);
1673 /* all this command does is repackage its args and call SetVolCmd */
1675 SetQuotaCmd(struct cmd_syndesc *as, void *arock) {
1676 struct cmd_syndesc ts;
1678 /* copy useful stuff from our command slot; we may later have to reorder */
1680 memcpy(&ts, as, sizeof(ts)); /* copy whole thing */
1682 err = memcpy_s(&ts, sizeof(ts), as, sizeof(ts)); /* copy whole thing */
1684 fprintf (stderr, "memcpy_s failure on ts");
1688 return SetVolCmd(&ts, arock);
1692 SetVolCmd(struct cmd_syndesc *as, void *arock) {
1694 struct ViceIoctl blob;
1695 struct cmd_item *ti;
1696 struct VolumeStatus *status;
1697 char *motd, *offmsg, *input, *destEnd;
1698 size_t destRemaining;
1702 SetDotDefault(&as->parms[0].items);
1703 for(ti=as->parms[0].items; ti; ti=ti->next) {
1705 destRemaining = sizeof(space);
1706 blob.out_size = AFS_PIOCTL_MAXSIZE;
1707 blob.in_size = sizeof(*status) + 3; /* for the three terminating nulls */
1710 status = (VolumeStatus *)space;
1711 status->MinQuota = status->MaxQuota = -1;
1712 motd = offmsg = NULL;
1713 if (as->parms[1].items) {
1714 code = util_GetHumanInt32(as->parms[1].items->data, &status->MaxQuota);
1716 fprintf(stderr,"%s: bad integer specified for quota.\n", pn);
1721 if (as->parms[2].items)
1722 motd = as->parms[2].items->data;
1723 if (as->parms[3].items)
1724 offmsg = as->parms[3].items->data;
1725 input = (char *)status + sizeof(*status);
1726 *(input++) = '\0'; /* never set name: this call doesn't change vldb */
1727 destRemaining -= sizeof(*status) + 1;
1729 if( FAILED(StringCbLength(offmsg, VMSGSIZE, &len))) {
1730 fprintf(stderr,"%s: message must be shorter than %d characters\n",
1735 if( FAILED(StringCbCopyEx(input, destRemaining, offmsg, &destEnd, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
1736 fprintf (stderr, "input - not enough space");
1739 blob.in_size += destEnd - input;
1740 input = destEnd + 1;
1741 destRemaining -= sizeof(char);
1744 destRemaining -= sizeof(char);
1747 if( FAILED(StringCbLength(motd, VMSGSIZE, &len))) {
1748 fprintf(stderr,"%s: message must be shorter than %d characters\n",
1752 if( FAILED(StringCbCopyEx(input, destRemaining, motd, &destEnd, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
1753 fprintf (stderr, "input - not enough space");
1756 blob.in_size += (long)(destEnd - input);
1757 input = destEnd + 1;
1758 destRemaining -= sizeof(char);
1761 destRemaining -= sizeof(char);
1763 code = pioctl_utf8(ti->data,VIOCSETVOLSTAT, &blob, 1);
1765 Die(errno, ti->data);
1772 /* values match cache manager File Types */
1774 filetypestr(afs_uint32 type)
1776 char * s = "Object";
1799 ExamineCmd(struct cmd_syndesc *as, void *arock)
1802 struct ViceIoctl blob;
1803 struct cmd_item *ti;
1804 struct VolumeStatus *status;
1805 char *name, *offmsg, *motd;
1808 cm_ioctlQueryOptions_t options;
1811 if (as->parms[1].items)
1814 SetDotDefault(&as->parms[0].items);
1815 for(ti=as->parms[0].items; ti; ti=ti->next) {
1817 afs_uint32 filetype;
1819 afs_uint32 unixModeBits;
1820 char cell[CELL_MAXNAMELEN];
1823 memset(&fid, 0, sizeof(fid));
1824 memset(&options, 0, sizeof(options));
1826 options.size = sizeof(options);
1827 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
1828 options.literal = literal;
1829 blob.in_size = options.size; /* no variable length data */
1832 blob.out_size = sizeof(cm_fid_t);
1833 blob.out = (char *) &fid;
1834 if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1) &&
1835 blob.out_size == sizeof(cm_fid_t)) {
1836 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
1839 Die(errno, ti->data);
1844 blob.out_size = sizeof(filetype);
1845 blob.out = &filetype;
1847 code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
1848 if (code || blob.out_size != sizeof(filetype)) {
1849 Die(errno, ti->data);
1854 blob.out_size = CELL_MAXNAMELEN;
1857 code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
1859 cell[blob.out_size-1] = '\0';
1860 printf("%s %s (%u.%u.%u) contained in cell %s\n",
1861 filetypestr(filetype),
1862 ti->data, fid.volume, fid.vnode, fid.unique,
1863 code ? "unknown-cell" : cell);
1865 blob.out_size = 2 * sizeof(afs_uint32);
1866 blob.out = (char *) &owner;
1867 if (0 == pioctl_utf8(ti->data, VIOCGETOWNER, &blob, 1) &&
1868 blob.out_size == 2 * sizeof(afs_uint32)) {
1869 char oname[PR_MAXNAMELEN] = "(unknown)";
1870 char gname[PR_MAXNAMELEN] = "(unknown)";
1873 /* Go to the PRDB and see if this all number username is valid */
1874 cm_GetConfigDir(confDir, sizeof(confDir));
1876 pr_Initialize(1, confDir, cell);
1877 pr_SIdToName(owner[0], oname);
1878 pr_SIdToName(owner[1], gname);
1879 printf("Owner %s (%d) Group %s (%d)\n", oname, owner[0], gname, owner[1]);
1882 blob.out_size = sizeof(afs_uint32);
1883 blob.out = (char *) &unixModeBits;
1884 if (0 == pioctl_utf8(ti->data, VIOC_GETUNIXMODE, &blob, 1) &&
1885 blob.out_size == sizeof(afs_uint32)) {
1886 printf("UNIX mode 0%o\n", unixModeBits);
1890 blob.out_size = AFS_PIOCTL_MAXSIZE;
1891 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
1893 space[blob.out_size - 1] = '\0';
1894 status = (VolumeStatus *)space;
1895 name = (char *)status + sizeof(*status);
1896 if( FAILED(StringCbLength(name, sizeof(space) - (name - space), &len))) {
1897 fprintf (stderr, "StringCbLength failure on name");
1900 offmsg = name + len + 1;
1901 if( FAILED(StringCbLength(offmsg, sizeof(space) - (offmsg - space), &len))) {
1902 fprintf (stderr, "StringCbLength failure on offmsg");
1905 motd = offmsg + len + 1;
1906 PrintStatus(status, name, motd, offmsg);
1908 Die(errno, ti->data);
1912 code = pioctl_utf8(ti->data, VIOC_PATH_AVAILABILITY, &blob, 1);
1915 printf("Volume is online\n");
1918 printf("Volume is offline\n");
1921 printf("All Volume servers are down\n");
1924 printf("All volume servers are busy\n");
1927 printf("Unknown volume state\n");
1928 Die(errno, ti->data);
1936 ListQuotaCmd(struct cmd_syndesc *as, void *arock)
1939 struct ViceIoctl blob;
1940 struct cmd_item *ti;
1941 struct VolumeStatus *status;
1946 printf("%-25s%-11s%-11s%-7s%-13s\n", "Volume Name", " Quota",
1947 " Used", " %Used", " Partition");
1948 SetDotDefault(&as->parms[0].items);
1949 for(ti=as->parms[0].items; ti; ti=ti->next) {
1951 blob.out_size = AFS_PIOCTL_MAXSIZE;
1954 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
1956 Die(errno, ti->data);
1960 space[blob.out_size - 1] = '\0';
1961 status = (VolumeStatus *)space;
1962 name = (char *)status + sizeof(*status);
1963 QuickPrintStatus(status, name);
1969 WhereIsCmd(struct cmd_syndesc *as, void *arock)
1972 struct ViceIoctl blob;
1973 struct cmd_item *ti;
1979 cm_ioctlQueryOptions_t options;
1981 if (as->parms[1].items)
1984 SetDotDefault(&as->parms[0].items);
1985 for(ti=as->parms[0].items; ti; ti=ti->next) {
1987 afs_uint32 filetype;
1990 memset(&fid, 0, sizeof(fid));
1991 memset(&options, 0, sizeof(options));
1993 options.size = sizeof(options);
1994 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
1995 options.literal = literal;
1996 blob.in_size = options.size; /* no variable length data */
1999 blob.out_size = sizeof(cm_fid_t);
2000 blob.out = (char *) &fid;
2001 if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1) &&
2002 blob.out_size == sizeof(cm_fid_t)) {
2003 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
2006 Die(errno, ti->data);
2011 blob.out_size = sizeof(filetype);
2012 blob.out = &filetype;
2014 code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
2015 if (code || blob.out_size != sizeof(filetype)) {
2016 Die(errno, ti->data);
2020 blob.out_size = AFS_PIOCTL_MAXSIZE;
2022 memset(space, 0, sizeof(space));
2023 code = pioctl_utf8(ti->data, VIOCWHEREIS, &blob, 1);
2025 Die(errno, ti->data);
2029 hosts = (afs_int32 *) space;
2030 printf("%s %s is on host%s ",
2031 filetypestr(filetype),
2033 (hosts[0] && !hosts[1]) ? "": "s");
2034 for(j=0; j<AFS_MAXHOSTS; j++) {
2037 tp = hostutil_GetNameByINet(hosts[j]);
2047 DiskFreeCmd(struct cmd_syndesc *as, void *arock)
2050 struct ViceIoctl blob;
2051 struct cmd_item *ti;
2053 struct VolumeStatus *status;
2056 printf("%-25s%-10s%-10s%-10s%-6s\n", "Volume Name", " kbytes",
2057 " used", " avail", " %used");
2058 SetDotDefault(&as->parms[0].items);
2059 for(ti=as->parms[0].items; ti; ti=ti->next) {
2061 blob.out_size = AFS_PIOCTL_MAXSIZE;
2064 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
2066 Die(errno, ti->data);
2070 space[blob.out_size - 1] = '\0';
2071 status = (VolumeStatus *)space;
2072 name = (char *)status + sizeof(*status);
2073 QuickPrintSpace(status, name);
2079 QuotaCmd(struct cmd_syndesc *as, void *arock)
2082 struct ViceIoctl blob;
2083 struct cmd_item *ti;
2085 struct VolumeStatus *status;
2088 SetDotDefault(&as->parms[0].items);
2089 for(ti=as->parms[0].items; ti; ti=ti->next) {
2091 blob.out_size = AFS_PIOCTL_MAXSIZE;
2094 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
2096 * The response is VolumeStatus, volume name, offline message, and motd
2098 if (code || blob.out_size < sizeof(*status)) {
2099 Die(errno, ti->data);
2104 status = (VolumeStatus *)space;
2105 if (status->MaxQuota)
2106 quotaPct = ((((double)status->BlocksInUse)/status->MaxQuota) * 100.0);
2109 printf("%2.0f%% of quota used.\n", quotaPct);
2115 ListMountCmd(struct cmd_syndesc *as, void *arock)
2118 struct ViceIoctl blob;
2119 struct cmd_item *ti;
2120 char orig_name[1024]; /*Original name, may be modified*/
2121 char true_name[1024]; /*``True'' dirname (e.g., symlink target)*/
2122 char parent_dir[1024]; /*Parent directory of true name*/
2123 char *last_component; /*Last component of true name*/
2127 struct stat statbuff; /*Buffer for status info*/
2128 #endif /* not WIN32 */
2130 int link_chars_read; /*Num chars read in readlink()*/
2131 #endif /* not WIN32 */
2132 int thru_symlink; /*Did we get to a mount point via a symlink?*/
2135 for(ti=as->parms[0].items; ti; ti=ti->next) {
2139 if( FAILED(StringCbCopy(orig_name, sizeof(orig_name), ti->data))) {
2140 fprintf (stderr, "orig_name - not enough space");
2143 #else /* not WIN32 */
2145 if( FAILED(StringCbPrintf(orig_name, sizeof(orig_name), "%s%s",
2146 (ti->data[0] == '/') ? "" : "./",
2148 fprintf (stderr, "orig_name - cannot be populated");
2151 #endif /* not WIN32 */
2154 if (lstat(orig_name, &statbuff) < 0) {
2155 /* if lstat fails, we should still try the pioctl, since it
2156 * may work (for example, lstat will fail, but pioctl will
2157 * work if the volume of offline (returning ENODEV). */
2158 statbuff.st_mode = S_IFDIR; /* lie like pros */
2162 * The lstat succeeded. If the given file is a symlink, substitute
2163 * the file name with the link name.
2165 if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
2168 * Read name of resolved file.
2170 link_chars_read = readlink(orig_name, true_name, 1024);
2171 if (link_chars_read <= 0) {
2173 "%s: Can't read target name for '%s' symbolic link!\n",
2180 * Add a trailing null to what was read, bump the length.
2182 true_name[link_chars_read++] = 0;
2185 * If the symlink is an absolute pathname, we're fine. Otherwise, we
2186 * have to create a full pathname using the original name and the
2187 * relative symlink name. Find the rightmost slash in the original
2188 * name (we know there is one) and splice in the symlink value.
2190 if (true_name[0] != '\\') {
2191 last_component = (char *) strrchr(orig_name, '\\');
2192 if( FAILED(StringCbCopy(++last_component, sizeof(orig_name) - (last_component - orig_name) * sizeof(char), true_name))) {
2193 fprintf (stderr, "last_component - not enough space");
2196 if( FAILED(StringCbCopy(true_name, sizeof(true_name), orig_name))) {
2197 fprintf (stderr, "true_name - not enough space");
2202 if( FAILED(StringCbCopy(true_name, sizeof(true_name), orig_name))) {
2203 fprintf (stderr, "true_name - not enough space");
2208 if( FAILED(StringCbCopy(true_name, sizeof(true_name), orig_name))) {
2209 fprintf (stderr, "true_name - not enough space");
2215 * Find rightmost slash, if any.
2218 last_component = (char *) strrchr(true_name, '\\');
2219 if (!last_component)
2221 last_component = (char *) strrchr(true_name, '/');
2222 if (last_component) {
2224 * Found it. Designate everything before it as the parent directory,
2225 * everything after it as the final component.
2227 if( FAILED(StringCchCopyN(parent_dir, sizeof(parent_dir) / sizeof(char), true_name, last_component - true_name + 1))) {
2228 fprintf (stderr, "parent_dir - not enough space");
2231 parent_dir[last_component - true_name + 1] = 0;
2232 last_component++; /*Skip the slash*/
2234 if (!InAFS(parent_dir)) {
2235 const char * nbname = NetbiosName();
2236 if( FAILED(StringCbLength(nbname, NETBIOSNAMESZ, &len))) {
2237 fprintf (stderr, "StringCbLength failure on nbname");
2240 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
2241 parent_dir[len+2] == '\\' &&
2242 parent_dir[len+3] == '\0' &&
2243 !strnicmp(nbname,&parent_dir[2],len))
2245 if( FAILED(StringCbPrintf(parent_dir, sizeof(parent_dir),"\\\\%s\\all\\", nbname))) {
2246 fprintf (stderr, "parent_dir - cannot be populated");
2254 * No slash appears in the given file name. Set parent_dir to the current
2255 * directory, and the last component as the given name.
2257 fs_ExtractDriveLetter(true_name, parent_dir);
2258 if( FAILED(StringCbCat(parent_dir, sizeof(parent_dir), "."))) {
2259 fprintf (stderr, "parent_dir - not enough space");
2262 last_component = true_name;
2263 fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2266 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
2267 fprintf(stderr,"%s: you may not use '.' or '..' as the last component\n",pn);
2268 fprintf(stderr,"%s: of a name in the 'fs lsmount' command.\n",pn);
2273 blob.in = last_component;
2274 if( FAILED(StringCchLength(last_component, sizeof(true_name) / sizeof(char) - (last_component - true_name), &len))) {
2275 fprintf (stderr, "StringCbLength failure on last_component");
2278 blob.in_size = (long)len+1;
2279 blob.out_size = AFS_PIOCTL_MAXSIZE;
2281 memset(space, 0, AFS_PIOCTL_MAXSIZE);
2283 code = pioctl_utf8(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
2286 printf("'%s' is a %smount point for volume '%.*s'\n",
2288 (thru_symlink ? "symbolic link, leading to a " : ""),
2293 if (errno == EINVAL) {
2294 fprintf(stderr,"'%s' is not a mount point.\n", ti->data);
2296 Die(errno, (ti->data ? ti->data : parent_dir));
2305 MakeMountCmd(struct cmd_syndesc *as, void *arock)
2308 char *cellName, *volName, *tmpName;
2310 char localCellName[128];
2312 char path[1024] = "";
2313 struct afsconf_cell info;
2314 struct vldbentry vldbEntry;
2315 struct ViceIoctl blob;
2319 memset(&info, 0, sizeof(info));
2321 if (as->parms[2].items) /* cell name specified */
2322 cellName = as->parms[2].items->data;
2325 volName = as->parms[1].items->data;
2326 if( FAILED(StringCbLength(volName, VL_MAXNAMELEN, &len))) {
2327 fprintf(stderr,"%s: volume name too long (length must be <= 64 characters)\n", pn);
2331 /* Check for a cellname in the volume specification, and complain
2332 * if it doesn't match what was specified with -cell */
2333 if (tmpName = strchr(volName, ':')) {
2336 if (strcasecmp(cellName,volName)) {
2337 fprintf(stderr,"fs: cellnames do not match.\n");
2342 volName = ++tmpName;
2345 parent = Parent(as->parms[0].items->data);
2346 if (!InAFS(parent)) {
2348 const char * nbname = NetbiosName();
2349 if ( FAILED(StringCbLength(nbname, NETBIOSNAMESZ, &len))) {
2350 fprintf (stderr, "StringCbLength failure on nbname");
2353 if (parent[0] == '\\' && parent[1] == '\\' &&
2354 (parent[len+2] == '\\' && parent[len+3] == '\0' || parent[len+2] == '\0') &&
2355 !strnicmp(nbname,&parent[2],len))
2357 if( FAILED(StringCbPrintf(path, sizeof(path),"%s%sall%s", parent,
2358 parent[len+2]?"":"\\",
2359 &as->parms[0].items->data[len+2]))) {
2360 fprintf (stderr, "path - cannot be populated");
2363 parent = Parent(path);
2364 if (!InAFS(parent)) {
2365 fprintf(stderr,"%s: mount points must be created within the AFS file system\n", pn);
2371 fprintf(stderr,"%s: mount points must be created within the AFS file system\n", pn);
2376 if( FAILED(StringCbLength(path, sizeof(path), &len))) {
2377 fprintf (stderr, "StringCbLength failure on path");
2381 if( FAILED(StringCbCopy(path, sizeof(path), as->parms[0].items->data))) {
2382 fprintf (stderr, "path - not enough space");
2386 if ( IsFreelanceRoot(parent) ) {
2388 fprintf(stderr,"%s: Only AFS Client Administrators may alter the Freelance root.afs volume\n", pn);
2394 blob.out_size = sizeof(localCellName);
2395 blob.out = localCellName;
2396 code = pioctl_utf8(parent, VIOC_GET_WS_CELL, &blob, 1);
2398 localCellName[sizeof(localCellName) - 1] = '\0';
2399 cellName = localCellName;
2404 code = GetCell(parent,space);
2410 code = GetCellName(cellName?cellName:space, &info);
2414 if (!(as->parms[4].items)) {
2415 /* not fast, check which cell the mountpoint is being created in */
2417 /* not fast, check name with VLDB */
2419 code = VLDBInit(1, &info);
2421 /* make the check. Don't complain if there are problems with init */
2422 code = ubik_VL_GetEntryByNameO(uclient, 0, volName, &vldbEntry);
2423 if (code == VL_NOENT) {
2424 fprintf(stderr,"%s: warning, volume %s does not exist in cell %s.\n",
2425 pn, volName, cellName ? cellName : space);
2430 if (as->parms[3].items) { /* if -rw specified */
2431 if( FAILED(StringCbCopy(space, sizeof(space), "%"))) {
2432 fprintf (stderr, "space arr - not enough space");
2436 if( FAILED(StringCbCopy(space, sizeof(space), "#"))) {
2437 fprintf (stderr, "space arr - not enough space");
2442 /* cellular mount point, prepend cell prefix */
2443 if( FAILED(StringCbCat(space, sizeof(space), info.name))) {
2444 fprintf (stderr, "space arr - not enough space");
2447 if( FAILED(StringCbCat(space, sizeof(space), ":"))) {
2448 fprintf (stderr, "space arr - not enough space");
2452 if( FAILED(StringCbCat(space, sizeof(space), volName))) { /* append volume name */
2453 fprintf (stderr, "space arr - not enough space");
2456 if( FAILED(StringCbCat(space, sizeof(space), "."))) { /* stupid convention; these end with a period */
2457 fprintf (stderr, "space arr - not enough space");
2461 /* create symlink with a special pioctl for Windows NT, since it doesn't
2462 * have a symlink system call.
2465 if( FAILED(StringCbLength(space, sizeof(space), &len))) {
2466 fprintf (stderr, "StringCbLength failure on space");
2469 blob.in_size = 1 + (long)len;
2472 code = pioctl_utf8(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
2473 #else /* not WIN32 */
2474 code = symlink(space, path);
2475 #endif /* not WIN32 */
2477 if (info.linkedCell)
2478 free(info.linkedCell);
2488 * Delete AFS mount points. Variables are used as follows:
2489 * tbuffer: Set to point to the null-terminated directory name of the mount point
2490 * (or ``.'' if none is provided)
2491 * tp: Set to point to the actual name of the mount point to nuke.
2494 RemoveMountCmd(struct cmd_syndesc *as, void *arock) {
2496 struct ViceIoctl blob;
2497 struct cmd_item *ti;
2499 char lsbuffer[1024];
2504 for(ti=as->parms[0].items; ti; ti=ti->next) {
2506 tp = (char *) strrchr(ti->data, '\\');
2508 tp = (char *) strrchr(ti->data, '/');
2510 if( FAILED(StringCchCopyN(tbuffer, sizeof(tbuffer) / sizeof(char), ti->data, code=(afs_int32)(tp-ti->data+1)))) { /* the dir name */
2511 fprintf (stderr, "tbuffer - not enough space");
2514 tp++; /* skip the slash */
2517 if (!InAFS(tbuffer)) {
2518 const char * nbname = NetbiosName();
2519 if( FAILED(StringCbLength(nbname, NETBIOSNAMESZ, &len))) {
2520 fprintf (stderr, "StringCbLength failure on nbname");
2524 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
2525 tbuffer[len+2] == '\\' &&
2526 tbuffer[len+3] == '\0' &&
2527 !strnicmp(nbname,&tbuffer[2],len))
2529 if( FAILED(StringCbPrintf(tbuffer, sizeof(tbuffer),"\\\\%s\\all\\", nbname))) {
2530 fprintf (stderr, "tbuffer - cannot be populated");
2537 fs_ExtractDriveLetter(ti->data, tbuffer);
2538 if( FAILED(StringCbCat(tbuffer, sizeof(tbuffer), "."))) {
2539 fprintf (stderr, "tbuffer - not enough space");
2543 fs_StripDriveLetter(tp, tp, 0);
2546 if( FAILED(StringCbLength(tp, AFS_PIOCTL_MAXSIZE, &len))) {
2547 fprintf (stderr, "StringCbLength failure on tp");
2550 blob.in_size = (long)len+1;
2551 blob.out = lsbuffer;
2552 blob.out_size = sizeof(lsbuffer);
2553 code = pioctl_utf8(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
2555 if (errno == EINVAL) {
2556 fprintf(stderr,"%s: '%s' is not a mount point.\n", pn, ti->data);
2558 Die(errno, ti->data);
2561 continue; /* don't bother trying */
2564 if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
2565 fprintf(stderr,"%s: Only AFS Client Administrators may alter the Freelance root.afs volume\n", pn);
2567 continue; /* skip */
2572 if( FAILED(StringCbLength(tp, AFS_PIOCTL_MAXSIZE, &len))) {
2573 fprintf (stderr, "StringCbLength failure on tp");
2576 blob.in_size = (long)len+1;
2577 code = pioctl_utf8(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
2579 Die(errno, ti->data);
2590 CheckServersCmd(struct cmd_syndesc *as, void *arock)
2593 struct ViceIoctl blob;
2597 struct afsconf_cell info;
2598 struct chservinfo checkserv;
2602 memset(&info, 0, sizeof(info));
2603 memset(&checkserv, 0, sizeof(struct chservinfo));
2604 blob.in_size=sizeof(struct chservinfo);
2605 blob.in=(caddr_t)&checkserv;
2607 blob.out_size = AFS_PIOCTL_MAXSIZE;
2609 memset(space, 0, sizeof(afs_int32)); /* so we assure zero when nothing is copied back */
2611 /* prepare flags for checkservers command */
2612 temp = 2; /* default to checking local cell only */
2613 if (as->parms[2].items)
2614 temp |= 1; /* set fast flag */
2615 if (as->parms[1].items)
2616 temp &= ~2; /* turn off local cell check */
2618 checkserv.magic = 0x12345678; /* XXX */
2619 checkserv.tflags=temp;
2621 /* now copy in optional cell name, if specified */
2622 if (as->parms[0].items) {
2623 code = GetCellName(as->parms[0].items->data, &info);
2627 if( FAILED(StringCbCopy(checkserv.tbuffer, sizeof(checkserv.tbuffer), info.name))) {
2628 fprintf (stderr, "tbuffer - not enough space");
2631 if( FAILED(StringCbLength(info.name, sizeof(info.name), &len))) {
2632 fprintf (stderr, "StringCbLength failure on info.name");
2635 checkserv.tsize=(int)len+1;
2636 if (info.linkedCell)
2637 free(info.linkedCell);
2639 if( FAILED(StringCbCopy(checkserv.tbuffer, sizeof(checkserv.tbuffer),"\0"))) {
2640 fprintf (stderr, "tbuffer - not enough space");
2646 if(as->parms[3].items) {
2647 checkserv.tinterval=atol(as->parms[3].items->data);
2650 if(checkserv.tinterval<0) {
2651 printf("Warning: The negative -interval is ignored; treated as an inquiry\n");
2652 checkserv.tinterval=-1;
2653 } else if(checkserv.tinterval> 600) {
2654 printf("Warning: The maximum -interval value is 10 mins (600 secs)\n");
2655 checkserv.tinterval=600; /* 10 min max interval */
2658 checkserv.tinterval = -1; /* don't change current interval */
2661 if ( checkserv.tinterval >= 0 ) {
2664 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2669 fprintf (stderr,"Permission denied: requires root access.\n");
2675 code = pioctl_utf8(0, VIOCCKSERV, &blob, 1);
2677 if ((errno == EACCES) && (checkserv.tinterval > 0)) {
2678 printf("Must be root to change -interval\n");
2685 memcpy(&temp, space, sizeof(afs_int32));
2687 err = memcpy_s(&temp, sizeof(temp), space, sizeof(afs_int32));
2689 fprintf (stderr, "memcpy_s failure on temp");
2694 if (checkserv.tinterval >= 0) {
2695 if (checkserv.tinterval > 0)
2696 printf("The new down server probe interval (%d secs) is now in effect (old interval was %d secs)\n",
2697 checkserv.tinterval, temp);
2699 printf("The current down server probe interval is %d secs\n", temp);
2703 printf("All servers are running.\n");
2705 printf("These servers unavailable due to network or server problems: ");
2706 for(j=0; j < AFS_MAXHOSTS; j++) {
2708 memcpy(&temp, space + j*sizeof(afs_int32), sizeof(afs_int32));
2710 err = memcpy_s(&temp, sizeof(temp), space + j*sizeof(afs_int32), sizeof(afs_int32));
2712 fprintf (stderr, "memcpy_s failure on temp");
2719 tp = hostutil_GetNameByINet(temp);
2729 MessagesCmd(struct cmd_syndesc *as, void *arock)
2732 struct ViceIoctl blob;
2733 struct gaginfo gagflags;
2734 struct cmd_item *show;
2736 memset(&gagflags, 0, sizeof(struct gaginfo));
2737 blob.in_size = sizeof(struct gaginfo);
2738 blob.in = (caddr_t ) &gagflags;
2739 blob.out_size = AFS_PIOCTL_MAXSIZE;
2741 memset(space, 0, sizeof(afs_int32)); /* so we assure zero when nothing is copied back */
2743 if (show = as->parms[0].items) {
2744 if (!strcasecmp (show->data, "user"))
2745 gagflags.showflags |= GAGUSER;
2746 else if (!strcasecmp (show->data, "console"))
2747 gagflags.showflags |= GAGCONSOLE;
2748 else if (!strcasecmp (show->data, "all"))
2749 gagflags.showflags |= GAGCONSOLE | GAGUSER;
2750 else if (!strcasecmp (show->data, "none"))
2754 "unrecognized flag %s: must be in {user,console,all,none}\n",
2763 code = pioctl_utf8(0, VIOC_GAG, &blob, 1);
2772 CheckVolumesCmd(struct cmd_syndesc *as, void *arock)
2775 struct ViceIoctl blob;
2779 code = pioctl_utf8(0, VIOCCKBACK, &blob, 1);
2784 printf("All volumeID/name mappings checked.\n");
2790 SetCacheSizeCmd(struct cmd_syndesc *as, void *arock)
2793 struct ViceIoctl blob;
2798 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2803 fprintf (stderr,"Permission denied: requires root access.\n");
2808 if (!as->parms[0].items && !as->parms[1].items) {
2809 fprintf(stderr,"%s: syntax error in set cache size cmd.\n", pn);
2812 if (as->parms[0].items) {
2813 code = util_GetHumanInt32(as->parms[0].items->data, &temp);
2815 fprintf(stderr,"%s: bad integer specified for cache size.\n", pn);
2820 blob.in = (char *) &temp;
2821 blob.in_size = sizeof(afs_int32);
2823 code = pioctl_utf8(0, VIOCSETCACHESIZE, &blob, 1);
2825 Die(errno, (char *) 0);
2829 printf("New cache size set.\n");
2834 GetCacheParmsCmd(struct cmd_syndesc *as, void *arock)
2837 struct ViceIoctl blob;
2838 cm_cacheParms_t parms;
2840 memset(&parms, 0, sizeof(parms));
2843 blob.out_size = sizeof(parms);
2844 blob.out = (char *) &parms;
2845 code = pioctl_utf8(0, VIOCGETCACHEPARMS, &blob, 1);
2846 if (code || blob.out_size != sizeof(parms)) {
2851 printf("AFS using %I64u of the cache's available %I64u 1K byte blocks.\n",
2852 parms.parms[1], parms.parms[0]);
2853 if (parms.parms[1] > parms.parms[0])
2854 printf("[Cache guideline temporarily deliberately exceeded; it will be adjusted down but you may wish to increase the cache size.]\n");
2859 ListCellsCmd(struct cmd_syndesc *as, void *arock)
2862 afs_int32 i, j, *lp, magic, size;
2864 afs_int32 addr, maxa = AFS_OMAXHOSTS;
2865 struct ViceIoctl blob;
2869 resolve = !(as->parms[0].items); /* -numeric */
2871 for(i=0;i<1000;i++) {
2874 memcpy(tp, &i, sizeof(afs_int32));
2876 err = memcpy_s(tp, sizeof(space), &i, sizeof(afs_int32));
2878 fprintf (stderr, "memcpy_s failure on tp");
2882 tp = (char *)(space + sizeof(afs_int32));
2883 lp = (afs_int32 *)tp;
2885 size = sizeof(afs_int32) + sizeof(afs_int32);
2886 blob.out_size = AFS_PIOCTL_MAXSIZE;
2887 blob.in_size = sizeof(afs_int32);
2890 code = pioctl_utf8(0, VIOCGETCELL, &blob, 1);
2893 break; /* done with the list */
2899 memcpy(&magic, tp, sizeof(afs_int32));
2901 err = memcpy_s(&magic, sizeof(magic), tp, sizeof(afs_int32));
2903 fprintf (stderr, "memcpy_s failure on magic");
2907 if (magic == 0x12345678) {
2908 maxa = AFS_MAXHOSTS;
2909 tp += sizeof(afs_int32);
2911 printf("Cell %s on hosts", tp+maxa*sizeof(afs_int32));
2912 for(j=0; j < maxa && j*sizeof(afs_int32) < AFS_PIOCTL_MAXSIZE; j++) {
2913 char *name, tbuffer[20];
2915 memcpy(&addr, tp + j*sizeof(afs_int32), sizeof(afs_int32));
2917 err = memcpy_s(&addr, sizeof(addr), tp + j*sizeof(afs_int32), sizeof(afs_int32));
2919 fprintf (stderr, "memcpy_s failure on addr");
2927 name = hostutil_GetNameByINet(addr);
2930 if( FAILED(StringCbPrintf(tbuffer, sizeof(tbuffer), "%d.%d.%d.%d", (addr >> 24) & 0xff,
2931 (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff))) {
2932 fprintf (stderr, "tbuffer - cannot be populated");
2937 printf(" %s", name);
2946 ListAliasesCmd(struct cmd_syndesc *as, void *arock)
2949 char *tp, *aliasName, *realName;
2950 struct ViceIoctl blob;
2957 memcpy(tp, &i, sizeof(afs_int32));
2959 err = memcpy_s(tp, sizeof(space), &i, sizeof(afs_int32));
2961 fprintf (stderr, "memcpy_s failure on tp");
2965 blob.out_size = AFS_PIOCTL_MAXSIZE;
2966 blob.in_size = sizeof(afs_int32);
2969 code = pioctl_utf8(0, VIOC_GETALIAS, &blob, 1);
2972 break; /* done with the list */
2976 space[blob.out_size - 1] = '\0';
2979 if( FAILED(StringCbLength(aliasName, sizeof(space), &len))) {
2980 fprintf (stderr, "StringCbLength failure on aliasName");
2985 printf("Alias %s for cell %s\n", aliasName, realName);
2991 CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
2994 struct ViceIoctl blob;
2995 struct cmd_item *ti;
2997 struct hostent *thp;
3001 ti = as->parms[0].items;
3004 thp = hostutil_GetHostByName(ti->data);
3006 fprintf(stderr, "host %s not found in host table.\n", ti->data);
3010 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
3012 err = memcpy_s(&hostAddr, sizeof(hostAddr), thp->h_addr, sizeof(afs_int32));
3014 fprintf (stderr, "memcpy_s failure on hostAddr");
3019 hostAddr = 0; /* means don't set host */
3020 setp = 0; /* aren't setting host */
3023 /* now do operation */
3024 blob.in_size = sizeof(afs_int32);
3025 blob.out_size = sizeof(afs_int32);
3026 blob.in = (char *) &hostAddr;
3027 blob.out = (char *) &hostAddr;
3029 code = pioctl_utf8(0, VIOC_CBADDR, &blob, 1);
3039 NewCellCmd(struct cmd_syndesc *as, void *arock)
3041 afs_uint32 code, linkedstate=0, size=0, count=0, *lp;
3042 afs_uint32 usedns=0, useregistry=0;
3043 struct ViceIoctl blob;
3044 struct cmd_item *ti;
3045 char *tp, *cellname=0, *linked_cellname=0;
3046 afs_uint32 fsport = 0, vlport = 0;
3047 size_t destRemaining;
3050 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3054 /* if there is no cell specified, use old Windows behavior */
3055 if (as->parms[0].items == NULL) {
3057 blob.in = (char *) 0;
3058 blob.out_size = AFS_PIOCTL_MAXSIZE;
3061 code = pioctl_utf8((char *) 0, VIOCNEWCELL, &blob, 1);
3064 Die(errno, (char *) 0);
3068 printf("Cell servers information refreshed\n");
3071 cellname = as->parms[0].items->data;
3074 if (as->parms[2].items) {
3076 * Link the cell, for the purposes of volume location, to the specified
3079 linked_cellname = as->parms[2].items->data;
3083 if (as->parms[3].items) {
3084 code = util_GetInt32(as->parms[2].items->data, &vlport);
3086 fprintf(stderr,"fs: bad integer specified for the fileserver port.\n");
3090 if (as->parms[4].items) {
3091 code = util_GetInt32(as->parms[3].items->data, &fsport);
3093 fprintf(stderr,"fs: bad integer specified for the vldb server port.\n");
3098 if (as->parms[5].items) {
3102 if (as->parms[6].items) {
3106 /* Count the number of hostnames */
3107 for (ti=as->parms[1].items; ti && count < AFS_MAXHOSTS; ti=ti->next, count++);
3109 if (!usedns && count == 0) {
3110 fprintf( stderr, "fs: at least one vldb server must be specified.");
3114 if (count > AFS_MAXHOSTS) {
3115 fprintf( stderr, "fs: at most %u servers may be specified.", AFS_MAXHOSTS);
3120 * The pioctl data buffer consists of the following structure:
3123 * afs_uint32 alternative fs port
3124 * afs_uint32 alternative vl port
3125 * afs_uint32 count of vldb servers
3128 * n * char[] hostnames
3131 memset(space, 0, sizeof(space));
3133 lp = (afs_uint32 *)tp;
3137 *lp |= VIOC_NEWCELL2_FLAG_USEDNS;
3140 *lp |= VIOC_NEWCELL2_FLAG_USEREG;
3143 *lp |= VIOC_NEWCELL2_FLAG_LINKED;
3152 /* count of server names */
3155 /* Switch back to char pointer */
3158 /* Add nul-terminated cellname */
3159 destRemaining = sizeof(space) - (tp - space);
3160 if( FAILED(StringCbCopyEx( tp,
3162 as->parms[0].items->data,
3165 STRSAFE_FILL_ON_FAILURE))) {
3166 fprintf (stderr, " not enough space for cellname");
3169 /* Move beyond the terminating nul */
3171 destRemaining -= sizeof(char);
3173 /* Add nul-terminated linkname */
3174 if( FAILED(StringCbCopyEx( tp,
3176 linkedstate ? linked_cellname : "",
3179 STRSAFE_FILL_ON_FAILURE))) {
3180 fprintf (stderr, " not enough space for linked cellname");
3183 /* Move beyond the terminating nul */
3185 destRemaining -= sizeof(char);
3187 /* Add the servers */
3188 for (ti=as->parms[1].items; ti; ti=ti->next) {
3189 if( FAILED(StringCbCopyEx( tp,
3194 STRSAFE_FILL_ON_FAILURE))) {
3195 fprintf (stderr, " not enough space for server %s", ti->data);
3198 /* Move beyond the terminating nul */
3200 destRemaining -= sizeof(char);
3203 blob.in_size = (tp - space);
3207 code = pioctl_utf8(NULL, VIOCNEWCELL2, &blob, 1);
3210 Die(errno, as->parms[0].items->data);
3214 printf("Cell servers information for %s added or updated.\n",
3215 as->parms[0].items->data);
3221 NewAliasCmd(struct cmd_syndesc *as, void *arock)
3224 struct ViceIoctl blob;
3226 char *aliasName, *realName;
3227 size_t destRemaining = sizeof(space);
3229 /* Setup and do the NEWALIAS pioctl call */
3230 aliasName = as->parms[0].items->data;
3231 realName = as->parms[1].items->data;
3233 if( FAILED(StringCbCopyEx(tp, destRemaining, aliasName, &tp, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3234 fprintf (stderr, "tp - not enough space");
3238 destRemaining -= sizeof(char);
3239 if( FAILED(StringCbCopyEx(tp, destRemaining, realName, &tp, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3240 fprintf (stderr, "tp - not enough space");
3244 destRemaining -= sizeof(char);
3246 blob.in_size = tp - space;
3250 code = pioctl_utf8(0, VIOC_NEWALIAS, &blob, 1);
3252 if (errno == EEXIST) {
3254 "%s: cell name `%s' in use by an existing cell.\n", pn,
3266 WhichCellCmd(struct cmd_syndesc *as, void *arock)
3269 struct cmd_item *ti;
3270 struct ViceIoctl blob;
3273 cm_ioctlQueryOptions_t options;
3275 if (as->parms[1].items)
3278 SetDotDefault(&as->parms[0].items);
3279 for(ti=as->parms[0].items; ti; ti=ti->next) {
3281 afs_uint32 filetype;
3282 char cell[CELL_MAXNAMELEN];
3285 memset(&fid, 0, sizeof(fid));
3286 memset(&options, 0, sizeof(options));
3288 options.size = sizeof(options);
3289 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
3290 options.literal = literal;
3291 blob.in_size = options.size; /* no variable length data */
3294 blob.out_size = sizeof(cm_fid_t);
3295 blob.out = (char *) &fid;
3296 if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1) &&
3297 blob.out_size == sizeof(cm_fid_t)) {
3298 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
3301 Die(errno, ti->data);
3306 blob.out_size = sizeof(filetype);
3307 blob.out = &filetype;
3309 code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
3310 if (code || blob.out_size != sizeof(filetype)) {
3311 Die(errno, ti->data);
3315 blob.out_size = CELL_MAXNAMELEN;
3318 code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
3320 if (errno == ENOENT)
3321 fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
3323 Die(errno, ti->data);
3327 cell[CELL_MAXNAMELEN - 1] = '\0';
3328 printf("%s %s lives in cell '%s'\n",
3329 filetypestr(filetype),
3336 WSCellCmd(struct cmd_syndesc *as, void *arock)
3339 struct ViceIoctl blob;
3343 blob.out_size = AFS_PIOCTL_MAXSIZE;
3346 code = pioctl_utf8(NULL, VIOC_GET_WS_CELL, &blob, 1);
3352 space[AFS_PIOCTL_MAXSIZE - 1] = '\0';
3353 printf("This workstation belongs to cell '%s'\n", space);
3359 PrimaryCellCmd(struct cmd_syndesc *as, void *arock)
3361 fprintf(stderr,"This command is obsolete, as is the concept of a primary token.\n");
3366 #ifndef AFS_NT40_ENV
3368 MonitorCmd(struct cmd_syndesc *as, void *arock)
3371 struct ViceIoctl blob;
3372 struct cmd_item *ti;
3374 struct hostent *thp;
3379 ti = as->parms[0].items;
3383 if (!strcmp(ti->data, "off")) {
3384 hostAddr = 0xffffffff;
3386 thp = hostutil_GetHostByName(ti->data);
3388 if (!strcmp(ti->data, "localhost")) {
3389 fprintf(stderr,"localhost not in host table, assuming 127.0.0.1\n");
3390 hostAddr = htonl(0x7f000001);
3392 fprintf(stderr,"host %s not found in host table.\n", ti->data);
3397 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
3399 err = memcpy_s(&hostAddr, sizeof(hostAddr), thp->h_addr, sizeof(afs_int32));
3401 fprintf (stderr, "memcpy_s failure on hostAddr");
3408 hostAddr = 0; /* means don't set host */
3409 setp = 0; /* aren't setting host */
3412 /* now do operation */
3413 blob.in_size = sizeof(afs_int32);
3414 blob.out_size = sizeof(afs_int32);
3415 blob.in = (char *) &hostAddr;
3416 blob.out = (char *) &hostAddr;
3417 code = pioctl_utf8(0, VIOC_AFS_MARINER_HOST, &blob, 1);
3418 if (code || blob.out_size != sizeof(afs_int32)) {
3423 printf("%s: new monitor host set.\n", pn);
3425 /* now decode old address */
3426 if (hostAddr == 0xffffffff) {
3427 printf("Cache monitoring is currently disabled.\n");
3429 tp = hostutil_GetNameByINet(hostAddr);
3430 printf("Using host %s for monitor services.\n", tp);
3435 #endif /* AFS_NT40_ENV */
3438 SysNameCmd(struct cmd_syndesc *as, void *arock)
3441 struct ViceIoctl blob;
3442 struct cmd_item *ti;
3443 char *input = space;
3446 size_t destRemaining = sizeof(space);
3449 ti = as->parms[0].items;
3453 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3458 fprintf (stderr,"Permission denied: requires root access.\n");
3466 blob.out_size = AFS_PIOCTL_MAXSIZE;
3467 blob.in_size = sizeof(afs_int32);
3469 memcpy(input, &setp, sizeof(afs_int32));
3471 err = memcpy_s(input, destRemaining, &setp, sizeof(afs_int32));
3473 fprintf (stderr, "memcpy_s failure on input");
3477 input += sizeof(afs_int32);
3478 destRemaining -= sizeof(afs_int32);
3479 for (; ti; ti = ti->next) {
3481 if( FAILED(StringCbCopyEx(input, destRemaining, ti->data, &input, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3482 fprintf(stderr, "%s: sysname%s too long.\n", pn,
3483 setp > 1 ? "s" : "");
3487 destRemaining -= sizeof(char);
3489 blob.in_size = (input - space) * sizeof(char);
3491 memcpy(space, &setp, sizeof(afs_int32));
3493 err = memcpy_s(space, sizeof(space), &setp, sizeof(afs_int32));
3495 fprintf (stderr, "memcpy_s failure on space");
3500 code = pioctl_utf8(0, VIOC_AFS_SYSNAME, &blob, 1);
3506 printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
3512 memcpy(&setp, input, sizeof(afs_int32));
3514 err = memcpy_s(&setp, sizeof(setp), input, sizeof(afs_int32));
3516 fprintf (stderr, "memcpy_s failure on setp");
3520 input += sizeof(afs_int32);
3522 fprintf(stderr,"No sysname name value was found\n");
3525 space[blob.out_size - 1] = '\0';
3526 printf("Current sysname%s is", setp > 1 ? " list" : "");
3527 for (; setp > 0; --setp ) {
3528 printf(" \'%s\'", input);
3529 if( FAILED(StringCbLength(input, sizeof(space) - (input - space), &len))) {
3530 fprintf (stderr, "StringCbLength failure on input");
3539 #ifndef AFS_NT40_ENV
3540 static char *exported_types[] = {"null", "nfs", ""};
3541 static int ExportAfsCmd(struct cmd_syndesc *as, void *arock)
3544 struct ViceIoctl blob;
3545 struct cmd_item *ti;
3546 int export = 0, type = 0, mode = 0, exp = 0, gstat = 0;
3547 int exportcall, pwsync = 0, smounts = 0;
3551 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3556 fprintf (stderr,"Permission denied: requires root access.\n");
3561 ti = as->parms[0].items;
3562 if (strcmp(ti->data, "nfs") == 0)
3563 type = 0x71; /* NFS */
3566 "Invalid exporter type, '%s', Only the 'nfs' exporter is currently supported\n", ti->data);
3569 ti = as->parms[1].items;
3571 if (strcmp(ti->data, "on") == 0)
3573 else if (strcmp(ti->data, "off") == 0)
3576 fprintf(stderr, "Illegal argument %s\n", ti->data);
3581 if (ti = as->parms[2].items) { /* -noconvert */
3582 if (strcmp(ti->data, "on") == 0)
3584 else if (strcmp(ti->data, "off") == 0)
3587 fprintf(stderr, "Illegal argument %s\n", ti->data);
3591 if (ti = as->parms[3].items) { /* -uidcheck */
3592 if (strcmp(ti->data, "on") == 0)
3594 else if (strcmp(ti->data, "off") == 0)
3597 fprintf(stderr, "Illegal argument %s\n", ti->data);
3601 if (ti = as->parms[4].items) { /* -submounts */
3602 if (strcmp(ti->data, "on") == 0)
3604 else if (strcmp(ti->data, "off") == 0)
3607 fprintf(stderr, "Illegal argument %s\n", ti->data);
3611 exportcall = (type << 24) | (mode << 6) | (pwsync << 4) | (smounts << 2) | export;
3614 blob.in = (char *) &exportcall;
3615 blob.in_size = sizeof(afs_int32);
3616 blob.out = (char *) &exportcall;
3617 blob.out_size = sizeof(afs_int32);
3618 code = pioctl_utf8(0, VIOC_EXPORTAFS, &blob, 1);
3620 if (errno == ENODEV) {
3622 "Sorry, the %s-exporter type is currently not supported on this AFS client\n", exported_types[type]);
3629 if (exportcall & 1) {
3630 printf("'%s' translator is enabled with the following options:\n\tRunning in %s mode\n\tRunning in %s mode\n\t%s\n",
3631 exported_types[type], (exportcall & 2 ? "strict unix" : "convert owner mode bits to world/other"),
3632 (exportcall & 4 ? "strict 'passwd sync'" : "no 'passwd sync'"),
3633 (exportcall & 8 ? "Allow mounts of /afs/.. subdirs" : "Only mounts to /afs allowed"));
3635 printf("'%s' translator is disabled\n", exported_types[type]);