no-more-ini-files-20040713
[openafs.git] / src / WINNT / afsd / fs.c
index 1ad8aaf..ac32533 100644 (file)
 #include <osi.h>
 #include <afsint.h>
 
-typedef long afs_int32;
-typedef unsigned long afs_uint32;
-typedef short afs_int16;
-typedef unsigned short afs_uint16;
-
 #include "fs.h"
 #include "fs_utils.h"
 #include "cmd.h"
@@ -48,6 +43,8 @@ static char tspace[1024];
 static struct ubik_client *uclient;
 #endif /* not WIN32 */
 
+static MemDumpCmd(struct cmd_syndesc *asp);
+static CSCPolicyCmd(struct cmd_syndesc *asp);
 
 extern afs_int32 VL_GetEntryByNameO();
 
@@ -519,25 +516,25 @@ char *name; {
     double QuotaUsed =0.0;
     double PartUsed =0.0;
     int WARN = 0;
-    printf("%-20s",name);
+    printf("%-25.25s",name);
 
     if (status->MaxQuota != 0) {
-       printf("%8d%8d", status->MaxQuota, status->BlocksInUse);
+       printf("%10d%10d", status->MaxQuota, status->BlocksInUse);
        QuotaUsed = ((((double)status->BlocksInUse)/status->MaxQuota) * 100.0);
     } else {
-       printf("no limit%8d", status->BlocksInUse);
+       printf("no limit%10d", status->BlocksInUse);
     }
     if (QuotaUsed > 90.0){
-       printf(" %8.0f%%<<", QuotaUsed);
+       printf(" %5.0f%%<<", QuotaUsed);
        WARN = 1;
     }
-    else printf(" %8.0f%%  ", QuotaUsed);
+    else printf(" %5.0f%%  ", QuotaUsed);
     PartUsed = (100.0 - ((((double)status->PartBlocksAvail)/status->PartMaxBlocks) * 100.0));
     if (PartUsed > 97.0){
-       printf(" %8.0f%%<<", PartUsed);
+       printf(" %9.0f%%<<", PartUsed);
        WARN = 1;
     }
-    else printf(" %8.0f%%  ", PartUsed);
+    else printf(" %9.0f%%  ", PartUsed);
     if (WARN){
        printf("\t<<WARNING\n");
     }
@@ -549,16 +546,16 @@ VolumeStatus *status;
 char *name; {
     double PartUsed =0.0;
     int WARN = 0;
-    printf("%-20s",name);
+    printf("%-25.25s",name);
 
-    printf("%8d%8d%8d", status->PartMaxBlocks, status->PartMaxBlocks - status->PartBlocksAvail, status->PartBlocksAvail);
+    printf("%10d%10d%10d", status->PartMaxBlocks, status->PartMaxBlocks - status->PartBlocksAvail, status->PartBlocksAvail);
        
     PartUsed = (100.0 - ((((double)status->PartBlocksAvail)/status->PartMaxBlocks) * 100.0));
     if (PartUsed > 90.0){
-       printf(" %8.0f%%<<", PartUsed);
+       printf(" %4.0f%%<<", PartUsed);
        WARN = 1;
     }
-    else printf(" %8.0f%%  ", PartUsed);
+    else printf(" %4.0f%%  ", PartUsed);
     if (WARN){
        printf("\t<<WARNING\n");
     }
@@ -586,6 +583,69 @@ char *AclToString(acl)
     return mydata;
 }
 
+BOOL IsAdmin (void)
+{
+    static BOOL fAdmin = FALSE;
+    static BOOL fTested = FALSE;
+
+    if (!fTested)
+    {
+        /* Obtain the SID for BUILTIN\Administrators. If this is Windows NT,
+         * expect this call to succeed; if it does not, we can presume that
+         * it's not NT and therefore the user always has administrative
+         * privileges.
+         */
+        PSID psidAdmin = NULL;
+        SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
+
+        fTested = TRUE;
+
+        if (!AllocateAndInitializeSid (&auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin))
+            fAdmin = TRUE;
+        else
+        {
+            /* Then open our current ProcessToken */
+            HANDLE hToken;
+
+            if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
+            {
+                /* We'll have to allocate a chunk of memory to store the list of
+                 * groups to which this user belongs; find out how much memory
+                 * we'll need.
+                 */
+                DWORD dwSize = 0;
+                PTOKEN_GROUPS pGroups;
+                
+                GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
+            
+                pGroups = (PTOKEN_GROUPS)malloc(dwSize);
+                
+                /* Allocate that buffer, and read in the list of groups. */
+                if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
+                {
+                    /* Look through the list of group SIDs and see if any of them
+                     * matches the Administrator group SID.
+                     */
+                    size_t iGroup = 0;
+                    for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
+                    {
+                        if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid))
+                            fAdmin = TRUE;
+                    }
+                }
+
+                if (pGroups)
+                    free(pGroups);
+            }
+        }
+
+        if (psidAdmin)
+            FreeSid (psidAdmin);
+    }
+
+    return fAdmin;
+}
+
 static SetACLCmd(as)
 struct cmd_syndesc *as; {
     register afs_int32 code;
@@ -1114,8 +1174,8 @@ register struct cmd_syndesc *as; {
     struct VolumeStatus *status;
     char *name;
     
-    printf("%-20s%-9s%-8s%-11s%-11s\n",
-           "Volume Name","   Quota", "   Used", "   % Used", " Partition");
+    printf("%-25s%-10s%-10s%-7s%-13s\n", 
+           "Volume Name", "     Quota", "      Used", "  %Used", "    Partition");
     SetDotDefault(&as->parms[0].items);
     for(ti=as->parms[0].items; ti; ti=ti->next) {
        /* once per file */
@@ -1176,8 +1236,8 @@ register struct cmd_syndesc *as; {
     char *name;
     struct VolumeStatus *status;
     
-    printf("%-20s%-9s%-8s%-11s%-11s\n",
-           "Volume Name","  kbytes ", " used", "  avail ", " %used");
+    printf("%-25s%-10s%-10s%-10s%-6s\n", "Volume Name", "    kbytes",
+          "      used", "     avail", " %used");
     SetDotDefault(&as->parms[0].items);
     for(ti=as->parms[0].items; ti; ti=ti->next) {
        /* once per file */
@@ -1588,12 +1648,26 @@ register struct cmd_syndesc *as; {
                } else if(checkserv.tinterval> 600) {
                    printf("Warning: The maximum -interval value is 10 mins (600 secs)\n");
                    checkserv.tinterval=600;    /* 10 min max interval */
-              }
+        }
        }
        else {
-         checkserv.tinterval = -1;     /* don't change current interval */
+        checkserv.tinterval = -1;      /* don't change current interval */
        }
 
+    if ( checkserv.tinterval != 0 ) {
+#ifdef WIN32
+        if ( !IsAdmin() ) {
+            fprintf (stderr,"Permission denied: requires Administrator access.\n");
+            return EACCES;
+        }
+#else /* WIN32 */
+        if (geteuid()) {
+            fprintf (stderr,"Permission denied: requires root access.\n");
+            return EACCES;
+        }
+#endif /* WIN32 */
+    }
+
     code = pioctl(0, VIOCCKSERV, &blob, 1);
     if (code) {
        if ((errno == EACCES) && (checkserv.tinterval > 0)) {
@@ -1693,6 +1767,18 @@ register struct cmd_syndesc *as; {
     struct ViceIoctl blob;
     afs_int32 temp;
     
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
     if (!as->parms[0].items && !as->parms[1].items) {
        fprintf(stderr,"%s: syntax error in set cache size cmd.\n", pn);
        return 1;
@@ -1754,7 +1840,7 @@ register struct cmd_syndesc *as; {
        tp = (char *)(space + sizeof(afs_int32));
        lp = (afs_int32 *)tp;
        *lp++ = 0x12345678;
-       size == sizeof(afs_int32) + sizeof(afs_int32);
+       size = sizeof(afs_int32) + sizeof(afs_int32);
        blob.out_size = MAXSIZE;
        blob.in_size = sizeof(afs_int32);
        blob.in = space;
@@ -1795,6 +1881,18 @@ register struct cmd_syndesc *as; {
     register struct hostent *thp;
     afs_int32 fsport = 0, vlport = 0;
 
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
     memset(space, 0, MAXHOSTS * sizeof(afs_int32));
     tp = space;
     lp = (afs_int32 *)tp;
@@ -1855,9 +1953,22 @@ register struct cmd_syndesc *as; {
        Die(errno, 0);
     return 0;
 #else /* WIN32 */
-       fprintf(stderr, "fs: 'newcell' not implemented, since afsdcell.ini is\n");
-       fprintf(stderr, "fs: re-read on every reference to a new cell, on Windows/NT.\n");
-        return -1;
+    register afs_int32 code;
+    struct ViceIoctl blob;
+    
+    blob.in_size = 0;
+    blob.in = (char *) 0;
+    blob.out_size = MAXSIZE;
+    blob.out = space;
+
+    code = pioctl((char *) 0, VIOCNEWCELL, &blob, 1);
+
+    if (code) {
+       Die(errno, (char *) 0);
+    }
+    else
+       printf("Cell servers information refreshed\n");
+    return 0;
 #endif /* WIN32 */
 }
 
@@ -1985,42 +2096,68 @@ static SysNameCmd(as)
 register struct cmd_syndesc *as; {
     register afs_int32 code;
     struct ViceIoctl blob;
-    register struct cmd_item *ti;
+    struct cmd_item *ti;
     char *input = space;
-    afs_int32 setp = 1;
+    afs_int32 setp = 0;
     
     ti = as->parms[0].items;
-    if (!ti) setp = 0;
+    if (ti) {
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+    }
+
     blob.in = space;
     blob.out = space;
     blob.out_size = MAXSIZE;
     blob.in_size = sizeof(afs_int32);
     memcpy(input, &setp, sizeof(afs_int32));
     input += sizeof(afs_int32);
-    if (ti) {
-       strcpy(input, ti->data);
-       blob.in_size += strlen(ti->data) + 1;
-       input += strlen(ti->data);
-       *(input++) = '\0';
+    for (; ti; ti = ti->next) {
+        setp++;
+        blob.in_size += strlen(ti->data) + 1;
+        if (blob.in_size > MAXSIZE) {
+            fprintf(stderr, "%s: sysname%s too long.\n", pn,
+                     setp > 1 ? "s" : "");
+            return 1;
+        }
+        strcpy(input, ti->data);
+        input += strlen(ti->data);
+        *(input++) = '\0';
     }
+    memcpy(space, &setp, sizeof(afs_int32));
     code = pioctl(0, VIOC_AFS_SYSNAME, &blob, 1);
     if (code) {
-       Die(errno, 0);
-       exit(1);
+        Die(errno, 0);
+        return 1;
     }    
     if (setp) {
-       printf("%s: new sysname set.\n", pn);
+        printf("%s: new sysname%s set.\n", pn, setp > 1 ? "s" : "");
+        return 0;
     }
-    else {
+
        input = space;
        memcpy(&setp, input, sizeof(afs_int32));
        input += sizeof(afs_int32);
        if (!setp) {
            fprintf(stderr,"No sysname name value was found\n");
-       } else {
-           printf("Current sysname is '%s'\n", input);
+        return 1;
+       } 
+    
+    printf("Current sysname%s", setp > 1 ? "s are" : " is");
+    for (; setp > 0; --setp ) {
+        printf(" \'%s\'", input);
+        input += strlen(input) + 1;
        }
-    }
+    printf("\n");
     return 0;
 }
 
@@ -2032,6 +2169,18 @@ register struct cmd_syndesc *as; {
     register struct cmd_item *ti;
     int export=0, type=0, mode = 0, exp = 0, gstat = 0, exportcall, pwsync=0, smounts=0;
     
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
     ti = as->parms[0].items;
     if (strcmp(ti->data, "nfs")        == 0) type = 0x71; /* NFS */
     else {
@@ -2099,6 +2248,7 @@ register struct cmd_syndesc *as; {
            }
        }
     }
+    return(0);
 }
 
 
@@ -2159,6 +2309,18 @@ register struct cmd_syndesc *as; {
     args.stat = 0;
     args.junk = 0;
 
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
     if (! as->parms[1].items) args.stat |= CM_SETCELLFLAG_SUID; /* default to -nosuid */
 
     /* set stat for all listed cells */
@@ -2282,6 +2444,8 @@ struct afsconf_cell *info;
                                          info->hostAddr[i].sin_port, USER_SERVICE_ID,
                                          sc, scIndex);
 
+    if (sc)
+        rxs_Release(sc);    /* Decrement the initial refCount */
     code = ubik_ClientInit(serverconns, &uclient);
 
     if (code) {
@@ -2360,6 +2524,29 @@ static addServer(name, rank)
        return code;
 }
 
+static BOOL IsWindowsNT (void)
+{
+    static BOOL fChecked = FALSE;
+    static BOOL fIsWinNT = FALSE;
+
+    if (!fChecked)
+    {
+        OSVERSIONINFO Version;
+
+        fChecked = TRUE;
+
+        memset (&Version, 0x00, sizeof(Version));
+        Version.dwOSVersionInfoSize = sizeof(Version);
+
+        if (GetVersionEx (&Version))
+        {
+            if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT)
+                fIsWinNT = TRUE;
+        }
+    }
+    return fIsWinNT;
+}
+
 
 static SetPrefCmd(as)
 register struct cmd_syndesc *as; {
@@ -2378,12 +2565,16 @@ register struct cmd_syndesc *as; {
   gblob.out = space;
   gblob.out_size = MAXSIZE;
 
-
-#ifndef WIN32
-  if (geteuid()) {
-    fprintf (stderr,"Permission denied: requires root access.\n");
-    return EACCES;
-  }
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
 #endif /* WIN32 */
 
   code = 0;
@@ -2521,33 +2712,45 @@ register struct cmd_syndesc *as; {
     }
   } while (!code && out->next_offset > 0);
 
-return code;
+    return code;
 }
 
 static TraceCmd(struct cmd_syndesc *asp)
 {
        long code;
-        struct ViceIoctl blob;
-        long inValue;
-        long outValue;
-        
-        if ((asp->parms[0].items && asp->parms[1].items)) {
-               fprintf(stderr, "fs trace: must use at most one of '-off' or '-on'\n");
-                return EINVAL;
+    struct ViceIoctl blob;
+    long inValue;
+    long outValue;
+    
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+        if (geteuid()) {
+            fprintf (stderr,"Permission denied: requires root access.\n");
+            return EACCES;
         }
+#endif /* WIN32 */
+
+    if ((asp->parms[0].items && asp->parms[1].items)) {
+               fprintf(stderr, "fs trace: must use at most one of '-off' or '-on'\n");
+        return EINVAL;
+    }
         
        /* determine if we're turning this tracing on or off */
        inValue = 0;
-        if (asp->parms[0].items)
-               inValue = 3;            /* enable */
+    if (asp->parms[0].items)
+        inValue = 3;           /* enable */
        else if (asp->parms[1].items) inValue = 2;      /* disable */
-        if (asp->parms[2].items) inValue |= 4;         /* do reset */
+    if (asp->parms[2].items) inValue |= 4;             /* do reset */
        if (asp->parms[3].items) inValue |= 8;          /* dump */
         
-        blob.in_size = sizeof(long);
-        blob.in = (char *) &inValue;
-        blob.out_size = sizeof(long);
-        blob.out = (char *) &outValue;
+    blob.in_size = sizeof(long);
+    blob.in = (char *) &inValue;
+    blob.out_size = sizeof(long);
+    blob.out = (char *) &outValue;
         
        code = pioctl(NULL, VIOC_TRACECTL, &blob, 1);
        if (code) {
@@ -2555,10 +2758,10 @@ static TraceCmd(struct cmd_syndesc *asp)
                return code;
        }
         
-        if (outValue) printf("AFS tracing enabled.\n");
-        else printf("AFS tracing disabled.\n");
+    if (outValue) printf("AFS tracing enabled.\n");
+    else printf("AFS tracing disabled.\n");
 
-        return 0;
+    return 0;
 }
 
 static void sbusage()
@@ -2575,6 +2778,18 @@ struct cmd_syndesc *as; {
     struct sbstruct tsb;
     int kb;
     
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
     if ((as->parms[0].items && as->parms[1].items) ||   
         (!as->parms[0].items && !as->parms[1].items)) /* same as logical xor */
       ;
@@ -2628,6 +2843,18 @@ static afs_int32 SetCryptCmd(as)
     struct ViceIoctl blob;
     char *tp;
  
+#ifdef WIN32
+    if ( !IsAdmin() ) {
+        fprintf (stderr,"Permission denied: requires Administrator access.\n");
+        return EACCES;
+    }
+#else /* WIN32 */
+    if (geteuid()) {
+        fprintf (stderr,"Permission denied: requires root access.\n");
+        return EACCES;
+    }
+#endif /* WIN32 */
+
     tp = as->parms[0].items->data;
     if (strcmp(tp, "on") == 0)
       flag = 1;
@@ -2716,7 +2943,7 @@ char **argv; {
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "output to named file");
     cmd_AddParm(ts, "-numeric", CMD_FLAG, CMD_OPTIONAL, "addresses only");
     cmd_AddParm(ts, "-vlservers", CMD_FLAG, CMD_OPTIONAL, "VL servers");
-/*    cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */
+    /* cmd_AddParm(ts, "-cell", CMD_FLAG, CMD_OPTIONAL, "cellname"); */
     cmd_CreateAlias(ts, "gp");
 
     ts = cmd_CreateSyntax("setacl", SetACLCmd, 0, "set access control list");
@@ -2791,12 +3018,12 @@ char **argv; {
     cmd_AddParm(ts, "-rw", CMD_FLAG, CMD_OPTIONAL, "force r/w volume");
     cmd_AddParm(ts, "-fast", CMD_FLAG, CMD_OPTIONAL, "don't check name with VLDB");
 
-/*
-
-defect 3069
-
+    /*
+     *
+     * defect 3069
+     * 
     cmd_AddParm(ts, "-root", CMD_FLAG, CMD_OPTIONAL, "create cellular mount point");
-*/
+    */
 
     
     ts = cmd_CreateSyntax("rmmount", RemoveMountCmd, 0, "remove mount point");
@@ -2831,17 +3058,19 @@ defect 3069
     cmd_CreateAlias(ts, "sq");
 
     ts = cmd_CreateSyntax("newcell", NewCellCmd, 0, "configure new cell");
+#ifndef WIN32
     cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "cell name");
     cmd_AddParm(ts, "-servers", CMD_LIST, CMD_REQUIRED, "primary servers");
     cmd_AddParm(ts, "-linkedcell", CMD_SINGLE, CMD_OPTIONAL, "linked cell name");
+#endif
 
 #ifdef FS_ENABLE_SERVER_DEBUG_PORTS
-/*
- * Turn this on only if you wish to be able to talk to a server which is listening
- * on alternative ports. This is not intended for general use and may not be
- * supported in the cache manager. It is not a way to run two servers at the
- * same host, since the cache manager cannot properly distinguish those two hosts.
- */
+    /*
+     * Turn this on only if you wish to be able to talk to a server which is listening
+     * on alternative ports. This is not intended for general use and may not be
+     * supported in the cache manager. It is not a way to run two servers at the
+     * same host, since the cache manager cannot properly distinguish those two hosts.
+     */
     cmd_AddParm(ts, "-fsport", CMD_SINGLE, CMD_OPTIONAL, "cell's fileserver port");
     cmd_AddParm(ts, "-vlport", CMD_SINGLE, CMD_OPTIONAL, "cell's vldb server port");
 #endif
@@ -2854,9 +3083,9 @@ defect 3069
 
     ts = cmd_CreateSyntax("wscell", WSCellCmd, 0, "list workstation's cell");
     
-/*
-    ts = cmd_CreateSyntax("primarycell", PrimaryCellCmd, 0, "obsolete (listed primary cell)");
-*/
+    /*
+     ts = cmd_CreateSyntax("primarycell", PrimaryCellCmd, 0, "obsolete (listed primary cell)");
+     */
     
     ts = cmd_CreateSyntax("monitor", MonitorCmd, 0, "set cache monitor host address");
     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL, "host name or 'off'");
@@ -2904,6 +3133,17 @@ defect 3069
     cmd_AddParm(ts, "-dump", CMD_FLAG, CMD_OPTIONAL, "dump log contents");
     cmd_CreateAlias(ts, "tr");
 
+    ts = cmd_CreateSyntax("memdump", MemDumpCmd, 0, "dump memory allocs in debug builds");
+    cmd_AddParm(ts, "-begin", CMD_FLAG, CMD_OPTIONAL, "set a memory checkpoint");
+    cmd_AddParm(ts, "-end", CMD_FLAG, CMD_OPTIONAL, "dump memory allocs");
+    
+    ts = cmd_CreateSyntax("cscpolicy", CSCPolicyCmd, 0, "change client side caching policy for AFS shares");
+    cmd_AddParm(ts, "-share", CMD_SINGLE, CMD_OPTIONAL, "AFS share");
+    cmd_AddParm(ts, "-manual", CMD_FLAG, CMD_OPTIONAL, "manual caching of documents");
+    cmd_AddParm(ts, "-programs", CMD_FLAG, CMD_OPTIONAL, "automatic caching of programs and documents");
+    cmd_AddParm(ts, "-documents", CMD_FLAG, CMD_OPTIONAL, "automatic caching of documents");
+    cmd_AddParm(ts, "-disable", CMD_FLAG, CMD_OPTIONAL, "disable caching");
+
     code = cmd_Dispatch(argc, argv);
 
 #ifndef WIN32
@@ -2960,3 +3200,141 @@ void Die(code, filename)
 #endif /* not WIN32 */
     }
 } /*Die*/
+
+static MemDumpCmd(struct cmd_syndesc *asp)
+{
+    long code;
+    struct ViceIoctl blob;
+    long inValue;
+    long outValue;
+  
+    if ((asp->parms[0].items && asp->parms[1].items)) {
+        fprintf(stderr, "fs trace: must use at most one of '-begin' or '-end'\n");
+        return EINVAL;
+    }
+  
+    /* determine if we're turning this tracing on or off */
+    inValue = 0;
+    if (asp->parms[0].items)
+        inValue = 1;            /* begin */
+    else if (asp->parms[1].items) 
+        inValue = 0;            /* end */
+  
+    blob.in_size = sizeof(long);
+    blob.in = (char *) &inValue;
+    blob.out_size = sizeof(long);
+    blob.out = (char *) &outValue;
+
+    code = pioctl(NULL, VIOC_TRACEMEMDUMP, &blob, 1);
+    if (code) {
+        Die(errno, NULL);
+        return code;
+    }
+
+    if (outValue) printf("AFS memdump begin.\n");
+    else printf("AFS memdump end.\n");
+
+    return 0;
+}
+
+static CSCPolicyCmd(struct cmd_syndesc *asp)
+{
+       struct cmd_item *ti;
+       char *share = NULL;
+    HKEY hkCSCPolicy;
+
+       for(ti=asp->parms[0].items; ti;ti=ti->next) {
+               share = ti->data;
+               if (share)
+               {
+                       break;
+               }
+       }
+
+       if (share)
+       {
+        char *policy;
+
+        RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+                        "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
+                        0, 
+                        "AFS", 
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_WRITE,
+                        NULL, 
+                        &hkCSCPolicy,
+                        NULL );
+
+        if ( !IsAdmin() || hkCSCPolicy == NULL ) {
+            fprintf (stderr,"Permission denied: requires Administrator access.\n");
+            if ( hkCSCPolicy )
+                RegCloseKey(hkCSCPolicy);
+            return EACCES;
+        }
+
+        policy = "manual";
+               
+               if (asp->parms[1].items)
+                       policy = "manual";
+               if (asp->parms[2].items)
+                       policy = "programs";
+               if (asp->parms[3].items)
+                       policy = "documents";
+               if (asp->parms[4].items)
+                       policy = "disable";
+               
+        RegSetValueEx( hkCSCPolicy, share, 0, REG_SZ, policy, strlen(policy)+1);
+               
+               printf("CSC policy on share \"%s\" changed to \"%s\".\n\n", share, policy);
+               printf("Close all applications that accessed files on this share or restart AFS Client for the change to take effect.\n"); 
+       }
+       else
+       {
+        DWORD dwIndex, dwPolicies;
+               char policyName[256];
+               DWORD policyNameLen;
+        char policy[256];
+        DWORD policyLen;
+        DWORD dwType;
+
+               /* list current csc policies */
+               
+        RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+                        "SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
+                        0, 
+                        "AFS", 
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ|KEY_QUERY_VALUE,
+                        NULL, 
+                        &hkCSCPolicy,
+                        NULL );
+
+        RegQueryInfoKey( hkCSCPolicy,
+                         NULL,  /* lpClass */
+                         NULL,  /* lpcClass */
+                         NULL,  /* lpReserved */
+                         NULL,  /* lpcSubKeys */
+                         NULL,  /* lpcMaxSubKeyLen */
+                         NULL,  /* lpcMaxClassLen */
+                         &dwPolicies, /* lpcValues */
+                         NULL,  /* lpcMaxValueNameLen */
+                         NULL,  /* lpcMaxValueLen */
+                         NULL,  /* lpcbSecurityDescriptor */
+                         NULL   /* lpftLastWriteTime */
+                         );
+               
+               printf("Current CSC policies:\n");
+        for ( dwIndex = 0; dwIndex < dwPolicies; dwIndex ++ ) {
+
+            policyNameLen = sizeof(policyName);
+            policyLen = sizeof(policy);
+            RegEnumValue( hkCSCPolicy, dwIndex, policyName, &policyNameLen, NULL,
+                          &dwType, policy, &policyLen);
+
+                       printf("  %s = %s\n", policyName, policy);
+               }
+       }
+
+    RegCloseKey(hkCSCPolicy);
+       return (0);
+}