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 <afs/param.h>
12 #include <afs/com_err.h>
24 #include <rx/rx_globals.h>
28 #include <afs/afs_consts.h>
29 #include <afs/cellconfig.h>
30 #include <afs/ptserver.h>
31 #include <afs/ptuser.h>
32 #include <afs/volser.h>
33 #include <WINNT\afsreg.h>
42 #define MAXINSIZE 1300 /* pioctl complains if data is larger than this */
43 #define VMSGSIZE 128 /* size of msg buf in volume hdr */
44 #define CELL_MAXNAMELEN 256
45 #define MAXHOSTCHARS 64
47 static char space[AFS_PIOCTL_MAXSIZE];
48 static char tspace[1024];
50 static struct ubik_client *uclient;
52 static int GetClientAddrsCmd(struct cmd_syndesc *asp, void *arock);
53 static int SetClientAddrsCmd(struct cmd_syndesc *asp, void *arock);
54 static int FlushMountCmd(struct cmd_syndesc *asp, void *arock);
55 static int RxStatProcCmd(struct cmd_syndesc *asp, void *arock);
56 static int RxStatPeerCmd(struct cmd_syndesc *asp, void *arock);
58 extern struct cmd_syndesc *cmd_CreateSyntax();
60 static int MemDumpCmd(struct cmd_syndesc *asp, void *arock);
61 static int CSCPolicyCmd(struct cmd_syndesc *asp, void *arock);
62 static int MiniDumpCmd(struct cmd_syndesc *asp, void *arock);
64 static char pn[] = "fs";
65 static int rxInitDone = 0;
68 * Character to use between name and rights in printed representation for
71 #define DFS_SEPARATOR ' '
73 typedef char sec_rgy_name_t[1025]; /* A DCE definition */
76 int dfs; /* Originally true if a dfs acl; now also the type
77 * of the acl (1, 2, or 3, corresponding to object,
78 * initial dir, or initial object). */
79 sec_rgy_name_t cell; /* DFS cell name */
82 struct AclEntry *pluslist;
83 struct AclEntry *minuslist;
87 struct AclEntry *next;
93 ZapAcl (struct Acl *acl)
98 ZapList(acl->pluslist);
99 ZapList(acl->minuslist);
104 * Mods for the AFS/DFS protocol translator.
106 * DFS rights. It's ugly to put these definitions here, but they
107 * *cannot* change, because they're part of the wire protocol.
108 * In any event, the protocol translator will guarantee these
109 * assignments for AFS cache managers.
111 #define DFS_READ 0x01
112 #define DFS_WRITE 0x02
113 #define DFS_EXECUTE 0x04
114 #define DFS_CONTROL 0x08
115 #define DFS_INSERT 0x10
116 #define DFS_DELETE 0x20
118 /* the application definable ones (backwards from AFS) */
119 #define DFS_USR0 0x80000000 /* "A" bit */
120 #define DFS_USR1 0x40000000 /* "B" bit */
121 #define DFS_USR2 0x20000000 /* "C" bit */
122 #define DFS_USR3 0x10000000 /* "D" bit */
123 #define DFS_USR4 0x08000000 /* "E" bit */
124 #define DFS_USR5 0x04000000 /* "F" bit */
125 #define DFS_USR6 0x02000000 /* "G" bit */
126 #define DFS_USR7 0x01000000 /* "H" bit */
127 #define DFS_USRALL (DFS_USR0 | DFS_USR1 | DFS_USR2 | DFS_USR3 |\
128 DFS_USR4 | DFS_USR5 | DFS_USR6 | DFS_USR7)
131 * Offset of -id switch in command structure for various commands.
132 * The -if switch is the next switch always.
134 static int parm_setacl_id, parm_copyacl_id, parm_listacl_id;
137 * Determine whether either the -id or -if switches are present, and
138 * return 0, 1 or 2, as appropriate. Abort if both switches are present.
140 /* int id; Offset of -id switch; -if is next switch */
142 getidf(struct cmd_syndesc *as, int id)
146 if (as->parms[id].items) {
149 if (as->parms[id + 1].items) {
154 "%s: you may specify either -id or -if, but not both switches\n",
162 PRights(afs_int32 arights, int dfs)
165 if (arights & PRSFS_READ)
167 if (arights & PRSFS_LOOKUP)
169 if (arights & PRSFS_INSERT)
171 if (arights & PRSFS_DELETE)
173 if (arights & PRSFS_WRITE)
175 if (arights & PRSFS_LOCK)
177 if (arights & PRSFS_ADMINISTER)
179 if (arights & PRSFS_USR0)
181 if (arights & PRSFS_USR1)
183 if (arights & PRSFS_USR2)
185 if (arights & PRSFS_USR3)
187 if (arights & PRSFS_USR4)
189 if (arights & PRSFS_USR5)
191 if (arights & PRSFS_USR6)
193 if (arights & PRSFS_USR7)
196 if (arights & DFS_READ)
200 if (arights & DFS_WRITE)
204 if (arights & DFS_EXECUTE)
208 if (arights & DFS_CONTROL)
212 if (arights & DFS_INSERT)
216 if (arights & DFS_DELETE)
220 if (arights & (DFS_USRALL))
222 if (arights & DFS_USR0)
224 if (arights & DFS_USR1)
226 if (arights & DFS_USR2)
228 if (arights & DFS_USR3)
230 if (arights & DFS_USR4)
232 if (arights & DFS_USR5)
234 if (arights & DFS_USR6)
236 if (arights & DFS_USR7)
242 /* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */
246 struct ViceIoctl blob;
247 cm_ioctlQueryOptions_t options;
251 memset(&options, 0, sizeof(options));
252 options.size = sizeof(options);
253 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
255 blob.in_size = options.size; /* no variable length data */
257 blob.out_size = sizeof(cm_fid_t);
258 blob.out = (char *) &fid;
260 code = pioctl_utf8(apath, VIOCGETFID, &blob, 1);
262 if ((errno == EINVAL) || (errno == ENOENT))
269 IsFreelanceRoot(char *apath)
271 struct ViceIoctl blob;
275 blob.out_size = AFS_PIOCTL_MAXSIZE;
278 code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
280 return !cm_strnicmp_utf8N("Freelance.Local.Root",space, blob.out_size);
282 return 1; /* assume it is because it is more restrictive that way */
285 /* return a static pointer to a buffer */
290 if( FAILED(StringCbCopy(tspace, sizeof(tspace), apath))) {
291 fprintf (stderr, "tspace - not enough space");
294 tp = strrchr(tspace, '\\');
296 *(tp+1) = 0; /* lv trailing slash so Parent("k:\foo") is "k:\" not "k:" */
299 fs_ExtractDriveLetter(apath, tspace);
300 if( FAILED(StringCbCat(tspace, sizeof(tspace), "."))) {
301 fprintf (stderr, "tspace - not enough space");
308 enum rtype {add, destroy, deny};
311 Convert(char *arights, int dfs, enum rtype *rtypep)
316 *rtypep = add; /* add rights, by default */
319 if (!strcmp(arights, "null")) {
323 if (!strcmp(arights,"read"))
324 return DFS_READ | DFS_EXECUTE;
325 if (!strcmp(arights, "write"))
326 return DFS_READ | DFS_EXECUTE | DFS_INSERT | DFS_DELETE |
328 if (!strcmp(arights, "all"))
329 return DFS_READ | DFS_EXECUTE | DFS_INSERT | DFS_DELETE |
330 DFS_WRITE | DFS_CONTROL;
332 if (!strcmp(arights,"read"))
333 return PRSFS_READ | PRSFS_LOOKUP;
334 if (!strcmp(arights, "write"))
335 return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
336 PRSFS_WRITE | PRSFS_LOCK;
337 if (!strcmp(arights, "mail"))
338 return PRSFS_INSERT | PRSFS_LOCK | PRSFS_LOOKUP;
339 if (!strcmp(arights, "all"))
340 return PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT | PRSFS_DELETE |
341 PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
343 if (!strcmp(arights, "none")) {
344 *rtypep = destroy; /* Remove entire entry */
348 for(; (tc = *arights) != '\0'; arights++) {
381 fprintf(stderr, "%s: illegal DFS rights character '%c'.\n",
389 mode |= PRSFS_LOOKUP;
391 mode |= PRSFS_INSERT;
393 mode |= PRSFS_DELETE;
399 mode |= PRSFS_ADMINISTER;
417 fprintf(stderr, "%s: illegal rights character '%c'.\n", pn,
426 static struct AclEntry *
427 FindList (struct AclEntry *alist, char *aname)
430 if (!strcasecmp(alist->name, aname))
437 /* if no parm specified in a particular slot, set parm to be "." instead */
439 SetDotDefault(struct cmd_item **aitemp)
445 return; /* already has value */
446 /* otherwise, allocate an item representing "." */
447 ti = (struct cmd_item *) malloc(sizeof(struct cmd_item));
449 ti->next = (struct cmd_item *) 0;
450 ti->data = (char *) malloc(len_data);
452 if( FAILED(StringCbCopy(ti->data, len_data, "."))) {
453 fprintf (stderr, "data - not enough space");
460 ChangeList (struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights)
462 struct AclEntry *tlist;
463 tlist = (plus ? al->pluslist : al->minuslist);
464 tlist = FindList (tlist, aname);
466 /* Found the item already in the list. */
467 tlist->rights = arights;
469 al->nplus -= PruneList(&al->pluslist, al->dfs);
471 al->nminus -= PruneList(&al->minuslist, al->dfs);
474 /* Otherwise we make a new item and plug in the new data. */
475 tlist = (struct AclEntry *) malloc(sizeof (struct AclEntry));
477 if( FAILED(StringCbCopy(tlist->name, sizeof(tlist->name), aname))) {
478 fprintf (stderr, "name - not enough space");
481 tlist->rights = arights;
483 tlist->next = al->pluslist;
484 al->pluslist = tlist;
486 if (arights == 0 || arights == -1)
487 al->nplus -= PruneList(&al->pluslist, al->dfs);
489 tlist->next = al->minuslist;
490 al->minuslist = tlist;
493 al->nminus -= PruneList(&al->minuslist, al->dfs);
498 ZapList (struct AclEntry *alist)
500 struct AclEntry *tp, *np;
501 for (tp = alist; tp; tp = np) {
508 PruneList (struct AclEntry **ae, int dfs)
510 struct AclEntry **lp;
511 struct AclEntry *te, *ne;
515 for(te = *ae;te;te=ne) {
516 if ((!dfs && te->rights == 0) || te->rights == -1) {
530 SkipLine (char *astr)
539 * Create an empty acl, taking into account whether the acl pointed
540 * to by astr is an AFS or DFS acl. Only parse this minimally, so we
541 * can recover from problems caused by bogus ACL's (in that case, always
542 * assume that the acl is AFS: for DFS, the user can always resort to
543 * acl_edit, but for AFS there may be no other way out).
551 tp = (struct Acl *)malloc(sizeof (struct Acl));
553 tp->nplus = tp->nminus = 0;
554 tp->pluslist = tp->minuslist = 0;
557 if (astr == NULL || sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell) <= 0) {
562 if (astr == NULL || sscanf_s(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell, sizeof(tp->cell)) <= 0) {
571 ParseAcl (char *astr, int astr_size)
573 int nplus, nminus, i, trights, ret;
576 struct AclEntry *first, *next, *last, *tl;
580 if( FAILED(StringCbLength(astr, astr_size, &len))) {
581 fprintf (stderr, "StringCbLength failure on astr");
584 if (astr == NULL || len == 0)
588 ret = sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
590 ret = sscanf_s(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell, sizeof(ta->cell));
596 astr = SkipLine(astr);
598 ret = sscanf(astr, "%d", &ta->nminus);
600 ret = sscanf_s(astr, "%d", &ta->nminus);
606 astr = SkipLine(astr);
613 for(i=0;i<nplus;i++) {
615 ret = sscanf(astr, "%100s %d", tname, &trights);
617 ret = sscanf_s(astr, "%100s %d", tname, sizeof(tname), &trights);
621 astr = SkipLine(astr);
622 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
627 if( FAILED(StringCbCopy(tl->name, sizeof(tl->name), tname))) {
628 fprintf (stderr, "name - not enough space");
631 tl->rights = trights;
637 ta->pluslist = first;
641 for(i=0;i<nminus;i++) {
643 ret = sscanf(astr, "%100s %d", tname, &trights);
645 ret = sscanf_s(astr, "%100s %d", tname, sizeof(tname), &trights);
649 astr = SkipLine(astr);
650 tl = (struct AclEntry *) malloc(sizeof (struct AclEntry));
655 if( FAILED(StringCbCopy(tl->name, sizeof(tl->name), tname))) {
656 fprintf (stderr, "name - not enough space");
659 tl->rights = trights;
665 ta->minuslist = first;
670 for (;first; first = next) {
674 first = ta->pluslist;
677 for (;first; first = next) {
686 PrintStatus(VolumeStatus *status, char *name, char *motd, char *offmsg)
688 printf("Volume status for vid = %u named %s is\n",status->Vid, name);
690 printf("Current offline message is %s\n",offmsg);
692 printf("Current message of the day is %s\n",motd);
693 printf("Current disk quota is ");
694 if (status->MaxQuota != 0)
695 printf("%d\n", status->MaxQuota);
697 printf("unlimited\n");
698 printf("Current blocks used are %d\n",status->BlocksInUse);
699 printf("The partition has %d blocks available out of %d\n",
700 status->PartBlocksAvail, status->PartMaxBlocks);
705 QuickPrintStatus(VolumeStatus *status, char *name)
707 double QuotaUsed =0.0;
708 double PartUsed =0.0;
710 printf("%-25.25s",name);
712 if (status->MaxQuota != 0) {
713 printf(" %10d %10d", status->MaxQuota, status->BlocksInUse);
714 QuotaUsed = ((((double)status->BlocksInUse)/status->MaxQuota) * 100.0);
716 printf(" no limit %10d", status->BlocksInUse);
718 if (QuotaUsed > 90.0){
719 printf(" %5.0f%%<<", QuotaUsed);
722 printf(" %5.0f%% ", QuotaUsed);
723 PartUsed = (100.0 - ((((double)status->PartBlocksAvail)/status->PartMaxBlocks) * 100.0));
724 if (PartUsed > 97.0){
725 printf(" %9.0f%%<<", PartUsed);
728 printf(" %9.0f%% ", PartUsed);
730 printf(" <<WARNING\n");
737 QuickPrintSpace(VolumeStatus *status, char *name)
739 double PartUsed =0.0;
741 printf("%-25.25s",name);
743 printf("%10d%10d%10d", status->PartMaxBlocks, status->PartMaxBlocks - status->PartBlocksAvail, status->PartBlocksAvail);
745 PartUsed = (100.0 - ((((double)status->PartBlocksAvail)/status->PartMaxBlocks) * 100.0));
746 if (PartUsed > 90.0){
747 printf(" %4.0f%%<<", PartUsed);
750 printf(" %4.0f%% ", PartUsed);
752 printf(" <<WARNING\n");
759 AclToString(struct Acl *acl)
761 static char mydata[AFS_PIOCTL_MAXSIZE];
762 char tstring[AFS_PIOCTL_MAXSIZE];
767 if( FAILED(StringCbPrintf(dfsstring, sizeof(dfsstring), " dfs:%d %s", acl->dfs, acl->cell))) {
768 fprintf (stderr, "dfsstring - cannot be populated");
774 if( FAILED(StringCbPrintf(mydata, sizeof(mydata), "%d%s\n%d\n", acl->nplus, dfsstring, acl->nminus))) {
775 fprintf (stderr, "mydata - cannot be populated");
778 for (tp = acl->pluslist;tp;tp=tp->next) {
779 if( FAILED(StringCbPrintf(tstring, sizeof(tstring), "%s %d\n", tp->name, tp->rights))) {
780 fprintf (stderr, "tstring - cannot be populated");
783 if( FAILED(StringCbCat(mydata, sizeof(mydata), tstring))) {
784 fprintf (stderr, "mydata - not enough space");
788 for (tp = acl->minuslist;tp;tp=tp->next) {
789 if( FAILED(StringCbPrintf(tstring, sizeof(tstring), "%s %d\n", tp->name, tp->rights))) {
790 fprintf (stderr, "tstring - cannot be populated");
793 if( FAILED(StringCbCat(mydata, sizeof(mydata), tstring))) {
794 fprintf (stderr, "mydata - not enough space");
801 static DWORD IsFreelance(void)
808 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
809 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
810 if (code == ERROR_SUCCESS) {
811 dummyLen = sizeof(cm_freelanceEnabled);
812 code = RegQueryValueEx(parmKey, "FreelanceClient", NULL, NULL,
813 (BYTE *) &enabled, &dummyLen);
814 RegCloseKey (parmKey);
819 #define NETBIOSNAMESZ 1024
820 static const char * NetbiosName(void)
822 static char buffer[NETBIOSNAMESZ] = "AFS";
828 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
829 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
830 if (code == ERROR_SUCCESS) {
831 dummyLen = sizeof(buffer);
832 code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
834 RegCloseKey (parmKey);
836 if( FAILED(StringCbCopy(buffer, sizeof(buffer), "AFS"))) {
837 fprintf (stderr, "buffer - not enough space");
844 #define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
846 static BOOL IsAdmin (void)
848 static BOOL fAdmin = FALSE;
849 static BOOL fTested = FALSE;
853 /* Obtain the SID for the AFS client admin group. If the group does
854 * not exist, then assume we have AFS client admin privileges.
856 PSID psidAdmin = NULL;
857 DWORD dwSize, dwSize2;
858 char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
859 char *pszRefDomain = NULL;
860 SID_NAME_USE snu = SidTypeGroup;
862 dwSize = sizeof(pszAdminGroup);
864 if (!GetComputerName(pszAdminGroup, &dwSize)) {
865 /* Can't get computer name. We return false in this case.
866 Retain fAdmin and fTested. This shouldn't happen.*/
873 if( FAILED(StringCbCat(pszAdminGroup, MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2,"\\"))) {
874 fprintf (stderr, "pszAdminGroup - not enough space");
877 if( FAILED(StringCbCat(pszAdminGroup, MAX_COMPUTERNAME_LENGTH +
878 sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2, AFSCLIENT_ADMIN_GROUPNAME))) {
879 fprintf (stderr, "pszAdminGroup - not enough space");
883 LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
884 /* that should always fail. */
886 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
887 /* if we can't find the group, then we allow the operation */
892 if (dwSize == 0 || dwSize2 == 0) {
898 psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
900 pszRefDomain = (char *)malloc(dwSize2);
901 assert(pszRefDomain);
903 if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
904 /* We can't lookup the group now even though we looked it up earlier.
905 Could this happen? */
908 /* Then open our current ProcessToken */
911 if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
914 if (!CheckTokenMembership(hToken, psidAdmin, &fAdmin)) {
915 /* We'll have to allocate a chunk of memory to store the list of
916 * groups to which this user belongs; find out how much memory
920 PTOKEN_GROUPS pGroups;
922 GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
924 pGroups = (PTOKEN_GROUPS)malloc(dwSize);
927 /* Allocate that buffer, and read in the list of groups. */
928 if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
930 /* Look through the list of group SIDs and see if any of them
931 * matches the AFS Client Admin group SID.
934 for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
936 if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
946 /* if do not have permission because we were not explicitly listed
947 * in the Admin Client Group let's see if we are the SYSTEM account
950 PTOKEN_USER pTokenUser;
951 SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
952 PSID pSidLocalSystem = 0;
955 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
957 pTokenUser = (PTOKEN_USER)malloc(dwSize);
960 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize))
961 gle = GetLastError();
963 if (AllocateAndInitializeSid( &SIDAuth, 1,
964 SECURITY_LOCAL_SYSTEM_RID,
968 if (EqualSid(pTokenUser->User.Sid, pSidLocalSystem)) {
972 FreeSid(pSidLocalSystem);
991 SetACLCmd(struct cmd_syndesc *as, void *arock)
994 struct ViceIoctl blob;
996 struct cmd_item *ti, *ui;
1000 int idf = getidf(as, parm_setacl_id);
1004 if (as->parms[2].items)
1008 plusp = !(as->parms[3].items);
1009 for(ti=as->parms[0].items; ti;ti=ti->next) {
1010 blob.out_size = AFS_PIOCTL_MAXSIZE;
1012 blob.in = blob.out = space;
1013 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1015 Die(errno, ti->data);
1021 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1024 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1029 if (!plusp && ta->dfs) {
1031 "fs: %s: you may not use the -negative switch with DFS acl's.\n%s",
1033 "(you may specify \"null\" to revoke all rights, however)\n");
1040 ta = EmptyAcl(space);
1042 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1045 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1050 CleanAcl(ta, ti->data);
1051 for(ui=as->parms[1].items; ui; ui=ui->next->next) {
1055 "%s: Missing second half of user/access pair.\n", pn);
1059 rights = Convert(ui->next->data, ta->dfs, &rtype);
1060 if (rtype == destroy && !ta->dfs) {
1061 struct AclEntry *tlist;
1063 tlist = (plusp ? ta->pluslist : ta->minuslist);
1064 if (!FindList(tlist, ui->data))
1067 if (rtype == deny && !ta->dfs)
1069 if (rtype == destroy && ta->dfs)
1071 ChangeList(ta, plusp, ui->data, rights);
1073 blob.in = AclToString(ta);
1075 if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
1076 fprintf (stderr, "StringCbLength failure on blob.in");
1079 blob.in_size = 1+(long)len;
1080 code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
1082 if (errno == EINVAL) {
1084 static char *fsenv = 0;
1086 fsenv = (char *)getenv("FS_EXPERT");
1088 fprintf(stderr, "fs: \"Invalid argument\" was returned when you tried to store a DFS access list.\n");
1091 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1092 "\nPossible reasons for this include:\n\n",
1093 " -You may have specified an inappropriate combination of rights.\n",
1094 " For example, some DFS-supported filesystems may not allow you to\n",
1095 " drop the \"c\" right from \"user_obj\".\n\n",
1096 " -A mask_obj may be required (it is likely required by the underlying\n",
1097 " filesystem if you try to set anything other than the basic \"user_obj\"\n",
1098 " \"mask_obj\", or \"group_obj\" entries). Unlike acl_edit, the fs command\n",
1099 " does not automatically create or update the mask_obj. Try setting\n",
1100 " the rights \"mask_obj all\" with \"fs sa\" before adding any explicit\n",
1101 " users or groups. You can do this with a single command, such as\n",
1102 " \"fs sa mask_obj all user:somename read\"\n\n",
1103 " -A specified user or group may not exist.\n\n",
1104 " -You may have tried to delete \"user_obj\", \"group_obj\", or \"other_obj\".\n",
1105 " This is probably not allowed by the underlying file system.\n\n",
1106 " -If you add a user or group to a DFS ACL, remember that it must be\n",
1107 " fully specified as \"user:username\" or \"group:groupname\". In addition, there\n",
1108 " may be local requirements on the format of the user or group name.\n",
1109 " Check with your cell administrator.\n\n",
1110 " -Or numerous other possibilities. It would be great if we could be more\n",
1111 " precise about the actual problem, but for various reasons, this is\n",
1112 " impractical via this interface. If you can't figure it out, you\n",
1113 " might try logging into a DCE-equipped machine and use acl_edit (or\n",
1114 " whatever is provided). You may get better results. Good luck!\n\n",
1115 " (You may inhibit this message by setting \"FS_EXPERT\" in your environment)\n");
1119 "%s: Invalid argument, possible reasons include:\n",
1121 fprintf(stderr,"\t-File not in AFS\n");
1123 "\t-Too many users on access control list\n");
1125 "\t-Tried to add non-existent user to access control list\n");
1128 Die(errno, ti->data);
1139 CopyACLCmd(struct cmd_syndesc *as, void *arock)
1142 struct ViceIoctl blob;
1143 struct Acl *fa, *ta = 0;
1144 struct AclEntry *tp;
1145 struct cmd_item *ti;
1147 int idf = getidf(as, parm_copyacl_id);
1151 if (as->parms[2].items)
1155 blob.out_size = AFS_PIOCTL_MAXSIZE;
1157 blob.in = blob.out = space;
1158 code = pioctl_utf8(as->parms[0].items->data, VIOCGETAL, &blob, 1);
1160 Die(errno, as->parms[0].items->data);
1163 fa = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1166 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1167 as->parms[0].items->data);
1170 CleanAcl(fa, as->parms[0].items->data);
1171 for (ti=as->parms[1].items; ti;ti=ti->next) {
1172 blob.out_size = AFS_PIOCTL_MAXSIZE;
1174 blob.in = blob.out = space;
1175 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1177 Die(errno, ti->data);
1184 ta = EmptyAcl(space);
1186 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1189 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1194 CleanAcl(ta, ti->data);
1195 if (ta->dfs != fa->dfs) {
1197 "%s: incompatible file system types: acl not copied to %s; aborted\n",
1203 if (! clear && strcmp(ta->cell, fa->cell) != 0) {
1205 "%s: default DCE cell differs for file %s: use \"-clear\" switch; acl not merged\n",
1210 if( FAILED(StringCbCopy(ta->cell, sizeof(ta->cell), fa->cell))) {
1211 fprintf (stderr, "cell - not enough space");
1215 for (tp = fa->pluslist;tp;tp=tp->next)
1216 ChangeList(ta, 1, tp->name, tp->rights);
1217 for (tp = fa->minuslist;tp;tp=tp->next)
1218 ChangeList(ta, 0, tp->name, tp->rights);
1219 blob.in = AclToString(ta);
1221 if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
1222 fprintf (stderr, "StringCbLength failure on blob.in");
1225 blob.in_size = 1+(long)len;
1226 code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
1228 if (errno == EINVAL) {
1230 "%s: Invalid argument, possible reasons include:\n", pn);
1231 fprintf(stderr,"\t-File not in AFS\n");
1233 Die(errno, ti->data);
1244 /* pioctl_utf8() call to get the cellname of a pathname */
1246 GetCell(char *fname, char *cellname)
1249 struct ViceIoctl blob;
1252 blob.out_size = CELL_MAXNAMELEN;
1253 blob.out = cellname;
1255 code = pioctl_utf8(fname, VIOC_FILE_CELL_NAME, &blob, 1);
1257 cellname[blob.out_size - 1] = '\0';
1261 /* Check if a username is valid: If it contains only digits (or a
1262 * negative sign), then it might be bad. We then query the ptserver
1266 BadName(char *aname, char *fname)
1268 afs_int32 tc, code, id;
1270 char cell[CELL_MAXNAMELEN];
1273 for ( nm = aname; tc = *nm; nm++) {
1274 /* all must be '-' or digit to be bad */
1275 if (tc != '-' && (tc < '0' || tc > '9'))
1279 /* Go to the PRDB and see if this all number username is valid */
1280 code = GetCell(fname, cell);
1284 cm_GetConfigDir(confDir, sizeof(confDir));
1286 pr_Initialize(1, confDir, cell);
1287 code = pr_SNameToId(aname, &id);
1290 /* 1=>Not-valid; 0=>Valid */
1291 return ((!code && (id == ANONYMOUSID)) ? 1 : 0);
1295 /* clean up an access control list of its bad entries; return 1 if we made
1296 any changes to the list, and 0 otherwise */
1298 CleanAcl(struct Acl *aa, char *fname)
1300 struct AclEntry *te, **le, *ne;
1303 /* Don't correct DFS ACL's for now */
1307 /* prune out bad entries */
1308 changes = 0; /* count deleted entries */
1310 for(te = aa->pluslist; te; te=ne) {
1312 if (BadName(te->name, fname)) {
1322 le = &aa->minuslist;
1323 for(te = aa->minuslist; te; te=ne) {
1325 if (BadName(te->name, fname)) {
1339 /* clean up an acl to not have bogus entries */
1341 CleanACLCmd(struct cmd_syndesc *as, void *arock)
1345 struct ViceIoctl blob;
1347 struct cmd_item *ti;
1348 struct AclEntry *te;
1352 SetDotDefault(&as->parms[0].items);
1353 for(ti=as->parms[0].items; ti; ti=ti->next) {
1354 blob.out_size = AFS_PIOCTL_MAXSIZE;
1357 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1359 Die(errno, ti->data);
1365 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1368 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1375 "%s: cleanacl is not supported for DFS access lists.\n",
1381 changes = CleanAcl(ta, ti->data);
1384 /* now set the acl */
1385 blob.in=AclToString(ta);
1386 if( FAILED(StringCbLength(blob.in, sizeof(space), &len))) {
1387 fprintf (stderr, "StringCbLength failure on blob.in");
1390 blob.in_size = (long)len+1;
1392 code = pioctl_utf8(ti->data, VIOCSETAL, &blob, 1);
1394 if (errno == EINVAL) {
1396 "%s: Invalid argument, possible reasons include\n",
1398 fprintf(stderr,"%s: File not in vice or\n", pn);
1400 "%s: Too many users on access control list or\n",
1403 Die(errno, ti->data);
1409 /* now list the updated acl */
1410 printf("Access list for %s is now\n", ti->data);
1411 if (ta->nplus > 0) {
1413 printf("Normal rights:\n");
1414 for(te = ta->pluslist;te;te=te->next) {
1415 printf(" %s ", te->name);
1416 PRights(te->rights, ta->dfs);
1420 if (ta->nminus > 0) {
1421 printf("Negative rights:\n");
1422 for(te = ta->minuslist;te;te=te->next) {
1423 printf(" %s ", te->name);
1424 PRights(te->rights, ta->dfs);
1431 printf("Access list for %s is fine.\n", ti->data);
1439 ListACLCmd(struct cmd_syndesc *as, void *arock)
1443 struct ViceIoctl blob;
1444 struct AclEntry *te;
1445 struct cmd_item *ti;
1446 int idf = getidf(as, parm_listacl_id);
1449 SetDotDefault(&as->parms[0].items);
1450 for(ti=as->parms[0].items; ti; ti=ti->next) {
1452 blob.out_size = AFS_PIOCTL_MAXSIZE;
1454 blob.in = blob.out = space;
1455 code = pioctl_utf8(ti->data, VIOCGETAL, &blob, 1);
1457 Die(errno, ti->data);
1461 ta = ParseAcl(space, AFS_PIOCTL_MAXSIZE);
1464 "fs: %s: invalid acl data returned from VIOCGETAL\n",
1469 if (as->parms[3].items) { /* -cmd */
1470 printf("fs setacl -dir %s -acl ", ti->data);
1471 if (ta->nplus > 0) {
1472 for (te = ta->pluslist; te; te = te->next) {
1473 printf(" %s ", te->name);
1474 PRights(te->rights, ta->dfs);
1478 if (ta->nminus > 0) {
1479 printf("fs setacl -dir %s -acl ", ti->data);
1480 for (te = ta->minuslist; te; te = te->next) {
1481 printf(" %s ", te->name);
1482 PRights(te->rights, ta->dfs);
1484 printf(" -negative\n");
1489 printf("Access list for %s is\n", ti->data);
1492 printf("DFS access list for %s is\n", ti->data);
1495 printf("DFS initial directory access list of %s is\n", ti->data);
1498 printf("DFS initial file access list of %s is\n", ti->data);
1502 printf(" Default cell = %s\n", ta->cell);
1504 separator = ta->dfs? DFS_SEPARATOR : ' ';
1505 if (ta->nplus > 0) {
1507 printf("Normal rights:\n");
1508 for(te = ta->pluslist;te;te=te->next) {
1509 printf(" %s%c", te->name, separator);
1510 PRights(te->rights, ta->dfs);
1514 if (ta->nminus > 0) {
1515 printf("Negative rights:\n");
1516 for(te = ta->minuslist;te;te=te->next) {
1517 printf(" %s ", te->name);
1518 PRights(te->rights, ta->dfs);
1531 FlushAllCmd(struct cmd_syndesc *as, void *arock)
1534 struct ViceIoctl blob;
1536 blob.in_size = blob.out_size = 0;
1537 code = pioctl_utf8(NULL, VIOC_FLUSHALL, &blob, 0);
1539 fprintf(stderr, "Error flushing all ");
1546 FlushVolumeCmd(struct cmd_syndesc *as, void *arock)
1549 struct ViceIoctl blob;
1550 struct cmd_item *ti;
1553 SetDotDefault(&as->parms[0].items);
1554 for(ti=as->parms[0].items; ti; ti=ti->next) {
1555 blob.in_size = blob.out_size = 0;
1556 code = pioctl_utf8(ti->data, VIOC_FLUSHVOLUME, &blob, 0);
1558 fprintf(stderr, "Error flushing volume ");
1568 FlushCmd(struct cmd_syndesc *as, void *arock)
1571 struct ViceIoctl blob;
1572 struct cmd_item *ti;
1575 cm_ioctlQueryOptions_t options;
1577 if (as->parms[1].items)
1580 for(ti=as->parms[0].items; ti; ti=ti->next) {
1582 memset(&options, 0, sizeof(options));
1583 options.size = sizeof(options);
1584 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
1585 options.literal = literal;
1586 blob.in_size = options.size; /* no variable length data */
1590 code = pioctl_utf8(ti->data, VIOCFLUSH, &blob, 0);
1592 if (errno == EMFILE) {
1593 fprintf(stderr, "%s: Can't flush active file %s\n", pn,
1596 fprintf(stderr, "%s: Error flushing file ", pn);
1606 /* all this command does is repackage its args and call SetVolCmd */
1608 SetQuotaCmd(struct cmd_syndesc *as, void *arock) {
1609 struct cmd_syndesc ts;
1611 /* copy useful stuff from our command slot; we may later have to reorder */
1613 memcpy(&ts, as, sizeof(ts)); /* copy whole thing */
1615 err = memcpy_s(&ts, sizeof(ts), as, sizeof(ts)); /* copy whole thing */
1617 fprintf (stderr, "memcpy_s failure on ts");
1621 return SetVolCmd(&ts, arock);
1625 SetVolCmd(struct cmd_syndesc *as, void *arock) {
1627 struct ViceIoctl blob;
1628 struct cmd_item *ti;
1629 struct VolumeStatus *status;
1630 char *motd, *offmsg, *input, *destEnd;
1631 size_t destRemaining;
1635 SetDotDefault(&as->parms[0].items);
1636 for(ti=as->parms[0].items; ti; ti=ti->next) {
1638 destRemaining = sizeof(space);
1639 blob.out_size = AFS_PIOCTL_MAXSIZE;
1640 blob.in_size = sizeof(*status) + 3; /* for the three terminating nulls */
1643 status = (VolumeStatus *)space;
1644 status->MinQuota = status->MaxQuota = -1;
1645 motd = offmsg = NULL;
1646 if (as->parms[1].items) {
1647 code = util_GetHumanInt32(as->parms[1].items->data, &status->MaxQuota);
1649 fprintf(stderr,"%s: bad integer specified for quota.\n", pn);
1654 if (as->parms[2].items)
1655 motd = as->parms[2].items->data;
1656 if (as->parms[3].items)
1657 offmsg = as->parms[3].items->data;
1658 input = (char *)status + sizeof(*status);
1659 *(input++) = '\0'; /* never set name: this call doesn't change vldb */
1660 destRemaining -= sizeof(*status) + 1;
1662 if( FAILED(StringCbLength(offmsg, VMSGSIZE, &len))) {
1663 fprintf(stderr,"%s: message must be shorter than %d characters\n",
1668 if( FAILED(StringCbCopyEx(input, destRemaining, offmsg, &destEnd, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
1669 fprintf (stderr, "input - not enough space");
1672 blob.in_size += destEnd - input;
1673 input = destEnd + 1;
1674 destRemaining -= sizeof(char);
1677 destRemaining -= sizeof(char);
1680 if( FAILED(StringCbLength(motd, VMSGSIZE, &len))) {
1681 fprintf(stderr,"%s: message must be shorter than %d characters\n",
1685 if( FAILED(StringCbCopyEx(input, destRemaining, motd, &destEnd, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
1686 fprintf (stderr, "input - not enough space");
1689 blob.in_size += (long)(destEnd - input);
1690 input = destEnd + 1;
1691 destRemaining -= sizeof(char);
1694 destRemaining -= sizeof(char);
1696 code = pioctl_utf8(ti->data,VIOCSETVOLSTAT, &blob, 1);
1698 Die(errno, ti->data);
1705 /* values match cache manager File Types */
1707 filetypestr(afs_uint32 type)
1709 char * s = "Object";
1732 ExamineCmd(struct cmd_syndesc *as, void *arock)
1735 struct ViceIoctl blob;
1736 struct cmd_item *ti;
1737 struct VolumeStatus *status;
1738 char *name, *offmsg, *motd;
1741 cm_ioctlQueryOptions_t options;
1744 if (as->parms[1].items)
1747 SetDotDefault(&as->parms[0].items);
1748 for(ti=as->parms[0].items; ti; ti=ti->next) {
1750 afs_uint32 filetype;
1752 char cell[CELL_MAXNAMELEN];
1755 memset(&fid, 0, sizeof(fid));
1756 memset(&options, 0, sizeof(options));
1758 options.size = sizeof(options);
1759 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
1760 options.literal = literal;
1761 blob.in_size = options.size; /* no variable length data */
1764 blob.out_size = sizeof(cm_fid_t);
1765 blob.out = (char *) &fid;
1766 if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1) &&
1767 blob.out_size == sizeof(cm_fid_t)) {
1768 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
1771 Die(errno, ti->data);
1776 blob.out_size = sizeof(filetype);
1777 blob.out = &filetype;
1779 code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
1780 if (code || blob.out_size != sizeof(filetype)) {
1781 Die(errno, ti->data);
1786 blob.out_size = CELL_MAXNAMELEN;
1789 code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
1791 cell[blob.out_size-1] = '\0';
1792 printf("%s %s (%u.%u.%u) contained in cell %s\n",
1793 filetypestr(filetype),
1794 ti->data, fid.volume, fid.vnode, fid.unique,
1795 code ? "unknown-cell" : cell);
1797 blob.out_size = 2 * sizeof(afs_uint32);
1798 blob.out = (char *) &owner;
1799 if (0 == pioctl_utf8(ti->data, VIOCGETOWNER, &blob, 1) &&
1800 blob.out_size == 2 * sizeof(afs_uint32)) {
1801 char oname[PR_MAXNAMELEN] = "(unknown)";
1802 char gname[PR_MAXNAMELEN] = "(unknown)";
1805 /* Go to the PRDB and see if this all number username is valid */
1806 cm_GetConfigDir(confDir, sizeof(confDir));
1808 pr_Initialize(1, confDir, cell);
1809 pr_SIdToName(owner[0], oname);
1810 pr_SIdToName(owner[1], gname);
1811 printf("Owner %s (%d) Group %s (%d)\n", oname, owner[0], gname, owner[1]);
1815 blob.out_size = AFS_PIOCTL_MAXSIZE;
1816 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
1818 space[blob.out_size - 1] = '\0';
1819 status = (VolumeStatus *)space;
1820 name = (char *)status + sizeof(*status);
1821 if( FAILED(StringCbLength(name, sizeof(space) - (name - space), &len))) {
1822 fprintf (stderr, "StringCbLength failure on name");
1825 offmsg = name + len + 1;
1826 if( FAILED(StringCbLength(offmsg, sizeof(space) - (offmsg - space), &len))) {
1827 fprintf (stderr, "StringCbLength failure on offmsg");
1830 motd = offmsg + len + 1;
1831 PrintStatus(status, name, motd, offmsg);
1833 Die(errno, ti->data);
1837 code = pioctl_utf8(ti->data, VIOC_PATH_AVAILABILITY, &blob, 1);
1840 printf("Volume is online\n");
1843 printf("Volume is offline\n");
1846 printf("All Volume servers are down\n");
1849 printf("All volume servers are busy\n");
1852 printf("Unknown volume state\n");
1853 Die(errno, ti->data);
1861 ListQuotaCmd(struct cmd_syndesc *as, void *arock)
1864 struct ViceIoctl blob;
1865 struct cmd_item *ti;
1866 struct VolumeStatus *status;
1871 printf("%-25s%-11s%-11s%-7s%-13s\n", "Volume Name", " Quota",
1872 " Used", " %Used", " Partition");
1873 SetDotDefault(&as->parms[0].items);
1874 for(ti=as->parms[0].items; ti; ti=ti->next) {
1876 blob.out_size = AFS_PIOCTL_MAXSIZE;
1879 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
1881 Die(errno, ti->data);
1885 space[blob.out_size - 1] = '\0';
1886 status = (VolumeStatus *)space;
1887 name = (char *)status + sizeof(*status);
1888 QuickPrintStatus(status, name);
1894 WhereIsCmd(struct cmd_syndesc *as, void *arock)
1897 struct ViceIoctl blob;
1898 struct cmd_item *ti;
1904 cm_ioctlQueryOptions_t options;
1906 if (as->parms[1].items)
1909 SetDotDefault(&as->parms[0].items);
1910 for(ti=as->parms[0].items; ti; ti=ti->next) {
1912 afs_uint32 filetype;
1915 memset(&fid, 0, sizeof(fid));
1916 memset(&options, 0, sizeof(options));
1918 options.size = sizeof(options);
1919 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
1920 options.literal = literal;
1921 blob.in_size = options.size; /* no variable length data */
1924 blob.out_size = sizeof(cm_fid_t);
1925 blob.out = (char *) &fid;
1926 if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1) &&
1927 blob.out_size == sizeof(cm_fid_t)) {
1928 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
1931 Die(errno, ti->data);
1936 blob.out_size = sizeof(filetype);
1937 blob.out = &filetype;
1939 code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
1940 if (code || blob.out_size != sizeof(filetype)) {
1941 Die(errno, ti->data);
1945 blob.out_size = AFS_PIOCTL_MAXSIZE;
1947 memset(space, 0, sizeof(space));
1948 code = pioctl_utf8(ti->data, VIOCWHEREIS, &blob, 1);
1950 Die(errno, ti->data);
1954 hosts = (afs_int32 *) space;
1955 printf("%s %s is on host%s ",
1956 filetypestr(filetype),
1958 (hosts[0] && !hosts[1]) ? "": "s");
1959 for(j=0; j<AFS_MAXHOSTS; j++) {
1962 tp = hostutil_GetNameByINet(hosts[j]);
1972 DiskFreeCmd(struct cmd_syndesc *as, void *arock)
1975 struct ViceIoctl blob;
1976 struct cmd_item *ti;
1978 struct VolumeStatus *status;
1981 printf("%-25s%-10s%-10s%-10s%-6s\n", "Volume Name", " kbytes",
1982 " used", " avail", " %used");
1983 SetDotDefault(&as->parms[0].items);
1984 for(ti=as->parms[0].items; ti; ti=ti->next) {
1986 blob.out_size = AFS_PIOCTL_MAXSIZE;
1989 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
1991 Die(errno, ti->data);
1995 space[blob.out_size - 1] = '\0';
1996 status = (VolumeStatus *)space;
1997 name = (char *)status + sizeof(*status);
1998 QuickPrintSpace(status, name);
2004 QuotaCmd(struct cmd_syndesc *as, void *arock)
2007 struct ViceIoctl blob;
2008 struct cmd_item *ti;
2010 struct VolumeStatus *status;
2013 SetDotDefault(&as->parms[0].items);
2014 for(ti=as->parms[0].items; ti; ti=ti->next) {
2016 blob.out_size = AFS_PIOCTL_MAXSIZE;
2019 code = pioctl_utf8(ti->data, VIOCGETVOLSTAT, &blob, 1);
2021 * The response is VolumeStatus, volume name, offline message, and motd
2023 if (code || blob.out_size < sizeof(*status)) {
2024 Die(errno, ti->data);
2029 status = (VolumeStatus *)space;
2030 if (status->MaxQuota)
2031 quotaPct = ((((double)status->BlocksInUse)/status->MaxQuota) * 100.0);
2034 printf("%2.0f%% of quota used.\n", quotaPct);
2040 ListMountCmd(struct cmd_syndesc *as, void *arock)
2043 struct ViceIoctl blob;
2044 struct cmd_item *ti;
2045 char orig_name[1024]; /*Original name, may be modified*/
2046 char true_name[1024]; /*``True'' dirname (e.g., symlink target)*/
2047 char parent_dir[1024]; /*Parent directory of true name*/
2048 char *last_component; /*Last component of true name*/
2052 struct stat statbuff; /*Buffer for status info*/
2053 #endif /* not WIN32 */
2055 int link_chars_read; /*Num chars read in readlink()*/
2056 #endif /* not WIN32 */
2057 int thru_symlink; /*Did we get to a mount point via a symlink?*/
2060 for(ti=as->parms[0].items; ti; ti=ti->next) {
2064 if( FAILED(StringCbCopy(orig_name, sizeof(orig_name), ti->data))) {
2065 fprintf (stderr, "orig_name - not enough space");
2068 #else /* not WIN32 */
2070 if( FAILED(StringCbPrintf(orig_name, sizeof(orig_name), "%s%s",
2071 (ti->data[0] == '/') ? "" : "./",
2073 fprintf (stderr, "orig_name - cannot be populated");
2076 #endif /* not WIN32 */
2079 if (lstat(orig_name, &statbuff) < 0) {
2080 /* if lstat fails, we should still try the pioctl, since it
2081 * may work (for example, lstat will fail, but pioctl will
2082 * work if the volume of offline (returning ENODEV). */
2083 statbuff.st_mode = S_IFDIR; /* lie like pros */
2087 * The lstat succeeded. If the given file is a symlink, substitute
2088 * the file name with the link name.
2090 if ((statbuff.st_mode & S_IFMT) == S_IFLNK) {
2093 * Read name of resolved file.
2095 link_chars_read = readlink(orig_name, true_name, 1024);
2096 if (link_chars_read <= 0) {
2098 "%s: Can't read target name for '%s' symbolic link!\n",
2105 * Add a trailing null to what was read, bump the length.
2107 true_name[link_chars_read++] = 0;
2110 * If the symlink is an absolute pathname, we're fine. Otherwise, we
2111 * have to create a full pathname using the original name and the
2112 * relative symlink name. Find the rightmost slash in the original
2113 * name (we know there is one) and splice in the symlink value.
2115 if (true_name[0] != '\\') {
2116 last_component = (char *) strrchr(orig_name, '\\');
2117 if( FAILED(StringCbCopy(++last_component, sizeof(orig_name) - (last_component - orig_name) * sizeof(char), true_name))) {
2118 fprintf (stderr, "last_component - not enough space");
2121 if( FAILED(StringCbCopy(true_name, sizeof(true_name), orig_name))) {
2122 fprintf (stderr, "true_name - not enough space");
2127 if( FAILED(StringCbCopy(true_name, sizeof(true_name), orig_name))) {
2128 fprintf (stderr, "true_name - not enough space");
2133 if( FAILED(StringCbCopy(true_name, sizeof(true_name), orig_name))) {
2134 fprintf (stderr, "true_name - not enough space");
2140 * Find rightmost slash, if any.
2143 last_component = (char *) strrchr(true_name, '\\');
2144 if (!last_component)
2146 last_component = (char *) strrchr(true_name, '/');
2147 if (last_component) {
2149 * Found it. Designate everything before it as the parent directory,
2150 * everything after it as the final component.
2152 if( FAILED(StringCchCopyN(parent_dir, sizeof(parent_dir) / sizeof(char), true_name, last_component - true_name + 1))) {
2153 fprintf (stderr, "parent_dir - not enough space");
2156 parent_dir[last_component - true_name + 1] = 0;
2157 last_component++; /*Skip the slash*/
2159 if (!InAFS(parent_dir)) {
2160 const char * nbname = NetbiosName();
2161 if( FAILED(StringCbLength(nbname, NETBIOSNAMESZ, &len))) {
2162 fprintf (stderr, "StringCbLength failure on nbname");
2165 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
2166 parent_dir[len+2] == '\\' &&
2167 parent_dir[len+3] == '\0' &&
2168 !strnicmp(nbname,&parent_dir[2],len))
2170 if( FAILED(StringCbPrintf(parent_dir, sizeof(parent_dir),"\\\\%s\\all\\", nbname))) {
2171 fprintf (stderr, "parent_dir - cannot be populated");
2179 * No slash appears in the given file name. Set parent_dir to the current
2180 * directory, and the last component as the given name.
2182 fs_ExtractDriveLetter(true_name, parent_dir);
2183 if( FAILED(StringCbCat(parent_dir, sizeof(parent_dir), "."))) {
2184 fprintf (stderr, "parent_dir - not enough space");
2187 last_component = true_name;
2188 fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
2191 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
2192 fprintf(stderr,"%s: you may not use '.' or '..' as the last component\n",pn);
2193 fprintf(stderr,"%s: of a name in the 'fs lsmount' command.\n",pn);
2198 blob.in = last_component;
2199 if( FAILED(StringCchLength(last_component, sizeof(true_name) / sizeof(char) - (last_component - true_name), &len))) {
2200 fprintf (stderr, "StringCbLength failure on last_component");
2203 blob.in_size = (long)len+1;
2204 blob.out_size = AFS_PIOCTL_MAXSIZE;
2206 memset(space, 0, AFS_PIOCTL_MAXSIZE);
2208 code = pioctl_utf8(parent_dir, VIOC_AFS_STAT_MT_PT, &blob, 1);
2211 printf("'%s' is a %smount point for volume '%.*s'\n",
2213 (thru_symlink ? "symbolic link, leading to a " : ""),
2218 if (errno == EINVAL) {
2219 fprintf(stderr,"'%s' is not a mount point.\n", ti->data);
2221 Die(errno, (ti->data ? ti->data : parent_dir));
2230 MakeMountCmd(struct cmd_syndesc *as, void *arock)
2233 char *cellName, *volName, *tmpName;
2235 char localCellName[128];
2237 char path[1024] = "";
2238 struct afsconf_cell info;
2239 struct vldbentry vldbEntry;
2240 struct ViceIoctl blob;
2244 memset(&info, 0, sizeof(info));
2246 if (as->parms[2].items) /* cell name specified */
2247 cellName = as->parms[2].items->data;
2250 volName = as->parms[1].items->data;
2251 if( FAILED(StringCbLength(volName, VL_MAXNAMELEN, &len))) {
2252 fprintf(stderr,"%s: volume name too long (length must be <= 64 characters)\n", pn);
2256 /* Check for a cellname in the volume specification, and complain
2257 * if it doesn't match what was specified with -cell */
2258 if (tmpName = strchr(volName, ':')) {
2261 if (strcasecmp(cellName,volName)) {
2262 fprintf(stderr,"fs: cellnames do not match.\n");
2267 volName = ++tmpName;
2270 parent = Parent(as->parms[0].items->data);
2271 if (!InAFS(parent)) {
2273 const char * nbname = NetbiosName();
2274 if ( FAILED(StringCbLength(nbname, NETBIOSNAMESZ, &len))) {
2275 fprintf (stderr, "StringCbLength failure on nbname");
2278 if (parent[0] == '\\' && parent[1] == '\\' &&
2279 parent[len+2] == '\\' &&
2280 parent[len+3] == '\0' &&
2281 !strnicmp(nbname,&parent[2],len))
2283 if( FAILED(StringCbPrintf(path, sizeof(path),"%sall\\%s", parent, &as->parms[0].items->data[len+2]))) {
2284 fprintf (stderr, "path - cannot be populated");
2287 parent = Parent(path);
2288 if (!InAFS(parent)) {
2289 fprintf(stderr,"%s: mount points must be created within the AFS file system\n", pn);
2295 fprintf(stderr,"%s: mount points must be created within the AFS file system\n", pn);
2300 if( FAILED(StringCbLength(path, sizeof(path), &len))) {
2301 fprintf (stderr, "StringCbLength failure on path");
2305 if( FAILED(StringCbCopy(path, sizeof(path), as->parms[0].items->data))) {
2306 fprintf (stderr, "path - not enough space");
2310 if ( IsFreelanceRoot(parent) ) {
2312 fprintf(stderr,"%s: Only AFS Client Administrators may alter the root.afs volume\n", pn);
2318 blob.out_size = sizeof(localCellName);
2319 blob.out = localCellName;
2320 code = pioctl_utf8(parent, VIOC_GET_WS_CELL, &blob, 1);
2322 localCellName[sizeof(localCellName) - 1] = '\0';
2323 cellName = localCellName;
2328 code = GetCell(parent,space);
2334 code = GetCellName(cellName?cellName:space, &info);
2338 if (!(as->parms[4].items)) {
2339 /* not fast, check which cell the mountpoint is being created in */
2341 /* not fast, check name with VLDB */
2343 code = VLDBInit(1, &info);
2345 /* make the check. Don't complain if there are problems with init */
2346 code = ubik_VL_GetEntryByNameO(uclient, 0, volName, &vldbEntry);
2347 if (code == VL_NOENT) {
2348 fprintf(stderr,"%s: warning, volume %s does not exist in cell %s.\n",
2349 pn, volName, cellName ? cellName : space);
2354 if (as->parms[3].items) { /* if -rw specified */
2355 if( FAILED(StringCbCopy(space, sizeof(space), "%"))) {
2356 fprintf (stderr, "space arr - not enough space");
2360 if( FAILED(StringCbCopy(space, sizeof(space), "#"))) {
2361 fprintf (stderr, "space arr - not enough space");
2366 /* cellular mount point, prepend cell prefix */
2367 if( FAILED(StringCbCat(space, sizeof(space), info.name))) {
2368 fprintf (stderr, "space arr - not enough space");
2371 if( FAILED(StringCbCat(space, sizeof(space), ":"))) {
2372 fprintf (stderr, "space arr - not enough space");
2376 if( FAILED(StringCbCat(space, sizeof(space), volName))) { /* append volume name */
2377 fprintf (stderr, "space arr - not enough space");
2380 if( FAILED(StringCbCat(space, sizeof(space), "."))) { /* stupid convention; these end with a period */
2381 fprintf (stderr, "space arr - not enough space");
2385 /* create symlink with a special pioctl for Windows NT, since it doesn't
2386 * have a symlink system call.
2389 if( FAILED(StringCbLength(space, sizeof(space), &len))) {
2390 fprintf (stderr, "StringCbLength failure on space");
2393 blob.in_size = 1 + (long)len;
2396 code = pioctl_utf8(path, VIOC_AFS_CREATE_MT_PT, &blob, 0);
2397 #else /* not WIN32 */
2398 code = symlink(space, path);
2399 #endif /* not WIN32 */
2401 if (info.linkedCell)
2402 free(info.linkedCell);
2412 * Delete AFS mount points. Variables are used as follows:
2413 * tbuffer: Set to point to the null-terminated directory name of the mount point
2414 * (or ``.'' if none is provided)
2415 * tp: Set to point to the actual name of the mount point to nuke.
2418 RemoveMountCmd(struct cmd_syndesc *as, void *arock) {
2420 struct ViceIoctl blob;
2421 struct cmd_item *ti;
2423 char lsbuffer[1024];
2428 for(ti=as->parms[0].items; ti; ti=ti->next) {
2430 tp = (char *) strrchr(ti->data, '\\');
2432 tp = (char *) strrchr(ti->data, '/');
2434 if( FAILED(StringCchCopyN(tbuffer, sizeof(tbuffer) / sizeof(char), ti->data, code=(afs_int32)(tp-ti->data+1)))) { /* the dir name */
2435 fprintf (stderr, "tbuffer - not enough space");
2438 tp++; /* skip the slash */
2441 if (!InAFS(tbuffer)) {
2442 const char * nbname = NetbiosName();
2443 if( FAILED(StringCbLength(nbname, NETBIOSNAMESZ, &len))) {
2444 fprintf (stderr, "StringCbLength failure on nbname");
2448 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
2449 tbuffer[len+2] == '\\' &&
2450 tbuffer[len+3] == '\0' &&
2451 !strnicmp(nbname,&tbuffer[2],len))
2453 if( FAILED(StringCbPrintf(tbuffer, sizeof(tbuffer),"\\\\%s\\all\\", nbname))) {
2454 fprintf (stderr, "tbuffer - cannot be populated");
2461 fs_ExtractDriveLetter(ti->data, tbuffer);
2462 if( FAILED(StringCbCat(tbuffer, sizeof(tbuffer), "."))) {
2463 fprintf (stderr, "tbuffer - not enough space");
2467 fs_StripDriveLetter(tp, tp, 0);
2470 if( FAILED(StringCbLength(tp, AFS_PIOCTL_MAXSIZE, &len))) {
2471 fprintf (stderr, "StringCbLength failure on tp");
2474 blob.in_size = (long)len+1;
2475 blob.out = lsbuffer;
2476 blob.out_size = sizeof(lsbuffer);
2477 code = pioctl_utf8(tbuffer, VIOC_AFS_STAT_MT_PT, &blob, 0);
2479 if (errno == EINVAL) {
2480 fprintf(stderr,"%s: '%s' is not a mount point.\n", pn, ti->data);
2482 Die(errno, ti->data);
2485 continue; /* don't bother trying */
2488 if ( IsFreelanceRoot(tbuffer) && !IsAdmin() ) {
2489 fprintf(stderr,"%s: Only AFS Client Administrators may alter the root.afs volume\n", pn);
2491 continue; /* skip */
2496 if( FAILED(StringCbLength(tp, AFS_PIOCTL_MAXSIZE, &len))) {
2497 fprintf (stderr, "StringCbLength failure on tp");
2500 blob.in_size = (long)len+1;
2501 code = pioctl_utf8(tbuffer, VIOC_AFS_DELETE_MT_PT, &blob, 0);
2503 Die(errno, ti->data);
2514 CheckServersCmd(struct cmd_syndesc *as, void *arock)
2517 struct ViceIoctl blob;
2521 struct afsconf_cell info;
2522 struct chservinfo checkserv;
2526 memset(&info, 0, sizeof(info));
2527 memset(&checkserv, 0, sizeof(struct chservinfo));
2528 blob.in_size=sizeof(struct chservinfo);
2529 blob.in=(caddr_t)&checkserv;
2531 blob.out_size = AFS_PIOCTL_MAXSIZE;
2533 memset(space, 0, sizeof(afs_int32)); /* so we assure zero when nothing is copied back */
2535 /* prepare flags for checkservers command */
2536 temp = 2; /* default to checking local cell only */
2537 if (as->parms[2].items)
2538 temp |= 1; /* set fast flag */
2539 if (as->parms[1].items)
2540 temp &= ~2; /* turn off local cell check */
2542 checkserv.magic = 0x12345678; /* XXX */
2543 checkserv.tflags=temp;
2545 /* now copy in optional cell name, if specified */
2546 if (as->parms[0].items) {
2547 code = GetCellName(as->parms[0].items->data, &info);
2551 if( FAILED(StringCbCopy(checkserv.tbuffer, sizeof(checkserv.tbuffer), info.name))) {
2552 fprintf (stderr, "tbuffer - not enough space");
2555 if( FAILED(StringCbLength(info.name, sizeof(info.name), &len))) {
2556 fprintf (stderr, "StringCbLength failure on info.name");
2559 checkserv.tsize=(int)len+1;
2560 if (info.linkedCell)
2561 free(info.linkedCell);
2563 if( FAILED(StringCbCopy(checkserv.tbuffer, sizeof(checkserv.tbuffer),"\0"))) {
2564 fprintf (stderr, "tbuffer - not enough space");
2570 if(as->parms[3].items) {
2571 checkserv.tinterval=atol(as->parms[3].items->data);
2574 if(checkserv.tinterval<0) {
2575 printf("Warning: The negative -interval is ignored; treated as an inquiry\n");
2576 checkserv.tinterval=-1;
2577 } else if(checkserv.tinterval> 600) {
2578 printf("Warning: The maximum -interval value is 10 mins (600 secs)\n");
2579 checkserv.tinterval=600; /* 10 min max interval */
2582 checkserv.tinterval = -1; /* don't change current interval */
2585 if ( checkserv.tinterval >= 0 ) {
2588 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2593 fprintf (stderr,"Permission denied: requires root access.\n");
2599 code = pioctl_utf8(0, VIOCCKSERV, &blob, 1);
2601 if ((errno == EACCES) && (checkserv.tinterval > 0)) {
2602 printf("Must be root to change -interval\n");
2609 memcpy(&temp, space, sizeof(afs_int32));
2611 err = memcpy_s(&temp, sizeof(temp), space, sizeof(afs_int32));
2613 fprintf (stderr, "memcpy_s failure on temp");
2618 if (checkserv.tinterval >= 0) {
2619 if (checkserv.tinterval > 0)
2620 printf("The new down server probe interval (%d secs) is now in effect (old interval was %d secs)\n",
2621 checkserv.tinterval, temp);
2623 printf("The current down server probe interval is %d secs\n", temp);
2627 printf("All servers are running.\n");
2629 printf("These servers unavailable due to network or server problems: ");
2630 for(j=0; j < AFS_MAXHOSTS; j++) {
2632 memcpy(&temp, space + j*sizeof(afs_int32), sizeof(afs_int32));
2634 err = memcpy_s(&temp, sizeof(temp), space + j*sizeof(afs_int32), sizeof(afs_int32));
2636 fprintf (stderr, "memcpy_s failure on temp");
2643 tp = hostutil_GetNameByINet(temp);
2653 MessagesCmd(struct cmd_syndesc *as, void *arock)
2656 struct ViceIoctl blob;
2657 struct gaginfo gagflags;
2658 struct cmd_item *show;
2660 memset(&gagflags, 0, sizeof(struct gaginfo));
2661 blob.in_size = sizeof(struct gaginfo);
2662 blob.in = (caddr_t ) &gagflags;
2663 blob.out_size = AFS_PIOCTL_MAXSIZE;
2665 memset(space, 0, sizeof(afs_int32)); /* so we assure zero when nothing is copied back */
2667 if (show = as->parms[0].items) {
2668 if (!strcasecmp (show->data, "user"))
2669 gagflags.showflags |= GAGUSER;
2670 else if (!strcasecmp (show->data, "console"))
2671 gagflags.showflags |= GAGCONSOLE;
2672 else if (!strcasecmp (show->data, "all"))
2673 gagflags.showflags |= GAGCONSOLE | GAGUSER;
2674 else if (!strcasecmp (show->data, "none"))
2678 "unrecognized flag %s: must be in {user,console,all,none}\n",
2687 code = pioctl_utf8(0, VIOC_GAG, &blob, 1);
2696 CheckVolumesCmd(struct cmd_syndesc *as, void *arock)
2699 struct ViceIoctl blob;
2703 code = pioctl_utf8(0, VIOCCKBACK, &blob, 1);
2708 printf("All volumeID/name mappings checked.\n");
2714 SetCacheSizeCmd(struct cmd_syndesc *as, void *arock)
2717 struct ViceIoctl blob;
2722 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
2727 fprintf (stderr,"Permission denied: requires root access.\n");
2732 if (!as->parms[0].items && !as->parms[1].items) {
2733 fprintf(stderr,"%s: syntax error in set cache size cmd.\n", pn);
2736 if (as->parms[0].items) {
2737 code = util_GetHumanInt32(as->parms[0].items->data, &temp);
2739 fprintf(stderr,"%s: bad integer specified for cache size.\n", pn);
2744 blob.in = (char *) &temp;
2745 blob.in_size = sizeof(afs_int32);
2747 code = pioctl_utf8(0, VIOCSETCACHESIZE, &blob, 1);
2749 Die(errno, (char *) 0);
2753 printf("New cache size set.\n");
2758 GetCacheParmsCmd(struct cmd_syndesc *as, void *arock)
2761 struct ViceIoctl blob;
2762 cm_cacheParms_t parms;
2764 memset(&parms, 0, sizeof(parms));
2767 blob.out_size = sizeof(parms);
2768 blob.out = (char *) &parms;
2769 code = pioctl_utf8(0, VIOCGETCACHEPARMS, &blob, 1);
2770 if (code || blob.out_size != sizeof(parms)) {
2775 printf("AFS using %I64u of the cache's available %I64u 1K byte blocks.\n",
2776 parms.parms[1], parms.parms[0]);
2777 if (parms.parms[1] > parms.parms[0])
2778 printf("[Cache guideline temporarily deliberately exceeded; it will be adjusted down but you may wish to increase the cache size.]\n");
2783 ListCellsCmd(struct cmd_syndesc *as, void *arock)
2786 afs_int32 i, j, *lp, magic, size;
2788 afs_int32 addr, maxa = AFS_OMAXHOSTS;
2789 struct ViceIoctl blob;
2793 resolve = !(as->parms[0].items); /* -numeric */
2795 for(i=0;i<1000;i++) {
2798 memcpy(tp, &i, sizeof(afs_int32));
2800 err = memcpy_s(tp, sizeof(space), &i, sizeof(afs_int32));
2802 fprintf (stderr, "memcpy_s failure on tp");
2806 tp = (char *)(space + sizeof(afs_int32));
2807 lp = (afs_int32 *)tp;
2809 size = sizeof(afs_int32) + sizeof(afs_int32);
2810 blob.out_size = AFS_PIOCTL_MAXSIZE;
2811 blob.in_size = sizeof(afs_int32);
2814 code = pioctl_utf8(0, VIOCGETCELL, &blob, 1);
2817 break; /* done with the list */
2823 memcpy(&magic, tp, sizeof(afs_int32));
2825 err = memcpy_s(&magic, sizeof(magic), tp, sizeof(afs_int32));
2827 fprintf (stderr, "memcpy_s failure on magic");
2831 if (magic == 0x12345678) {
2832 maxa = AFS_MAXHOSTS;
2833 tp += sizeof(afs_int32);
2835 printf("Cell %s on hosts", tp+maxa*sizeof(afs_int32));
2836 for(j=0; j < maxa && j*sizeof(afs_int32) < AFS_PIOCTL_MAXSIZE; j++) {
2837 char *name, tbuffer[20];
2839 memcpy(&addr, tp + j*sizeof(afs_int32), sizeof(afs_int32));
2841 err = memcpy_s(&addr, sizeof(addr), tp + j*sizeof(afs_int32), sizeof(afs_int32));
2843 fprintf (stderr, "memcpy_s failure on addr");
2851 name = hostutil_GetNameByINet(addr);
2854 if( FAILED(StringCbPrintf(tbuffer, sizeof(tbuffer), "%d.%d.%d.%d", (addr >> 24) & 0xff,
2855 (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff))) {
2856 fprintf (stderr, "tbuffer - cannot be populated");
2861 printf(" %s", name);
2870 ListAliasesCmd(struct cmd_syndesc *as, void *arock)
2873 char *tp, *aliasName, *realName;
2874 struct ViceIoctl blob;
2881 memcpy(tp, &i, sizeof(afs_int32));
2883 err = memcpy_s(tp, sizeof(space), &i, sizeof(afs_int32));
2885 fprintf (stderr, "memcpy_s failure on tp");
2889 blob.out_size = AFS_PIOCTL_MAXSIZE;
2890 blob.in_size = sizeof(afs_int32);
2893 code = pioctl_utf8(0, VIOC_GETALIAS, &blob, 1);
2896 break; /* done with the list */
2900 space[blob.out_size - 1] = '\0';
2903 if( FAILED(StringCbLength(aliasName, sizeof(space), &len))) {
2904 fprintf (stderr, "StringCbLength failure on aliasName");
2909 printf("Alias %s for cell %s\n", aliasName, realName);
2915 CallBackRxConnCmd(struct cmd_syndesc *as, void *arock)
2918 struct ViceIoctl blob;
2919 struct cmd_item *ti;
2921 struct hostent *thp;
2925 ti = as->parms[0].items;
2928 thp = hostutil_GetHostByName(ti->data);
2930 fprintf(stderr, "host %s not found in host table.\n", ti->data);
2934 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
2936 err = memcpy_s(&hostAddr, sizeof(hostAddr), thp->h_addr, sizeof(afs_int32));
2938 fprintf (stderr, "memcpy_s failure on hostAddr");
2943 hostAddr = 0; /* means don't set host */
2944 setp = 0; /* aren't setting host */
2947 /* now do operation */
2948 blob.in_size = sizeof(afs_int32);
2949 blob.out_size = sizeof(afs_int32);
2950 blob.in = (char *) &hostAddr;
2951 blob.out = (char *) &hostAddr;
2953 code = pioctl_utf8(0, VIOC_CBADDR, &blob, 1);
2963 NewCellCmd(struct cmd_syndesc *as, void *arock)
2966 afs_int32 code, linkedstate=0, size=0, *lp;
2967 struct ViceIoctl blob;
2968 struct cmd_item *ti;
2969 char *destEnd, *tp, *cellname=0;
2970 struct hostent *thp;
2971 afs_int32 fsport = 0, vlport = 0;
2974 size_t destRemaining;
2976 memset(space, 0, AFS_MAXHOSTS * sizeof(afs_int32));
2978 lp = (afs_int32 *)tp;
2980 tp += sizeof(afs_int32);
2981 for(ti=as->parms[1].items; ti; ti=ti->next) {
2982 thp = hostutil_GetHostByName(ti->data);
2984 fprintf(stderr,"%s: Host %s not found in host table, skipping it.\n",
2989 memcpy(tp, thp->h_addr, sizeof(afs_int32));
2991 err = memcpy_s(tp, sizeof(space) - (tp - space) * sizeof(char), thp->h_addr, sizeof(afs_int32));
2993 fprintf (stderr, "memcpy_s failure on tp");
2997 tp += sizeof(afs_int32);
3000 if (as->parms[2].items) {
3002 * Link the cell, for the purposes of volume location, to the specified
3005 cellname = as->parms[2].items->data;
3008 #ifdef FS_ENABLE_SERVER_DEBUG_PORTS
3009 if (as->parms[3].items) {
3010 code = util_GetInt32(as->parms[3].items->data, &vlport);
3012 fprintf(stderr,"fs: bad integer specified for the fileserver port.\n");
3016 if (as->parms[4].items) {
3017 code = util_GetInt32(as->parms[4].items->data, &fsport);
3019 fprintf(stderr,"fs: bad integer specified for the vldb server port.\n");
3024 tp = (char *)(space + (AFS_MAXHOSTS+1) *sizeof(afs_int32));
3025 lp = (afs_int32 *)tp;
3029 if( FAILED(StringCbCopyEx(space + ((AFS_MAXHOSTS+4) * sizeof(afs_int32)), sizeof(space) - (AFS_MAXHOSTS+4) * sizeof(afs_int32)
3030 , as->parms[0].items->data, &tp, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3031 fprintf (stderr, "var - not enough space");
3034 tp++; /* for null */
3035 destRemaining -= sizeof(char);
3037 if( FAILED(StringCbCopyEx(tp, sizeof(space) - size, cellname, &destEnd, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3038 fprintf (tp, "space arr - not enough space");
3041 size += destEnd - tp + 1;
3043 blob.in_size = size;
3046 code = pioctl_utf8(0, VIOCNEWCELL, &blob, 1);
3052 struct ViceIoctl blob;
3055 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3060 blob.in = (char *) 0;
3061 blob.out_size = AFS_PIOCTL_MAXSIZE;
3064 code = pioctl_utf8((char *) 0, VIOCNEWCELL, &blob, 1);
3067 Die(errno, (char *) 0);
3071 printf("Cell servers information refreshed\n");
3078 NewAliasCmd(struct cmd_syndesc *as, void *arock)
3081 struct ViceIoctl blob;
3083 char *aliasName, *realName;
3084 size_t destRemaining = sizeof(space);
3086 /* Setup and do the NEWALIAS pioctl call */
3087 aliasName = as->parms[0].items->data;
3088 realName = as->parms[1].items->data;
3090 if( FAILED(StringCbCopyEx(tp, destRemaining, aliasName, &tp, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3091 fprintf (stderr, "tp - not enough space");
3095 destRemaining -= sizeof(char);
3096 if( FAILED(StringCbCopyEx(tp, destRemaining, realName, &tp, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3097 fprintf (stderr, "tp - not enough space");
3101 destRemaining -= sizeof(char);
3103 blob.in_size = tp - space;
3107 code = pioctl_utf8(0, VIOC_NEWALIAS, &blob, 1);
3109 if (errno == EEXIST) {
3111 "%s: cell name `%s' in use by an existing cell.\n", pn,
3123 WhichCellCmd(struct cmd_syndesc *as, void *arock)
3126 struct cmd_item *ti;
3127 struct ViceIoctl blob;
3130 cm_ioctlQueryOptions_t options;
3132 if (as->parms[1].items)
3135 SetDotDefault(&as->parms[0].items);
3136 for(ti=as->parms[0].items; ti; ti=ti->next) {
3138 afs_uint32 filetype;
3139 char cell[CELL_MAXNAMELEN];
3142 memset(&fid, 0, sizeof(fid));
3143 memset(&options, 0, sizeof(options));
3145 options.size = sizeof(options);
3146 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
3147 options.literal = literal;
3148 blob.in_size = options.size; /* no variable length data */
3151 blob.out_size = sizeof(cm_fid_t);
3152 blob.out = (char *) &fid;
3153 if (0 == pioctl_utf8(ti->data, VIOCGETFID, &blob, 1) &&
3154 blob.out_size == sizeof(cm_fid_t)) {
3155 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
3158 Die(errno, ti->data);
3163 blob.out_size = sizeof(filetype);
3164 blob.out = &filetype;
3166 code = pioctl_utf8(ti->data, VIOC_GETFILETYPE, &blob, 1);
3167 if (code || blob.out_size != sizeof(filetype)) {
3168 Die(errno, ti->data);
3172 blob.out_size = CELL_MAXNAMELEN;
3175 code = pioctl_utf8(ti->data, VIOC_FILE_CELL_NAME, &blob, 1);
3177 if (errno == ENOENT)
3178 fprintf(stderr,"%s: no such cell as '%s'\n", pn, ti->data);
3180 Die(errno, ti->data);
3184 cell[CELL_MAXNAMELEN - 1] = '\0';
3185 printf("%s %s lives in cell '%s'\n",
3186 filetypestr(filetype),
3193 WSCellCmd(struct cmd_syndesc *as, void *arock)
3196 struct ViceIoctl blob;
3200 blob.out_size = AFS_PIOCTL_MAXSIZE;
3203 code = pioctl_utf8(NULL, VIOC_GET_WS_CELL, &blob, 1);
3209 space[AFS_PIOCTL_MAXSIZE - 1] = '\0';
3210 printf("This workstation belongs to cell '%s'\n", space);
3216 PrimaryCellCmd(struct cmd_syndesc *as, void *arock)
3218 fprintf(stderr,"This command is obsolete, as is the concept of a primary token.\n");
3223 #ifndef AFS_NT40_ENV
3225 MonitorCmd(struct cmd_syndesc *as, void *arock)
3228 struct ViceIoctl blob;
3229 struct cmd_item *ti;
3231 struct hostent *thp;
3236 ti = as->parms[0].items;
3240 if (!strcmp(ti->data, "off")) {
3241 hostAddr = 0xffffffff;
3243 thp = hostutil_GetHostByName(ti->data);
3245 if (!strcmp(ti->data, "localhost")) {
3246 fprintf(stderr,"localhost not in host table, assuming 127.0.0.1\n");
3247 hostAddr = htonl(0x7f000001);
3249 fprintf(stderr,"host %s not found in host table.\n", ti->data);
3254 memcpy(&hostAddr, thp->h_addr, sizeof(afs_int32));
3256 err = memcpy_s(&hostAddr, sizeof(hostAddr), thp->h_addr, sizeof(afs_int32));
3258 fprintf (stderr, "memcpy_s failure on hostAddr");
3265 hostAddr = 0; /* means don't set host */
3266 setp = 0; /* aren't setting host */
3269 /* now do operation */
3270 blob.in_size = sizeof(afs_int32);
3271 blob.out_size = sizeof(afs_int32);
3272 blob.in = (char *) &hostAddr;
3273 blob.out = (char *) &hostAddr;
3274 code = pioctl_utf8(0, VIOC_AFS_MARINER_HOST, &blob, 1);
3275 if (code || blob.out_size != sizeof(afs_int32)) {
3280 printf("%s: new monitor host set.\n", pn);
3282 /* now decode old address */
3283 if (hostAddr == 0xffffffff) {
3284 printf("Cache monitoring is currently disabled.\n");
3286 tp = hostutil_GetNameByINet(hostAddr);
3287 printf("Using host %s for monitor services.\n", tp);
3292 #endif /* AFS_NT40_ENV */
3295 SysNameCmd(struct cmd_syndesc *as, void *arock)
3298 struct ViceIoctl blob;
3299 struct cmd_item *ti;
3300 char *input = space;
3303 size_t destRemaining = sizeof(space);
3306 ti = as->parms[0].items;
3310 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3315 fprintf (stderr,"Permission denied: requires root access.\n");
3323 blob.out_size = AFS_PIOCTL_MAXSIZE;
3324 blob.in_size = sizeof(afs_int32);
3326 memcpy(input, &setp, sizeof(afs_int32));
3328 err = memcpy_s(input, destRemaining, &setp, sizeof(afs_int32));
3330 fprintf (stderr, "memcpy_s failure on input");
3334 input += sizeof(afs_int32);
3335 destRemaining -= sizeof(afs_int32);
3336 for (; ti; ti = ti->next) {
3338 if( FAILED(StringCbCopyEx(input, destRemaining, ti->data, &input, &destRemaining, STRSAFE_FILL_ON_FAILURE))) {
3339 fprintf(stderr, "%s: sysname%s too long.\n", pn,
3340 setp > 1 ? "s" : "");
3344 destRemaining -= sizeof(char);
3346 blob.in_size = (input - space) * sizeof(char);
3348 memcpy(space, &setp, sizeof(afs_int32));
3350 err = memcpy_s(space, sizeof(space), &setp, sizeof(afs_int32));
3352 fprintf (stderr, "memcpy_s failure on space");
3357 code = pioctl_utf8(0, VIOC_AFS_SYSNAME, &blob, 1);
3363 printf("%s: new sysname%s set.\n", pn, setp > 1 ? " list" : "");
3369 memcpy(&setp, input, sizeof(afs_int32));
3371 err = memcpy_s(&setp, sizeof(setp), input, sizeof(afs_int32));
3373 fprintf (stderr, "memcpy_s failure on setp");
3377 input += sizeof(afs_int32);
3379 fprintf(stderr,"No sysname name value was found\n");
3382 space[blob.out_size - 1] = '\0';
3383 printf("Current sysname%s is", setp > 1 ? " list" : "");
3384 for (; setp > 0; --setp ) {
3385 printf(" \'%s\'", input);
3386 if( FAILED(StringCbLength(input, sizeof(space) - (input - space), &len))) {
3387 fprintf (stderr, "StringCbLength failure on input");
3396 #ifndef AFS_NT40_ENV
3397 static char *exported_types[] = {"null", "nfs", ""};
3398 static int ExportAfsCmd(struct cmd_syndesc *as, void *arock)
3401 struct ViceIoctl blob;
3402 struct cmd_item *ti;
3403 int export = 0, type = 0, mode = 0, exp = 0, gstat = 0;
3404 int exportcall, pwsync = 0, smounts = 0;
3408 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3413 fprintf (stderr,"Permission denied: requires root access.\n");
3418 ti = as->parms[0].items;
3419 if (strcmp(ti->data, "nfs") == 0)
3420 type = 0x71; /* NFS */
3423 "Invalid exporter type, '%s', Only the 'nfs' exporter is currently supported\n", ti->data);
3426 ti = as->parms[1].items;
3428 if (strcmp(ti->data, "on") == 0)
3430 else if (strcmp(ti->data, "off") == 0)
3433 fprintf(stderr, "Illegal argument %s\n", ti->data);
3438 if (ti = as->parms[2].items) { /* -noconvert */
3439 if (strcmp(ti->data, "on") == 0)
3441 else if (strcmp(ti->data, "off") == 0)
3444 fprintf(stderr, "Illegal argument %s\n", ti->data);
3448 if (ti = as->parms[3].items) { /* -uidcheck */
3449 if (strcmp(ti->data, "on") == 0)
3451 else if (strcmp(ti->data, "off") == 0)
3454 fprintf(stderr, "Illegal argument %s\n", ti->data);
3458 if (ti = as->parms[4].items) { /* -submounts */
3459 if (strcmp(ti->data, "on") == 0)
3461 else if (strcmp(ti->data, "off") == 0)
3464 fprintf(stderr, "Illegal argument %s\n", ti->data);
3468 exportcall = (type << 24) | (mode << 6) | (pwsync << 4) | (smounts << 2) | export;
3471 blob.in = (char *) &exportcall;
3472 blob.in_size = sizeof(afs_int32);
3473 blob.out = (char *) &exportcall;
3474 blob.out_size = sizeof(afs_int32);
3475 code = pioctl_utf8(0, VIOC_EXPORTAFS, &blob, 1);
3477 if (errno == ENODEV) {
3479 "Sorry, the %s-exporter type is currently not supported on this AFS client\n", exported_types[type]);
3486 if (exportcall & 1) {
3487 printf("'%s' translator is enabled with the following options:\n\tRunning in %s mode\n\tRunning in %s mode\n\t%s\n",
3488 exported_types[type], (exportcall & 2 ? "strict unix" : "convert owner mode bits to world/other"),
3489 (exportcall & 4 ? "strict 'passwd sync'" : "no 'passwd sync'"),
3490 (exportcall & 8 ? "Allow mounts of /afs/.. subdirs" : "Only mounts to /afs allowed"));
3492 printf("'%s' translator is disabled\n", exported_types[type]);
3501 GetCellCmd(struct cmd_syndesc *as, void *arock)
3504 struct ViceIoctl blob;
3505 struct afsconf_cell info;
3506 struct cmd_item *ti;
3514 memset(&info, 0, sizeof(info));
3515 memset(&args, 0, sizeof(args)); /* avoid Purify UMR error */
3516 for(ti=as->parms[0].items; ti; ti=ti->next) {
3518 blob.out_size = sizeof(args);
3519 blob.out = (caddr_t) &args;
3520 code = GetCellName(ti->data, &info);
3525 if (info.linkedCell)
3526 free(info.linkedCell);
3527 if( FAILED(StringCbLength(info.name, sizeof(info.name), &len))) {
3528 fprintf (stderr, "StringCbLength failure on info.name");
3531 blob.in_size = 1+(long)len;
3532 blob.in = info.name;
3533 code = pioctl_utf8(0, VIOC_GETCELLSTATUS, &blob, 1);
3535 if (errno == ENOENT)
3536 fprintf(stderr,"%s: the cell named '%s' does not exist\n", pn, info.name);
3538 Die(errno, info.name);
3542 printf("Cell %s status: ", info.name);
3548 printf("no setuid allowed");
3550 printf("setuid allowed");
3552 printf(", using old VLDB");
3558 static int SetCellCmd(struct cmd_syndesc *as, void *arock)
3561 struct ViceIoctl blob;
3562 struct afsconf_cell info;
3563 struct cmd_item *ti;
3571 memset(&info, 0, sizeof(info));
3573 /* Check arguments. */
3574 if (as->parms[1].items && as->parms[2].items) {
3575 fprintf(stderr, "Cannot specify both -suid and -nosuid.\n");
3579 /* figure stuff to set */
3585 fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
3590 fprintf (stderr,"Permission denied: requires root access.\n");
3595 if (! as->parms[1].items)
3596 args.stat |= CM_SETCELLFLAG_SUID; /* default to -nosuid */
3598 /* set stat for all listed cells */
3599 for(ti=as->parms[0].items; ti; ti=ti->next) {
3601 code = GetCellName(ti->data, &info);
3606 if (info.linkedCell)
3607 free(info.linkedCell);
3608 if( FAILED(StringCbCopy(args.cname, sizeof(args.cname), info.name))) {
3609 fprintf (stderr, "cname - not enough space");
3612 blob.in_size = sizeof(args);
3613 blob.in = (caddr_t) &args;
3615 blob.out = (caddr_t) 0;
3616 code = pioctl_utf8(0, VIOC_SETCELLSTATUS, &blob, 1);
3618 Die(errno, info.name); /* XXX added cell name to Die() call */
3626 GetCellName(char *cellNamep, struct afsconf_cell *infop)
3628 if( FAILED(StringCbCopy(infop->name, sizeof(infop->name), cellNamep))) {
3629 fprintf (stderr, "name - not enough space");
3636 VLDBInit(int noAuthFlag, struct afsconf_cell *info)
3641 cm_GetConfigDir(confDir, sizeof(confDir));
3643 code = ugen_ClientInit(noAuthFlag, confDir,
3644 info->name, 0, &uclient,
3645 NULL, pn, rxkad_clear,