Added prefer_ipv4 bool parameter to resolve_name().
[ira/wip.git] / source3 / torture / torture.c
index 00e8266a22af8a359aaabc00ce6ea9c87eef51aa..babcb1e7d0e0cfc6a0ba0418202fa4d4e32fd6c2 100644 (file)
@@ -18,7 +18,7 @@
 */
 
 #include "includes.h"
-#include "wbc_async.h"
+#include "nsswitch/libwbclient/wbc_async.h"
 
 extern char *optarg;
 extern int optind;
@@ -492,7 +492,7 @@ static bool rw_torture(struct cli_state *c)
                        correct = False;
                }
 
-               if (!cli_unlock(c, fnum2, n*sizeof(int), sizeof(int))) {
+               if (!NT_STATUS_IS_OK(cli_unlock(c, fnum2, n*sizeof(int), sizeof(int)))) {
                        printf("unlock failed (%s)\n", cli_errstr(c));
                        correct = False;
                }
@@ -705,7 +705,7 @@ static bool rw_torture2(struct cli_state *c1, struct cli_state *c2)
 
 static bool run_readwritetest(int dummy)
 {
-       static struct cli_state *cli1, *cli2;
+       struct cli_state *cli1, *cli2;
        bool test1, test2 = False;
 
        if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
@@ -1429,12 +1429,12 @@ static bool run_locktest2(int dummy)
                printf("lock at 100 failed (%s)\n", cli_errstr(cli));
        }
        cli_setpid(cli, 2);
-       if (cli_unlock(cli, fnum1, 100, 4)) {
+       if (NT_STATUS_IS_OK(cli_unlock(cli, fnum1, 100, 4))) {
                printf("unlock at 100 succeeded! This is a locking bug\n");
                correct = False;
        }
 
-       if (cli_unlock(cli, fnum1, 0, 4)) {
+       if (NT_STATUS_IS_OK(cli_unlock(cli, fnum1, 0, 4))) {
                printf("unlock1 succeeded! This is a locking bug\n");
                correct = False;
        } else {
@@ -1443,7 +1443,7 @@ static bool run_locktest2(int dummy)
                                 NT_STATUS_RANGE_NOT_LOCKED)) return False;
        }
 
-       if (cli_unlock(cli, fnum1, 0, 8)) {
+       if (NT_STATUS_IS_OK(cli_unlock(cli, fnum1, 0, 8))) {
                printf("unlock2 succeeded! This is a locking bug\n");
                correct = False;
        } else {
@@ -1565,14 +1565,14 @@ static bool run_locktest3(int dummy)
        for (offset=i=0;i<torture_numops;i++) {
                NEXT_OFFSET;
 
-               if (!cli_unlock(cli1, fnum1, offset-1, 1)) {
+               if (!NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, offset-1, 1))) {
                        printf("unlock1 %d failed (%s)\n", 
                               i,
                               cli_errstr(cli1));
                        return False;
                }
 
-               if (!cli_unlock(cli2, fnum2, offset-2, 1)) {
+               if (!NT_STATUS_IS_OK(cli_unlock(cli2, fnum2, offset-2, 1))) {
                        printf("unlock2 %d failed (%s)\n", 
                               i,
                               cli_errstr(cli1));
@@ -1703,7 +1703,7 @@ static bool run_locktest4(int dummy)
 
        ret = cli_lock(cli1, fnum1, 110, 4, 0, READ_LOCK) &&
              cli_lock(cli1, fnum1, 112, 4, 0, READ_LOCK) &&
-             cli_unlock(cli1, fnum1, 110, 6);
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 110, 6));
        EXPECTED(ret, False);
        printf("the same process %s coalesce read locks\n", ret?"can":"cannot");
 
@@ -1721,30 +1721,30 @@ static bool run_locktest4(int dummy)
 
        ret = cli_lock(cli1, fnum1, 140, 4, 0, READ_LOCK) &&
              cli_lock(cli1, fnum1, 140, 4, 0, READ_LOCK) &&
-             cli_unlock(cli1, fnum1, 140, 4) &&
-             cli_unlock(cli1, fnum1, 140, 4);
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 140, 4)) &&
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 140, 4));
        EXPECTED(ret, True);
        printf("this server %s do recursive read locking\n", ret?"does":"doesn't");
 
 
        ret = cli_lock(cli1, fnum1, 150, 4, 0, WRITE_LOCK) &&
              cli_lock(cli1, fnum1, 150, 4, 0, READ_LOCK) &&
-             cli_unlock(cli1, fnum1, 150, 4) &&
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 150, 4)) &&
              (cli_read(cli2, fnum2, buf, 150, 4) == 4) &&
              !(cli_write(cli2, fnum2, 0, buf, 150, 4) == 4) &&
-             cli_unlock(cli1, fnum1, 150, 4);
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 150, 4));
        EXPECTED(ret, True);
        printf("this server %s do recursive lock overlays\n", ret?"does":"doesn't");
 
        ret = cli_lock(cli1, fnum1, 160, 4, 0, READ_LOCK) &&
-             cli_unlock(cli1, fnum1, 160, 4) &&
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 160, 4)) &&
              (cli_write(cli2, fnum2, 0, buf, 160, 4) == 4) &&          
              (cli_read(cli2, fnum2, buf, 160, 4) == 4);                
        EXPECTED(ret, True);
        printf("the same process %s remove a read lock using write locking\n", ret?"can":"cannot");
 
        ret = cli_lock(cli1, fnum1, 170, 4, 0, WRITE_LOCK) &&
-             cli_unlock(cli1, fnum1, 170, 4) &&
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 170, 4)) &&
              (cli_write(cli2, fnum2, 0, buf, 170, 4) == 4) &&          
              (cli_read(cli2, fnum2, buf, 170, 4) == 4);                
        EXPECTED(ret, True);
@@ -1752,7 +1752,7 @@ static bool run_locktest4(int dummy)
 
        ret = cli_lock(cli1, fnum1, 190, 4, 0, WRITE_LOCK) &&
              cli_lock(cli1, fnum1, 190, 4, 0, READ_LOCK) &&
-             cli_unlock(cli1, fnum1, 190, 4) &&
+             NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 190, 4)) &&
              !(cli_write(cli2, fnum2, 0, buf, 190, 4) == 4) &&         
              (cli_read(cli2, fnum2, buf, 190, 4) == 4);                
        EXPECTED(ret, True);
@@ -1861,7 +1861,7 @@ static bool run_locktest5(int dummy)
        /* Unlock the first process lock, then check this was the WRITE lock that was
                removed. */
 
-       ret = cli_unlock(cli1, fnum1, 0, 4) &&
+       ret = NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 0, 4)) &&
                        cli_lock(cli2, fnum2, 0, 4, 0, READ_LOCK);
 
        EXPECTED(ret, True);
@@ -1872,15 +1872,15 @@ static bool run_locktest5(int dummy)
 
        /* We should have 3 stacked locks here. Ensure we need to do 3 unlocks. */
 
-       ret = cli_unlock(cli1, fnum1, 1, 1) &&
-                 cli_unlock(cli1, fnum1, 0, 4) &&
-                 cli_unlock(cli1, fnum1, 0, 4);
+       ret = NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 1, 1)) &&
+                 NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 0, 4)) &&
+                 NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 0, 4));
 
        EXPECTED(ret, True);
        printf("the same process %s unlock the stack of 4 locks\n", ret?"can":"cannot"); 
 
        /* Ensure the next unlock fails. */
-       ret = cli_unlock(cli1, fnum1, 0, 4);
+       ret = NT_STATUS_IS_OK(cli_unlock(cli1, fnum1, 0, 4));
        EXPECTED(ret, False);
        printf("the same process %s count the lock stack\n", !ret?"can":"cannot"); 
 
@@ -2083,6 +2083,80 @@ fail:
        return correct;
 }
 
+/*
+ * This demonstrates a problem with our use of GPFS share modes: A file
+ * descriptor sitting in the pending close queue holding a GPFS share mode
+ * blocks opening a file another time. Happens with Word 2007 temp files.
+ * With "posix locking = yes" and "gpfs:sharemodes = yes" enabled, the third
+ * open is denied with NT_STATUS_SHARING_VIOLATION.
+ */
+
+static bool run_locktest8(int dummy)
+{
+       struct cli_state *cli1;
+       const char *fname = "\\lockt8.lck";
+       uint16_t fnum1, fnum2;
+       char buf[200];
+       bool correct = False;
+       NTSTATUS status;
+
+       if (!torture_open_connection(&cli1, 0)) {
+               return False;
+       }
+
+       cli_sockopt(cli1, sockops);
+
+       printf("starting locktest8\n");
+
+       cli_unlink(cli1, fname, aSYSTEM | aHIDDEN);
+
+       status = cli_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, DENY_WRITE,
+                         &fnum1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "cli_open returned %s\n", cli_errstr(cli1));
+               return false;
+       }
+
+       memset(buf, 0, sizeof(buf));
+
+       status = cli_open(cli1, fname, O_RDONLY, DENY_NONE, &fnum2);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "cli_open second time returned %s\n",
+                         cli_errstr(cli1));
+               goto fail;
+       }
+
+       if (!cli_lock(cli1, fnum2, 1, 1, 0, READ_LOCK)) {
+               printf("Unable to apply read lock on range 1:1, error was "
+                      "%s\n", cli_errstr(cli1));
+               goto fail;
+       }
+
+       status = cli_close(cli1, fnum1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "cli_close(fnum1) %s\n", cli_errstr(cli1));
+               goto fail;
+       }
+
+       status = cli_open(cli1, fname, O_RDWR, DENY_NONE, &fnum1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_fprintf(stderr, "cli_open third time returned %s\n",
+                          cli_errstr(cli1));
+                goto fail;
+        }
+
+       correct = true;
+
+fail:
+       cli_close(cli1, fnum1);
+       cli_close(cli1, fnum2);
+       cli_unlink(cli1, fname, aSYSTEM | aHIDDEN);
+       torture_close_connection(cli1);
+
+       printf("finished locktest8\n");
+       return correct;
+}
+
 /*
 test whether fnums and tids open on one VC are available on another (a major
 security hole)
@@ -2471,7 +2545,7 @@ static bool run_attrtest(int dummy)
        cli_open(cli, fname, 
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE, &fnum);
        cli_close(cli, fnum);
-       if (!cli_getatr(cli, fname, NULL, NULL, &t)) {
+       if (!NT_STATUS_IS_OK(cli_getatr(cli, fname, NULL, NULL, &t))) {
                printf("getatr failed (%s)\n", cli_errstr(cli));
                correct = False;
        }
@@ -2485,12 +2559,12 @@ static bool run_attrtest(int dummy)
 
        t2 = t-60*60*24; /* 1 day ago */
 
-       if (!cli_setatr(cli, fname, 0, t2)) {
+       if (!NT_STATUS_IS_OK(cli_setatr(cli, fname, 0, t2))) {
                printf("setatr failed (%s)\n", cli_errstr(cli));
                correct = True;
        }
 
-       if (!cli_getatr(cli, fname, NULL, NULL, &t)) {
+       if (!NT_STATUS_IS_OK(cli_getatr(cli, fname, NULL, NULL, &t))) {
                printf("getatr failed (%s)\n", cli_errstr(cli));
                correct = True;
        }
@@ -3018,7 +3092,7 @@ static bool run_deletetest(int dummy)
                goto fail;
        }
 
-       if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[2] setting delete_on_close failed (%s)\n", cli_errstr(cli1));
                correct = False;
                goto fail;
@@ -3071,7 +3145,7 @@ static bool run_deletetest(int dummy)
                goto fail;
        }
 
-       if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[3] setting delete_on_close failed (%s)\n", cli_errstr(cli1));
                correct = False;
                goto fail;
@@ -3127,7 +3201,7 @@ static bool run_deletetest(int dummy)
                goto fail;
        }
 
-       if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[4] setting delete_on_close failed (%s)\n", cli_errstr(cli1));
                correct = False;
                goto fail;
@@ -3161,7 +3235,7 @@ static bool run_deletetest(int dummy)
 
        /* This should fail - only allowed on NT opens with DELETE access. */
 
-       if (cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[5] setting delete_on_close on OpenX file succeeded - should fail !\n");
                correct = False;
                goto fail;
@@ -3189,7 +3263,7 @@ static bool run_deletetest(int dummy)
 
        /* This should fail - only allowed on NT opens with DELETE access. */
 
-       if (cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[6] setting delete_on_close on file with no delete access succeeded - should fail !\n");
                correct = False;
                goto fail;
@@ -3214,13 +3288,13 @@ static bool run_deletetest(int dummy)
                goto fail;
        }
 
-       if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[7] setting delete_on_close on file failed !\n");
                correct = False;
                goto fail;
        }
 
-       if (!cli_nt_delete_on_close(cli1, fnum1, False)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, false))) {
                printf("[7] unsetting delete_on_close on file failed !\n");
                correct = False;
                goto fail;
@@ -3276,7 +3350,7 @@ static bool run_deletetest(int dummy)
                goto fail;
        }
 
-       if (!cli_nt_delete_on_close(cli1, fnum1, True)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum1, true))) {
                printf("[8] setting delete_on_close on file failed !\n");
                correct = False;
                goto fail;
@@ -3565,7 +3639,7 @@ static bool run_rename(int dummy)
                printf("Fourth open failed - %s\n", cli_errstr(cli1));
                return False;
        }
-       if (!cli_nt_delete_on_close(cli1, fnum2, True)) {
+       if (!NT_STATUS_IS_OK(cli_nt_delete_on_close(cli1, fnum2, true))) {
                printf("[8] setting delete_on_close on file failed !\n");
                return False;
        }
@@ -3726,7 +3800,7 @@ static bool run_opentest(int dummy)
                return False;
        }
 
-       if (!cli_setatr(cli1, fname, aRONLY, 0)) {
+       if (!NT_STATUS_IS_OK(cli_setatr(cli1, fname, aRONLY, 0))) {
                printf("cli_setatr failed (%s)\n", cli_errstr(cli1));
                return False;
        }
@@ -3796,7 +3870,7 @@ static bool run_opentest(int dummy)
        }
 
        /* Ensure size == 20. */
-       if (!cli_getatr(cli1, fname, NULL, &fsize, NULL)) {
+       if (!NT_STATUS_IS_OK(cli_getatr(cli1, fname, NULL, &fsize, NULL))) {
                printf("(3) getatr failed (%s)\n", cli_errstr(cli1));
                return False;
        }
@@ -3819,7 +3893,7 @@ static bool run_opentest(int dummy)
        }
 
        /* Ensure size == 0. */
-       if (!cli_getatr(cli1, fname, NULL, &fsize, NULL)) {
+       if (!NT_STATUS_IS_OK(cli_getatr(cli1, fname, NULL, &fsize, NULL))) {
                printf("(3) getatr failed (%s)\n", cli_errstr(cli1));
                return False;
        }
@@ -3834,8 +3908,7 @@ static bool run_opentest(int dummy)
 
 
        printf("testing ctemp\n");
-       fnum1 = cli_ctemp(cli1, "\\", &tmp_path);
-       if (fnum1 == (uint16_t)-1) {
+       if (!NT_STATUS_IS_OK(cli_ctemp(cli1, talloc_tos(), "\\", &fnum1, &tmp_path))) {
                printf("ctemp failed (%s)\n", cli_errstr(cli1));
                return False;
        }
@@ -4061,11 +4134,16 @@ static bool run_opentest(int dummy)
 static bool run_simple_posix_open_test(int dummy)
 {
        static struct cli_state *cli1;
-       const char *fname = "\\posix:file";
-       const char *dname = "\\posix:dir";
+       const char *fname = "posix:file";
+       const char *hname = "posix:hlink";
+       const char *sname = "posix:symlink";
+       const char *dname = "posix:dir";
+       char buf[10];
+       char namebuf[11];
        uint16 major, minor;
        uint32 caplow, caphigh;
-       int fnum1 = -1;
+       uint16_t fnum1 = (uint16_t)-1;
+       SMB_STRUCT_STAT sbuf;
        bool correct = false;
 
        printf("Starting simple POSIX open test\n");
@@ -4097,27 +4175,52 @@ static bool run_simple_posix_open_test(int dummy)
        cli_posix_unlink(cli1, fname);
        cli_setatr(cli1, dname, 0, 0);
        cli_posix_rmdir(cli1, dname);
+       cli_setatr(cli1, hname, 0, 0);
+       cli_posix_unlink(cli1, hname);
+       cli_setatr(cli1, sname, 0, 0);
+       cli_posix_unlink(cli1, sname);
 
        /* Create a directory. */
-       if (cli_posix_mkdir(cli1, dname, 0777) == -1) {
+       if (!NT_STATUS_IS_OK(cli_posix_mkdir(cli1, dname, 0777))) {
                printf("POSIX mkdir of %s failed (%s)\n", dname, cli_errstr(cli1));
                goto out;
        }
 
-       fnum1 = cli_posix_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, 0600);
-       if (fnum1 == -1) {
+       if (!NT_STATUS_IS_OK(cli_posix_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, 0600, &fnum1))) {
                printf("POSIX create of %s failed (%s)\n", fname, cli_errstr(cli1));
                goto out;
        }
 
+       /* Test ftruncate - set file size. */
+       if (!NT_STATUS_IS_OK(cli_ftruncate(cli1, fnum1, 1000))) {
+               printf("ftruncate failed (%s)\n", cli_errstr(cli1));
+               goto out;
+       }
+
+       /* Ensure st_size == 1000 */
+       if (!NT_STATUS_IS_OK(cli_posix_stat(cli1, fname, &sbuf))) {
+               printf("stat failed (%s)\n", cli_errstr(cli1));
+               goto out;
+       }
+
+       if (sbuf.st_ex_size != 1000) {
+               printf("ftruncate - stat size (%u) != 1000\n", (unsigned int)sbuf.st_ex_size);
+               goto out;
+       }
+
+       /* Test ftruncate - set file size back to zero. */
+       if (!NT_STATUS_IS_OK(cli_ftruncate(cli1, fnum1, 0))) {
+               printf("ftruncate failed (%s)\n", cli_errstr(cli1));
+               goto out;
+       }
+
        if (!NT_STATUS_IS_OK(cli_close(cli1, fnum1))) {
                printf("close failed (%s)\n", cli_errstr(cli1));
                goto out;
        }
 
        /* Now open the file again for read only. */
-       fnum1 = cli_posix_open(cli1, fname, O_RDONLY, 0);
-       if (fnum1 == -1) {
+       if (!NT_STATUS_IS_OK(cli_posix_open(cli1, fname, O_RDONLY, 0, &fnum1))) {
                printf("POSIX open of %s failed (%s)\n", fname, cli_errstr(cli1));
                goto out;
        }
@@ -4134,12 +4237,105 @@ static bool run_simple_posix_open_test(int dummy)
        }
 
        /* Ensure the file has gone. */
-       fnum1 = cli_posix_open(cli1, fname, O_RDONLY, 0);
-       if (fnum1 != -1) {
+       if (NT_STATUS_IS_OK(cli_posix_open(cli1, fname, O_RDONLY, 0, &fnum1))) {
                printf("POSIX open of %s succeeded, should have been deleted.\n", fname);
                goto out;
        }
 
+       /* What happens when we try and POSIX open a directory ? */
+       if (NT_STATUS_IS_OK(cli_posix_open(cli1, dname, O_RDONLY, 0, &fnum1))) {
+               printf("POSIX open of directory %s succeeded, should have failed.\n", fname);
+               goto out;
+       } else {
+               if (!check_error(__LINE__, cli1, ERRDOS, EISDIR,
+                               NT_STATUS_FILE_IS_A_DIRECTORY)) {
+                       goto out;
+               }
+       }
+
+       /* Create the file. */
+       if (!NT_STATUS_IS_OK(cli_posix_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL, 0600, &fnum1))) {
+               printf("POSIX create of %s failed (%s)\n", fname, cli_errstr(cli1));
+               goto out;
+       }
+
+       /* Write some data into it. */
+       if (cli_write(cli1, fnum1, 0, "TEST DATA\n", 0, 10) != 10) {
+               printf("cli_write failed: %s\n", cli_errstr(cli1));
+               goto out;
+       }
+
+       cli_close(cli1, fnum1);
+
+       /* Now create a hardlink. */
+       if (!NT_STATUS_IS_OK(cli_posix_hardlink(cli1, fname, hname))) {
+               printf("POSIX hardlink of %s failed (%s)\n", hname, cli_errstr(cli1));
+               goto out;
+       }
+
+       /* Now create a symlink. */
+       if (!NT_STATUS_IS_OK(cli_posix_symlink(cli1, fname, sname))) {
+               printf("POSIX symlink of %s failed (%s)\n", sname, cli_errstr(cli1));
+               goto out;
+       }
+
+       /* Open the hardlink for read. */
+       if (!NT_STATUS_IS_OK(cli_posix_open(cli1, hname, O_RDONLY, 0, &fnum1))) {
+               printf("POSIX open of %s failed (%s)\n", hname, cli_errstr(cli1));
+               goto out;
+       }
+
+       if (cli_read(cli1, fnum1, buf, 0, 10) != 10) {
+               printf("POSIX read of %s failed (%s)\n", hname, cli_errstr(cli1));
+               goto out;
+       }
+
+       if (memcmp(buf, "TEST DATA\n", 10)) {
+               printf("invalid data read from hardlink\n");
+               goto out;
+       }
+
+       /* Do a POSIX lock/unlock. */
+       if (!NT_STATUS_IS_OK(cli_posix_lock(cli1, fnum1, 0, 100, true, READ_LOCK))) {
+               printf("POSIX lock failed %s\n", cli_errstr(cli1));
+               goto out;
+       }
+
+       /* Punch a hole in the locked area. */
+       if (!NT_STATUS_IS_OK(cli_posix_unlock(cli1, fnum1, 10, 80))) {
+               printf("POSIX unlock failed %s\n", cli_errstr(cli1));
+               goto out;
+       }
+
+       cli_close(cli1, fnum1);
+
+       /* Open the symlink for read - this should fail. A POSIX
+          client should not be doing opens on a symlink. */
+       if (NT_STATUS_IS_OK(cli_posix_open(cli1, sname, O_RDONLY, 0, &fnum1))) {
+               printf("POSIX open of %s succeeded (should have failed)\n", sname);
+               goto out;
+       } else {
+               if (!check_error(__LINE__, cli1, ERRDOS, ERRbadpath,
+                               NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
+                       printf("POSIX open of %s should have failed "
+                               "with NT_STATUS_OBJECT_PATH_NOT_FOUND, "
+                               "failed with %s instead.\n",
+                               sname, cli_errstr(cli1));
+                       goto out;
+               }
+       }
+
+       if (!NT_STATUS_IS_OK(cli_posix_readlink(cli1, sname, namebuf, sizeof(namebuf)))) {
+               printf("POSIX readlink on %s failed (%s)\n", sname, cli_errstr(cli1));
+               goto out;
+       }
+
+       if (strcmp(namebuf, fname) != 0) {
+               printf("POSIX readlink on %s failed to match name %s (read %s)\n",
+                       sname, fname, namebuf);
+               goto out;
+       }
+
        if (!NT_STATUS_IS_OK(cli_posix_rmdir(cli1, dname))) {
                printf("POSIX rmdir failed (%s)\n", cli_errstr(cli1));
                goto out;
@@ -4150,11 +4346,15 @@ static bool run_simple_posix_open_test(int dummy)
 
   out:
 
-       if (fnum1 != -1) {
+       if (fnum1 != (uint16_t)-1) {
                cli_close(cli1, fnum1);
-               fnum1 = -1;
+               fnum1 = (uint16_t)-1;
        }
 
+       cli_setatr(cli1, sname, 0, 0);
+       cli_posix_unlink(cli1, sname);
+       cli_setatr(cli1, hname, 0, 0);
+       cli_posix_unlink(cli1, hname);
        cli_setatr(cli1, fname, 0, 0);
        cli_posix_unlink(cli1, fname);
        cli_setatr(cli1, dname, 0, 0);
@@ -4285,7 +4485,7 @@ static bool run_openattrtest(int dummy)
                                return False;
                        }
 
-                       if (!cli_getatr(cli1, fname, &attr, NULL, NULL)) {
+                       if (!NT_STATUS_IS_OK(cli_getatr(cli1, fname, &attr, NULL, NULL))) {
                                printf("getatr(2) failed (%s)\n", cli_errstr(cli1));
                                return False;
                        }
@@ -4959,6 +5159,7 @@ static bool run_chain1(int dummy)
        struct tevent_req *reqs[3], *smbreqs[3];
        bool done = false;
        const char *str = "foobar";
+       NTSTATUS status;
 
        printf("starting chain1 test\n");
        if (!torture_open_connection(&cli1, 0)) {
@@ -4983,7 +5184,64 @@ static bool run_chain1(int dummy)
        if (reqs[2] == NULL) return false;
        tevent_req_set_callback(reqs[2], chain1_close_completion, &done);
 
-       if (!cli_smb_chain_send(smbreqs, ARRAY_SIZE(smbreqs))) {
+       status = cli_smb_chain_send(smbreqs, ARRAY_SIZE(smbreqs));
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+
+       while (!done) {
+               event_loop_once(evt);
+       }
+
+       torture_close_connection(cli1);
+       return True;
+}
+
+static void chain2_sesssetup_completion(struct tevent_req *req)
+{
+       NTSTATUS status;
+       status = cli_session_setup_guest_recv(req);
+       d_printf("sesssetup returned %s\n", nt_errstr(status));
+}
+
+static void chain2_tcon_completion(struct tevent_req *req)
+{
+       bool *done = (bool *)tevent_req_callback_data_void(req);
+       NTSTATUS status;
+       status = cli_tcon_andx_recv(req);
+       d_printf("tcon_and_x returned %s\n", nt_errstr(status));
+       *done = true;
+}
+
+static bool run_chain2(int dummy)
+{
+       struct cli_state *cli1;
+       struct event_context *evt = event_context_init(NULL);
+       struct tevent_req *reqs[2], *smbreqs[2];
+       bool done = false;
+       NTSTATUS status;
+
+       printf("starting chain2 test\n");
+       status = cli_start_connection(&cli1, global_myname(), host, NULL,
+                                     port_to_use, Undefined, 0, NULL);
+       if (!NT_STATUS_IS_OK(status)) {
+               return False;
+       }
+
+       cli_sockopt(cli1, sockops);
+
+       reqs[0] = cli_session_setup_guest_create(talloc_tos(), evt, cli1,
+                                                &smbreqs[0]);
+       if (reqs[0] == NULL) return false;
+       tevent_req_set_callback(reqs[0], chain2_sesssetup_completion, NULL);
+
+       reqs[1] = cli_tcon_andx_create(talloc_tos(), evt, cli1, "IPC$",
+                                      "?????", NULL, 0, &smbreqs[1]);
+       if (reqs[1] == NULL) return false;
+       tevent_req_set_callback(reqs[1], chain2_tcon_completion, &done);
+
+       status = cli_smb_chain_send(smbreqs, ARRAY_SIZE(smbreqs));
+       if (!NT_STATUS_IS_OK(status)) {
                return false;
        }
 
@@ -5006,14 +5264,14 @@ static bool run_mangle1(int dummy)
        SMB_OFF_T size;
        uint16_t mode;
 
-       printf("starting chain1 test\n");
+       printf("starting mangle1 test\n");
        if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
        cli_sockopt(cli, sockops);
 
-       if (NT_STATUS_IS_OK(cli_ntcreate(
+       if (!NT_STATUS_IS_OK(cli_ntcreate(
                        cli, fname, 0, GENERIC_ALL_ACCESS|DELETE_ACCESS,
                        FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, 0, 0, &fnum))) {
                d_printf("open %s failed: %s\n", fname, cli_errstr(cli));
@@ -5209,6 +5467,281 @@ static bool run_uid_regression_test(int dummy)
        return correct;
 }
 
+
+static const char *illegal_chars = "*\\/?<>|\":";
+static char force_shortname_chars[] = " +,.[];=\177";
+
+static void shortname_del_fn(const char *mnt, file_info *finfo, const char *mask, void *state)
+{
+       struct cli_state *pcli = (struct cli_state *)state;
+       fstring fname;
+       slprintf(fname, sizeof(fname), "\\shortname\\%s", finfo->name);
+
+       if (strcmp(finfo->name, ".") == 0 || strcmp(finfo->name, "..") == 0)
+               return;
+
+       if (finfo->mode & aDIR) {
+               if (!NT_STATUS_IS_OK(cli_rmdir(pcli, fname)))
+                       printf("del_fn: failed to rmdir %s\n,", fname );
+       } else {
+               if (!NT_STATUS_IS_OK(cli_unlink(pcli, fname, aSYSTEM | aHIDDEN)))
+                       printf("del_fn: failed to unlink %s\n,", fname );
+       }
+}
+
+struct sn_state {
+       int i;
+       bool val;
+};
+
+static void shortname_list_fn(const char *mnt, file_info *finfo, const char *name, void *state)
+{
+       struct sn_state *s = (struct sn_state  *)state;
+       int i = s->i;
+
+#if 0
+       printf("shortname list: i = %d, name = |%s|, shortname = |%s|\n",
+               i, finfo->name, finfo->short_name);
+#endif
+
+       if (strchr(force_shortname_chars, i)) {
+               if (!finfo->short_name[0]) {
+                       /* Shortname not created when it should be. */
+                       d_printf("(%s) ERROR: Shortname was not created for file %s containing %d\n",
+                               __location__, finfo->name, i);
+                       s->val = true;
+               }
+       } else if (finfo->short_name[0]){
+               /* Shortname created when it should not be. */
+               d_printf("(%s) ERROR: Shortname %s was created for file %s\n",
+                       __location__, finfo->short_name, finfo->name);
+               s->val = true;
+       }
+}
+
+static bool run_shortname_test(int dummy)
+{
+       static struct cli_state *cli;
+       bool correct = True;
+       int i;
+       struct sn_state s;
+       char fname[20];
+
+       printf("starting shortname test\n");
+
+       if (!torture_open_connection(&cli, 0)) {
+               return False;
+       }
+
+       cli_sockopt(cli, sockops);
+
+       cli_list(cli, "\\shortname\\*", 0, shortname_del_fn, cli);
+       cli_list(cli, "\\shortname\\*", aDIR, shortname_del_fn, cli);
+       cli_rmdir(cli, "\\shortname");
+
+       if (!NT_STATUS_IS_OK(cli_mkdir(cli, "\\shortname"))) {
+               d_printf("(%s) cli_mkdir of \\shortname failed: %s\n",
+                       __location__, cli_errstr(cli));
+               correct = false;
+               goto out;
+       }
+
+       strlcpy(fname, "\\shortname\\", sizeof(fname));
+       strlcat(fname, "test .txt", sizeof(fname));
+
+       s.val = false;
+
+       for (i = 32; i < 128; i++) {
+               NTSTATUS status;
+               uint16_t fnum = (uint16_t)-1;
+
+               s.i = i;
+
+               if (strchr(illegal_chars, i)) {
+                       continue;
+               }
+               fname[15] = i;
+
+               status = cli_ntcreate(cli, fname, 0, GENERIC_ALL_ACCESS, FILE_ATTRIBUTE_NORMAL,
+                                   FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OVERWRITE_IF, 0, 0, &fnum);
+               if (!NT_STATUS_IS_OK(status)) {
+                       d_printf("(%s) cli_nt_create of %s failed: %s\n",
+                               __location__, fname, cli_errstr(cli));
+                       correct = false;
+                       goto out;
+               }
+               cli_close(cli, fnum);
+               if (cli_list(cli, "\\shortname\\test*.*", 0, shortname_list_fn, &s) != 1) {
+                       d_printf("(%s) failed to list %s: %s\n",
+                               __location__, fname, cli_errstr(cli));
+                       correct = false;
+                       goto out;
+               }
+               if (!NT_STATUS_IS_OK(cli_unlink(cli, fname, aSYSTEM | aHIDDEN))) {
+                       d_printf("(%s) failed to delete %s: %s\n",
+                               __location__, fname, cli_errstr(cli));
+                       correct = false;
+                       goto out;
+               }
+
+               if (s.val) {
+                       correct = false;
+                       goto out;
+               }
+       }
+
+  out:
+
+       cli_list(cli, "\\shortname\\*", 0, shortname_del_fn, cli);
+       cli_list(cli, "\\shortname\\*", aDIR, shortname_del_fn, cli);
+       cli_rmdir(cli, "\\shortname");
+       torture_close_connection(cli);
+       return correct;
+}
+
+static void pagedsearch_cb(struct tevent_req *req)
+{
+       int rc;
+       struct tldap_message *msg;
+       char *dn;
+
+       rc = tldap_search_paged_recv(req, talloc_tos(), &msg);
+       if (rc != TLDAP_SUCCESS) {
+               d_printf("tldap_search_paged_recv failed: %s\n",
+                        tldap_err2string(rc));
+               return;
+       }
+       if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
+               TALLOC_FREE(msg);
+               return;
+       }
+       if (!tldap_entry_dn(msg, &dn)) {
+               d_printf("tldap_entry_dn failed\n");
+               return;
+       }
+       d_printf("%s\n", dn);
+       TALLOC_FREE(msg);
+}
+
+static bool run_tldap(int dummy)
+{
+       struct tldap_context *ld;
+       int fd, rc;
+       NTSTATUS status;
+       struct sockaddr_storage addr;
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       char *basedn;
+
+       if (!resolve_name(host, &addr, 0, false)) {
+               d_printf("could not find host %s\n", host);
+               return false;
+       }
+       status = open_socket_out(&addr, 389, 9999, &fd);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("open_socket_out failed: %s\n", nt_errstr(status));
+               return false;
+       }
+
+       ld = tldap_context_create(talloc_tos(), fd);
+       if (ld == NULL) {
+               close(fd);
+               d_printf("tldap_context_create failed\n");
+               return false;
+       }
+
+       rc = tldap_fetch_rootdse(ld);
+       if (rc != TLDAP_SUCCESS) {
+               d_printf("tldap_fetch_rootdse failed: %s\n",
+                        tldap_errstr(talloc_tos(), ld, rc));
+               return false;
+       }
+
+       basedn = tldap_talloc_single_attribute(
+               tldap_rootdse(ld), "defaultNamingContext", talloc_tos());
+       if (basedn == NULL) {
+               d_printf("no defaultNamingContext\n");
+               return false;
+       }
+       d_printf("defaultNamingContext: %s\n", basedn);
+
+       ev = tevent_context_init(talloc_tos());
+       if (ev == NULL) {
+               d_printf("tevent_context_init failed\n");
+               return false;
+       }
+
+       req = tldap_search_paged_send(talloc_tos(), ev, ld, basedn,
+                                     TLDAP_SCOPE_SUB, "(objectclass=*)",
+                                     NULL, 0, 0,
+                                     NULL, 0, NULL, 0, 0, 0, 0, 5);
+       if (req == NULL) {
+               d_printf("tldap_search_paged_send failed\n");
+               return false;
+       }
+       tevent_req_set_callback(req, pagedsearch_cb, NULL);
+
+       tevent_req_poll(req, ev);
+
+       TALLOC_FREE(req);
+
+       TALLOC_FREE(ld);
+       return true;
+}
+
+static bool run_streamerror(int dummy)
+{
+       struct cli_state *cli;
+       const char *dname = "\\testdir";
+       const char *streamname =
+               "testdir:{4c8cc155-6c1e-11d1-8e41-00c04fb9386d}:$DATA";
+       NTSTATUS status;
+       time_t change_time, access_time, write_time;
+       SMB_OFF_T size;
+       uint16_t mode, fnum;
+       bool ret = true;
+
+       if (!torture_open_connection(&cli, 0)) {
+               return false;
+       }
+
+       cli_rmdir(cli, dname);
+
+       status = cli_mkdir(cli, dname);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("mkdir failed: %s\n", nt_errstr(status));
+               return false;
+       }
+
+       cli_qpathinfo(cli, streamname, &change_time, &access_time, &write_time,
+                     &size, &mode);
+       status = cli_nt_error(cli);
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               printf("pathinfo returned %s, expected "
+                      "NT_STATUS_OBJECT_NAME_NOT_FOUND\n",
+                      nt_errstr(status));
+               ret = false;
+       }
+
+       status = cli_ntcreate(cli, streamname, 0x16,
+                             FILE_READ_DATA|FILE_READ_EA|
+                             FILE_READ_ATTRIBUTES|READ_CONTROL_ACCESS,
+                             FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
+                             FILE_OPEN, 0, 0, &fnum);
+
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               printf("ntcreate returned %s, expected "
+                      "NT_STATUS_OBJECT_NAME_NOT_FOUND\n",
+                      nt_errstr(status));
+               ret = false;
+       }
+
+
+       cli_rmdir(cli, dname);
+       return ret;
+}
+
 static bool run_local_substitute(int dummy)
 {
        bool ok = true;
@@ -5230,17 +5763,45 @@ static bool run_local_substitute(int dummy)
        return ok;
 }
 
+static bool run_local_base64(int dummy)
+{
+       int i;
+       bool ret = true;
+
+       for (i=1; i<2000; i++) {
+               DATA_BLOB blob1, blob2;
+               char *b64;
+
+               blob1.data = talloc_array(talloc_tos(), uint8_t, i);
+               blob1.length = i;
+               generate_random_buffer(blob1.data, blob1.length);
+
+               b64 = base64_encode_data_blob(talloc_tos(), blob1);
+               if (b64 == NULL) {
+                       d_fprintf(stderr, "base64_encode_data_blob failed "
+                                 "for %d bytes\n", i);
+                       ret = false;
+               }
+               blob2 = base64_decode_data_blob(b64);
+               TALLOC_FREE(b64);
+
+               if (data_blob_cmp(&blob1, &blob2)) {
+                       d_fprintf(stderr, "data_blob_cmp failed for %d "
+                                 "bytes\n", i);
+                       ret = false;
+               }
+               TALLOC_FREE(blob1.data);
+               data_blob_free(&blob2);
+       }
+       return ret;
+}
+
 static bool run_local_gencache(int dummy)
 {
        char *val;
        time_t tm;
        DATA_BLOB blob;
 
-       if (!gencache_init()) {
-               d_printf("%s: gencache_init() failed\n", __location__);
-               return False;
-       }
-
        if (!gencache_set("foo", "bar", time(NULL) + 1000)) {
                d_printf("%s: gencache_set() failed\n", __location__);
                return False;
@@ -5277,15 +5838,13 @@ static bool run_local_gencache(int dummy)
        }
 
        blob = data_blob_string_const_null("bar");
-       tm = time(NULL);
+       tm = time(NULL) + 60;
 
        if (!gencache_set_data_blob("foo", &blob, tm)) {
                d_printf("%s: gencache_set_data_blob() failed\n", __location__);
                return False;
        }
 
-       data_blob_free(&blob);
-
        if (!gencache_get_data_blob("foo", &blob, NULL)) {
                d_printf("%s: gencache_get_data_blob() failed\n", __location__);
                return False;
@@ -5316,17 +5875,6 @@ static bool run_local_gencache(int dummy)
                return False;
        }
 
-       if (!gencache_shutdown()) {
-               d_printf("%s: gencache_shutdown() failed\n", __location__);
-               return False;
-       }
-
-       if (gencache_shutdown()) {
-               d_printf("%s: second gencache_shutdown() succeeded\n",
-                        __location__);
-               return False;
-       }
-
        return True;
 }
 
@@ -5420,6 +5968,96 @@ static bool run_local_rbtree(int dummy)
        return ret;
 }
 
+/* Split a path name into filename and stream name components. Canonicalise
+ * such that an implicit $DATA token is always explicit.
+ *
+ * The "specification" of this function can be found in the
+ * run_local_stream_name() function in torture.c, I've tried those
+ * combinations against a W2k3 server.
+ */
+
+static NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+                                      char **pbase, char **pstream)
+{
+       char *base = NULL;
+       char *stream = NULL;
+       char *sname; /* stream name */
+       const char *stype; /* stream type */
+
+       DEBUG(10, ("split_ntfs_stream_name called for [%s]\n", fname));
+
+       sname = strchr_m(fname, ':');
+
+       if (lp_posix_pathnames() || (sname == NULL)) {
+               if (pbase != NULL) {
+                       base = talloc_strdup(mem_ctx, fname);
+                       NT_STATUS_HAVE_NO_MEMORY(base);
+               }
+               goto done;
+       }
+
+       if (pbase != NULL) {
+               base = talloc_strndup(mem_ctx, fname, PTR_DIFF(sname, fname));
+               NT_STATUS_HAVE_NO_MEMORY(base);
+       }
+
+       sname += 1;
+
+       stype = strchr_m(sname, ':');
+
+       if (stype == NULL) {
+               sname = talloc_strdup(mem_ctx, sname);
+               stype = "$DATA";
+       }
+       else {
+               if (StrCaseCmp(stype, ":$DATA") != 0) {
+                       /*
+                        * If there is an explicit stream type, so far we only
+                        * allow $DATA. Is there anything else allowed? -- vl
+                        */
+                       DEBUG(10, ("[%s] is an invalid stream type\n", stype));
+                       TALLOC_FREE(base);
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+               sname = talloc_strndup(mem_ctx, sname, PTR_DIFF(stype, sname));
+               stype += 1;
+       }
+
+       if (sname == NULL) {
+               TALLOC_FREE(base);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (sname[0] == '\0') {
+               /*
+                * no stream name, so no stream
+                */
+               goto done;
+       }
+
+       if (pstream != NULL) {
+               stream = talloc_asprintf(mem_ctx, "%s:%s", sname, stype);
+               if (stream == NULL) {
+                       TALLOC_FREE(sname);
+                       TALLOC_FREE(base);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               /*
+                * upper-case the type field
+                */
+               strupper_m(strchr_m(stream, ':')+1);
+       }
+
+ done:
+       if (pbase != NULL) {
+               *pbase = base;
+       }
+       if (pstream != NULL) {
+               *pstream = stream;
+       }
+       return NT_STATUS_OK;
+}
+
 static bool test_stream_name(const char *fname, const char *expected_base,
                             const char *expected_stream,
                             NTSTATUS expected_status)
@@ -5616,12 +6254,12 @@ static bool run_local_wbclient(int dummy)
 
        BlockSignals(True, SIGPIPE);
 
-       ev = event_context_init(talloc_tos());
+       ev = tevent_context_init_byname(talloc_tos(), "epoll");
        if (ev == NULL) {
                goto fail;
        }
 
-       wb_ctx = TALLOC_ARRAY(ev, struct wb_context *, torture_numops);
+       wb_ctx = TALLOC_ARRAY(ev, struct wb_context *, nprocs);
        if (wb_ctx == NULL) {
                goto fail;
        }
@@ -5629,12 +6267,14 @@ static bool run_local_wbclient(int dummy)
        ZERO_STRUCT(wb_req);
        wb_req.cmd = WINBINDD_PING;
 
-       for (i=0; i<torture_numops; i++) {
-               wb_ctx[i] = wb_context_init(ev);
+       d_printf("nprocs=%d, numops=%d\n", (int)nprocs, (int)torture_numops);
+
+       for (i=0; i<nprocs; i++) {
+               wb_ctx[i] = wb_context_init(ev, NULL);
                if (wb_ctx[i] == NULL) {
                        goto fail;
                }
-               for (j=0; j<5; j++) {
+               for (j=0; j<torture_numops; j++) {
                        struct tevent_req *req;
                        req = wb_trans_send(ev, ev, wb_ctx[i],
                                            (j % 2) == 0, &wb_req);
@@ -5647,7 +6287,7 @@ static bool run_local_wbclient(int dummy)
 
        i = 0;
 
-       while (i < 5 * torture_numops) {
+       while (i < nprocs * torture_numops) {
                event_loop_once(ev);
        }
 
@@ -5819,6 +6459,7 @@ static struct {
        {"LOCK5",  run_locktest5,  0},
        {"LOCK6",  run_locktest6,  0},
        {"LOCK7",  run_locktest7,  0},
+       {"LOCK8",  run_locktest8,  0},
        {"UNLINK", run_unlinktest, 0},
        {"BROWSE", run_browsetest, 0},
        {"ATTR",   run_attrtest,   0},
@@ -5843,6 +6484,7 @@ static struct {
        {"OPEN", run_opentest, 0},
        {"POSIX", run_simple_posix_open_test, 0},
        { "UID-REGRESSION-TEST", run_uid_regression_test, 0},
+       { "SHORTNAME-TEST", run_shortname_test, 0},
 #if 1
        {"OPENATTR", run_openattrtest, 0},
 #endif
@@ -5866,11 +6508,15 @@ static struct {
        { "EATEST", run_eatest, 0},
        { "SESSSETUP_BENCH", run_sesssetup_bench, 0},
        { "CHAIN1", run_chain1, 0},
+       { "CHAIN2", run_chain2, 0},
        { "WINDOWS-WRITE", run_windows_write, 0},
        { "CLI_ECHO", run_cli_echo, 0},
        { "GETADDRINFO", run_getaddrinfo_send, 0},
+       { "TLDAP", run_tldap },
+       { "STREAMERROR", run_streamerror },
        { "LOCAL-SUBSTITUTE", run_local_substitute, 0},
        { "LOCAL-GENCACHE", run_local_gencache, 0},
+       { "LOCAL-BASE64", run_local_base64, 0},
        { "LOCAL-RBTREE", run_local_rbtree, 0},
        { "LOCAL-MEMCACHE", run_local_memcache, 0},
        { "LOCAL-STREAM-NAME", run_local_stream_name, 0},