r23779: Change from v2 or later to v3 or later.
[bbaumbach/samba-autobuild/.git] / source3 / torture / torture.c
index ef9497d9ad9e16cccee7091f8d60509a17053761..b5c454a3a116707a45b5a482db37606d3a14ce46 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -18,8 +18,6 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#define NO_SYSLOG
-
 #include "includes.h"
 
 extern char *optarg;
@@ -38,6 +36,8 @@ static BOOL use_oplocks;
 static BOOL use_level_II_oplocks;
 static const char *client_txt = "client_oplocks.txt";
 static BOOL use_kerberos;
+static fstring multishare_conn_fname;
+static BOOL use_multishare_conn = False;
 
 BOOL torture_showall = False;
 
@@ -46,6 +46,7 @@ static double create_procs(BOOL (*fn)(int), BOOL *result);
 
 static struct timeval tp1,tp2;
 
+
 void start_timer(void)
 {
        GetTimeOfDay(&tp1);
@@ -96,28 +97,29 @@ void *shm_setup(int size)
 }
 
 
-static BOOL open_nbt_connection(struct cli_state *c)
+static struct cli_state *open_nbt_connection(void)
 {
        struct nmb_name called, calling;
        struct in_addr ip;
-
-       ZERO_STRUCTP(c);
+       struct cli_state *c;
+       NTSTATUS status;
 
        make_nmb_name(&calling, myname, 0x0);
        make_nmb_name(&called , host, 0x20);
 
         zero_ip(&ip);
 
-       if (!cli_initialise(c)) {
+       if (!(c = cli_initialise())) {
                printf("Failed initialize cli_struct to connect with %s\n", host);
-               return False;
+               return NULL;
        }
 
        c->port = port_to_use;
 
-       if (!cli_connect(c, host, &ip)) {
-               printf("Failed to connect with %s\n", host);
-               return False;
+       status = cli_connect(c, host, &ip);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) );
+               return NULL;
        }
 
        c->use_kerberos = use_kerberos;
@@ -131,9 +133,10 @@ static BOOL open_nbt_connection(struct cli_state *c)
                 * Well, that failed, try *SMBSERVER ... 
                 * However, we must reconnect as well ...
                 */
-               if (!cli_connect(c, host, &ip)) {
-                       printf("Failed to connect with %s\n", host);
-                       return False;
+               status = cli_connect(c, host, &ip);
+               if (!NT_STATUS_IS_OK(status)) {
+                       printf("Failed to connect with %s. Error %s\n", host, nt_errstr(status) );
+                       return NULL;
                }
 
                make_nmb_name(&called, "*SMBSERVER", 0x20);
@@ -142,14 +145,74 @@ static BOOL open_nbt_connection(struct cli_state *c)
                        printf("We tried with a called name of %s & %s\n",
                                host, "*SMBSERVER");
                        cli_shutdown(c);
-                       return False;
+                       return NULL;
                }
        }
 
-       return True;
+       return c;
+}
+
+/* Insert a NULL at the first separator of the given path and return a pointer
+ * to the remainder of the string.
+ */
+static char *
+terminate_path_at_separator(char * path)
+{
+       char * p;
+
+       if (!path) {
+               return NULL;
+       }
+
+       if ((p = strchr_m(path, '/'))) {
+               *p = '\0';
+               return p + 1;
+       }
+
+       if ((p = strchr_m(path, '\\'))) {
+               *p = '\0';
+               return p + 1;
+       }
+       
+       /* No separator. */
+       return NULL;
+}
+
+/*
+  parse a //server/share type UNC name
+*/
+BOOL smbcli_parse_unc(const char *unc_name, TALLOC_CTX *mem_ctx,
+                     char **hostname, char **sharename)
+{
+       char *p;
+
+       *hostname = *sharename = NULL;
+
+       if (strncmp(unc_name, "\\\\", 2) &&
+           strncmp(unc_name, "//", 2)) {
+               return False;
+       }
+
+       *hostname = talloc_strdup(mem_ctx, &unc_name[2]);
+       p = terminate_path_at_separator(*hostname);
+
+       if (p && *p) {
+               *sharename = talloc_strdup(mem_ctx, p);
+               terminate_path_at_separator(*sharename);
+       }
+
+       if (*hostname && *sharename) {
+               return True;
+       }
+
+       TALLOC_FREE(*hostname);
+       TALLOC_FREE(*sharename);
+       return False;
 }
 
-BOOL torture_open_connection(struct cli_state **c)
+static BOOL torture_open_connection_share(struct cli_state **c,
+                                  const char *hostname, 
+                                  const char *sharename)
 {
        BOOL retry;
        int flags = 0;
@@ -157,13 +220,15 @@ BOOL torture_open_connection(struct cli_state **c)
 
        if (use_kerberos)
                flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
-       
+
        status = cli_full_connection(c, myname,
-                                    host, NULL, port_to_use, 
-                                    share, "?????", 
+                                    hostname, NULL, port_to_use, 
+                                    sharename, "?????", 
                                     username, workgroup, 
                                     password, flags, Undefined, &retry);
        if (!NT_STATUS_IS_OK(status)) {
+               printf("failed to open share connection: //%s/%s port:%d - %s\n",
+                       hostname, sharename, port_to_use, nt_errstr(status));
                return False;
        }
 
@@ -174,6 +239,47 @@ BOOL torture_open_connection(struct cli_state **c)
        return True;
 }
 
+void torture_open_connection_free_unclist(char **unc_list)
+{
+       if (unc_list!=NULL)
+       {
+               SAFE_FREE(unc_list[0]);
+               SAFE_FREE(unc_list);
+       }
+}
+
+BOOL torture_open_connection(struct cli_state **c, int conn_index)
+{
+       char **unc_list = NULL;
+       int num_unc_names = 0;
+       BOOL result;
+
+       if (use_multishare_conn==True) {
+               char *h, *s;
+               unc_list = file_lines_load(multishare_conn_fname, &num_unc_names, 0);
+               if (!unc_list || num_unc_names <= 0) {
+                       printf("Failed to load unc names list from '%s'\n", multishare_conn_fname);
+                       exit(1);
+               }
+
+               if (!smbcli_parse_unc(unc_list[conn_index % num_unc_names],
+                                     NULL, &h, &s)) {
+                       printf("Failed to parse UNC name %s\n",
+                              unc_list[conn_index % num_unc_names]);
+                       torture_open_connection_free_unclist(unc_list);
+                       exit(1);
+               }
+
+               result = torture_open_connection_share(c, h, s);
+
+               /* h, s were copied earlier */
+               torture_open_connection_free_unclist(unc_list);
+               return result;
+       }
+
+       return torture_open_connection_share(c, host, share);
+}
+
 BOOL torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid)
 {
        uint16 old_vuid = cli->vuid;
@@ -183,7 +289,10 @@ BOOL torture_cli_session_setup2(struct cli_state *cli, uint16 *new_vuid)
 
        fstrcpy(old_user_name, cli->user_name);
        cli->vuid = 0;
-       ret = cli_session_setup(cli, username, password, passlen, password, passlen, workgroup);
+       ret = NT_STATUS_IS_OK(cli_session_setup(cli, username,
+                                               password, passlen,
+                                               password, passlen,
+                                               workgroup));
        *new_vuid = cli->vuid;
        cli->vuid = old_vuid;
        fstrcpy(cli->user_name, old_user_name);
@@ -210,16 +319,16 @@ static BOOL check_error(int line, struct cli_state *c,
                        uint8 eclass, uint32 ecode, NTSTATUS nterr)
 {
         if (cli_is_dos_error(c)) {
-                uint8 class;
+                uint8 cclass;
                 uint32 num;
 
                 /* Check DOS error */
 
-                cli_dos_error(c, &class, &num);
+                cli_dos_error(c, &cclass, &num);
 
-                if (eclass != class || ecode != num) {
+                if (eclass != cclass || ecode != num) {
                         printf("unexpected error code class=%d code=%d\n", 
-                               (int)class, (int)num);
+                               (int)cclass, (int)num);
                         printf(" expected %d/%d %s (line=%d)\n", 
                                (int)eclass, (int)ecode, nt_errstr(nterr), line);
                         return False;
@@ -263,6 +372,8 @@ static BOOL rw_torture(struct cli_state *c)
        char buf[1024];
        BOOL correct = True;
 
+       memset(buf, '\0', sizeof(buf));
+
        fnum2 = cli_open(c, lockfname, O_RDWR | O_CREAT | O_EXCL, 
                         DENY_NONE);
        if (fnum2 == -1)
@@ -464,8 +575,8 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
        int fnum1;
        int fnum2;
        int i;
-       uchar buf[131072];
-       uchar buf_rd[131072];
+       char buf[131072];
+       char buf_rd[131072];
        BOOL correct = True;
        ssize_t bytes_read;
 
@@ -496,7 +607,7 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
                        printf("%d\r", i); fflush(stdout);
                }
 
-               generate_random_buffer(buf, buf_size);
+               generate_random_buffer((unsigned char *)buf, buf_size);
 
                if (cli_write(c1, fnum1, 0, buf, 0, buf_size) != buf_size) {
                        printf("write failed (%s)\n", cli_errstr(c1));
@@ -506,7 +617,7 @@ static BOOL rw_torture2(struct cli_state *c1, struct cli_state *c2)
 
                if ((bytes_read = cli_read(c2, fnum2, buf_rd, 0, buf_size)) != buf_size) {
                        printf("read failed (%s)\n", cli_errstr(c2));
-                       printf("read %d, expected %ld\n", bytes_read, 
+                       printf("read %d, expected %ld\n", (int)bytes_read, 
                               (unsigned long)buf_size); 
                        correct = False;
                        break;
@@ -542,7 +653,7 @@ static BOOL run_readwritetest(int dummy)
        static struct cli_state *cli1, *cli2;
        BOOL test1, test2 = False;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -597,7 +708,7 @@ static BOOL run_readwritelarge(int dummy)
        char buf[126*1024];
        BOOL correct = True;
  
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -700,7 +811,6 @@ static BOOL run_netbench(int client)
 {
        struct cli_state *cli;
        int i;
-       fstring fname;
        pstring line;
        char cname[20];
        FILE *f;
@@ -715,7 +825,7 @@ static BOOL run_netbench(int client)
 
        nb_setup(cli);
 
-       slprintf(cname,sizeof(fname), "client%d", client);
+       slprintf(cname,sizeof(cname)-1, "client%d", client);
 
        f = fopen(client_txt, "r");
 
@@ -829,7 +939,7 @@ static BOOL run_locktest1(int dummy)
        time_t t1, t2;
        unsigned lock_timeout;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -944,7 +1054,9 @@ static BOOL run_tcon_test(int dummy)
        char buf[4];
        BOOL ret = True;
 
-       if (!torture_open_connection(&cli)) {
+       memset(buf, '\0', sizeof(buf));
+
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
        cli_sockopt(cli, sockops);
@@ -1046,7 +1158,7 @@ static BOOL run_tcon2_test(int dummy)
        char *service;
        NTSTATUS status;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
        cli_sockopt(cli, sockops);
@@ -1199,7 +1311,7 @@ static BOOL run_locktest2(int dummy)
        int fnum1, fnum2, fnum3;
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -1338,7 +1450,7 @@ static BOOL run_locktest3(int dummy)
 
 #define NEXT_OFFSET offset += (~(uint32)0) / torture_numops
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -1462,7 +1574,7 @@ static BOOL run_locktest4(int dummy)
        char buf[1000];
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
 
@@ -1633,7 +1745,7 @@ static BOOL run_locktest5(int dummy)
        char buf[1000];
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
 
@@ -1756,7 +1868,7 @@ static BOOL run_locktest6(int dummy)
        int fnum;
        NTSTATUS status;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -1796,7 +1908,7 @@ static BOOL run_locktest7(int dummy)
        char buf[200];
        BOOL correct = False;
 
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
 
@@ -1932,7 +2044,7 @@ static BOOL run_fdpasstest(int dummy)
        int fnum1;
        pstring buf;
 
-       if (!torture_open_connection(&cli1) || !torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli1, 0) || !torture_open_connection(&cli2, 1)) {
                return False;
        }
        cli_sockopt(cli1, sockops);
@@ -1987,7 +2099,7 @@ static BOOL run_fdsesstest(int dummy)
        pstring buf;
        BOOL ret = True;
 
-       if (!torture_open_connection(&cli))
+       if (!torture_open_connection(&cli, 0))
                return False;
        cli_sockopt(cli, sockops);
 
@@ -2069,7 +2181,7 @@ static BOOL run_unlinktest(int dummy)
        int fnum;
        BOOL correct = True;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2114,7 +2226,7 @@ test how many open files this server supports on the one socket
 static BOOL run_maxfidtest(int dummy)
 {
        struct cli_state *cli;
-       const char *template = "\\maxfid.%d.%d";
+       const char *ftemplate = "\\maxfid.%d.%d";
        fstring fname;
        int fnums[0x11000], i;
        int retries=4;
@@ -2130,7 +2242,7 @@ static BOOL run_maxfidtest(int dummy)
        cli_sockopt(cli, sockops);
 
        for (i=0; i<0x11000; i++) {
-               slprintf(fname,sizeof(fname)-1,template, i,(int)getpid());
+               slprintf(fname,sizeof(fname)-1,ftemplate, i,(int)getpid());
                if ((fnums[i] = cli_open(cli, fname, 
                                        O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
                    -1) {
@@ -2146,7 +2258,7 @@ static BOOL run_maxfidtest(int dummy)
 
        printf("cleaning up\n");
        for (;i>=0;i--) {
-               slprintf(fname,sizeof(fname)-1,template, i,(int)getpid());
+               slprintf(fname,sizeof(fname)-1,ftemplate, i,(int)getpid());
                cli_close(cli, fnums[i]);
                if (!cli_unlink(cli, fname)) {
                        printf("unlink of %s failed (%s)\n", 
@@ -2177,20 +2289,20 @@ static void rand_buf(char *buf, int len)
 static BOOL run_negprot_nowait(int dummy)
 {
        int i;
-       static struct cli_state cli;
+       static struct cli_state *cli;
        BOOL correct = True;
 
        printf("starting negprot nowait test\n");
 
-       if (!open_nbt_connection(&cli)) {
+       if (!(cli = open_nbt_connection())) {
                return False;
        }
 
        for (i=0;i<50000;i++) {
-               cli_negprot_send(&cli);
+               cli_negprot_send(cli);
        }
 
-       if (!torture_close_connection(&cli)) {
+       if (!torture_close_connection(cli)) {
                correct = False;
        }
 
@@ -2205,7 +2317,7 @@ static BOOL run_randomipc(int dummy)
 {
        char *rparam = NULL;
        char *rdata = NULL;
-       int rdrcnt,rprcnt;
+       unsigned int rdrcnt,rprcnt;
        pstring param;
        int api, param_len, i;
        struct cli_state *cli;
@@ -2214,7 +2326,7 @@ static BOOL run_randomipc(int dummy)
 
        printf("starting random ipc test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2267,7 +2379,7 @@ static BOOL run_browsetest(int dummy)
 
        printf("starting browse test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2305,7 +2417,7 @@ static BOOL run_attrtest(int dummy)
 
        printf("starting attrib test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2364,7 +2476,8 @@ static BOOL run_trans2test(int dummy)
        struct cli_state *cli;
        int fnum;
        SMB_OFF_T size;
-       time_t c_time, a_time, m_time, w_time, m_time2;
+       time_t c_time, a_time, m_time;
+       struct timespec c_time_ts, a_time_ts, m_time_ts, w_time_ts, m_time2_ts;
        const char *fname = "\\trans2.tst";
        const char *dname = "\\trans2";
        const char *fname2 = "\\trans2\\trans2.tst";
@@ -2373,15 +2486,15 @@ static BOOL run_trans2test(int dummy)
 
        printf("starting trans2 test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
        cli_unlink(cli, fname);
        fnum = cli_open(cli, fname, 
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
-       if (!cli_qfileinfo(cli, fnum, NULL, &size, &c_time, &a_time, &m_time,
-                          NULL, NULL)) {
+       if (!cli_qfileinfo(cli, fnum, NULL, &size, &c_time_ts, &a_time_ts, &w_time_ts,
+                          &m_time_ts, NULL)) {
                printf("ERROR: qfileinfo failed (%s)\n", cli_errstr(cli));
                correct = False;
        }
@@ -2436,13 +2549,13 @@ static BOOL run_trans2test(int dummy)
        fnum = cli_open(cli, fname, 
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
        cli_close(cli, fnum);
-       if (!cli_qpathinfo2(cli, fname, &c_time, &a_time, &m_time
-                           &w_time, &size, NULL, NULL)) {
+       if (!cli_qpathinfo2(cli, fname, &c_time_ts, &a_time_ts, &w_time_ts
+                           &m_time_ts, &size, NULL, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
                correct = False;
        } else {
-               if (w_time < 60*60*24*2) {
-                       printf("write time=%s", ctime(&w_time));
+               if (w_time_ts.tv_sec < 60*60*24*2) {
+                       printf("write time=%s", ctime(&w_time_ts.tv_sec));
                        printf("This system appears to set a initial 0 write time\n");
                        correct = False;
                }
@@ -2458,8 +2571,8 @@ static BOOL run_trans2test(int dummy)
                correct = False;
        }
        sleep(3);
-       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time, &a_time, &m_time
-                           &w_time, &size, NULL, NULL)) {
+       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time_ts, &a_time_ts, &w_time_ts
+                           &m_time_ts, &size, NULL, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
                correct = False;
        }
@@ -2468,12 +2581,13 @@ static BOOL run_trans2test(int dummy)
                        O_RDWR | O_CREAT | O_TRUNC, DENY_NONE);
        cli_write(cli, fnum,  0, (char *)&fnum, 0, sizeof(fnum));
        cli_close(cli, fnum);
-       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time, &a_time, &m_time2
-                           &w_time, &size, NULL, NULL)) {
+       if (!cli_qpathinfo2(cli, "\\trans2\\", &c_time_ts, &a_time_ts, &w_time_ts
+                           &m_time2_ts, &size, NULL, NULL)) {
                printf("ERROR: qpathinfo2 failed (%s)\n", cli_errstr(cli));
                correct = False;
        } else {
-               if (m_time2 == m_time) {
+               if (memcmp(&m_time_ts, &m_time2_ts, sizeof(struct timespec))
+                   == 0) {
                        printf("This system does not update directory modification times\n");
                        correct = False;
                }
@@ -2505,7 +2619,7 @@ static BOOL new_trans(struct cli_state *pcli, int fnum, int level)
                correct = False;
        } else {
                printf("qfileinfo: level %d, len = %u\n", level, len);
-               dump_data(0, buf, len);
+               dump_data(0, (uint8 *)buf, len);
                printf("\n");
        }
        SAFE_FREE(buf);
@@ -2522,7 +2636,7 @@ static BOOL run_w2ktest(int dummy)
 
        printf("starting w2k test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -2557,7 +2671,7 @@ static BOOL run_oplock1(int dummy)
 
        printf("starting oplock test 1\n");
 
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
 
@@ -2615,7 +2729,7 @@ static BOOL run_oplock2(int dummy)
 
        printf("starting oplock test 2\n");
 
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                use_level_II_oplocks = False;
                use_oplocks = saved_use_oplocks;
                return False;
@@ -2624,7 +2738,7 @@ static BOOL run_oplock2(int dummy)
        cli1->use_oplocks = True;
        cli1->use_level_II_oplocks = True;
 
-       if (!torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli2, 1)) {
                use_level_II_oplocks = False;
                use_oplocks = saved_use_oplocks;
                return False;
@@ -2758,7 +2872,7 @@ static BOOL run_oplock3(int dummy)
                /* Child code */
                use_oplocks = True;
                use_level_II_oplocks = True;
-               if (!torture_open_connection(&cli)) {
+               if (!torture_open_connection(&cli, 0)) {
                        *shared_correct = False;
                        exit(0);
                } 
@@ -2772,7 +2886,7 @@ static BOOL run_oplock3(int dummy)
        /* parent code */
        use_oplocks = True;
        use_level_II_oplocks = True;
-       if (!torture_open_connection(&cli)) { 
+       if (!torture_open_connection(&cli, 1)) { /* other is forked */
                return False;
        }
        cli_oplock_handler(cli, oplock3_handler);
@@ -2805,7 +2919,7 @@ static BOOL run_deletetest(int dummy)
        
        printf("starting delete test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3119,7 +3233,7 @@ static BOOL run_deletetest(int dummy)
        cli_setatr(cli1, fname, 0, 0);
        cli_unlink(cli1, fname);
        
-       if (!torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli2, 1)) {
                printf("[8] failed to open second connection.\n");
                correct = False;
                goto fail;
@@ -3286,7 +3400,7 @@ static BOOL run_properties(int dummy)
        
        ZERO_STRUCT(cli);
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
        
@@ -3334,7 +3448,7 @@ static BOOL run_xcopy(int dummy)
 
        printf("starting xcopy test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3377,7 +3491,7 @@ static BOOL run_rename(int dummy)
 
        printf("starting rename test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3563,7 +3677,7 @@ static BOOL run_pipe_number(int dummy)
        int num_pipes = 0;
 
        printf("starting pipenumber test\n");
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
 
@@ -3577,6 +3691,7 @@ static BOOL run_pipe_number(int dummy)
                        break;
                }
                num_pipes++;
+               printf("\r%6d", num_pipes);
        }
 
        printf("pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
@@ -3600,7 +3715,7 @@ static BOOL run_opentest(int dummy)
 
        printf("starting open test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -3747,7 +3862,7 @@ static BOOL run_opentest(int dummy)
        
        /* Test the non-io opens... */
 
-       if (!torture_open_connection(&cli2)) {
+       if (!torture_open_connection(&cli2, 1)) {
                return False;
        }
        
@@ -4048,7 +4163,7 @@ static BOOL run_openattrtest(int dummy)
 
        printf("starting open attr test\n");
        
-       if (!torture_open_connection(&cli1)) {
+       if (!torture_open_connection(&cli1, 0)) {
                return False;
        }
        
@@ -4160,7 +4275,7 @@ static BOOL run_dirtest(int dummy)
 
        printf("starting directory test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4233,7 +4348,7 @@ BOOL torture_ioctl_test(int dummy)
        DATA_BLOB blob;
        NTSTATUS status;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4261,7 +4376,8 @@ BOOL torture_ioctl_test(int dummy)
                        status = cli_raw_ioctl(cli, fnum, code, &blob);
 
                        if (NT_STATUS_IS_OK(status)) {
-                               printf("ioctl 0x%x OK : %d bytes\n", code, blob.length);
+                               printf("ioctl 0x%x OK : %d bytes\n", (int)code,
+                                      (int)blob.length);
                                data_blob_free(&blob);
                        }
                }
@@ -4284,7 +4400,7 @@ BOOL torture_chkpath_test(int dummy)
        int fnum;
        BOOL ret;
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4369,7 +4485,8 @@ static BOOL run_eatest(int dummy)
 
        printf("starting eatest\n");
        
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
+               talloc_destroy(mem_ctx);
                return False;
        }
        
@@ -4381,6 +4498,7 @@ static BOOL run_eatest(int dummy)
 
        if (fnum == -1) {
                printf("open failed - %s\n", cli_errstr(cli));
+               talloc_destroy(mem_ctx);
                return False;
        }
 
@@ -4391,6 +4509,7 @@ static BOOL run_eatest(int dummy)
                memset(ea_val, (char)i+1, i+1);
                if (!cli_set_ea_fnum(cli, fnum, ea_name, ea_val, i+1)) {
                        printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+                       talloc_destroy(mem_ctx);
                        return False;
                }
        }
@@ -4403,6 +4522,7 @@ static BOOL run_eatest(int dummy)
                memset(ea_val, (char)i+1, i+1);
                if (!cli_set_ea_path(cli, fname, ea_name, ea_val, i+1)) {
                        printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+                       talloc_destroy(mem_ctx);
                        return False;
                }
        }
@@ -4412,7 +4532,7 @@ static BOOL run_eatest(int dummy)
                correct = False;
        }
 
-       printf("num_eas = %d\n", num_eas);
+       printf("num_eas = %d\n", (int)num_eas);
 
        if (num_eas != 20) {
                printf("Should be 20 EA's stored... failing.\n");
@@ -4421,30 +4541,37 @@ static BOOL run_eatest(int dummy)
 
        for (i = 0; i < num_eas; i++) {
                printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
-               dump_data(0, ea_list[i].value.data, ea_list[i].value.length);
+               dump_data(0, ea_list[i].value.data,
+                         ea_list[i].value.length);
        }
 
        /* Setting EA's to zero length deletes them. Test this */
        printf("Now deleting all EA's - case indepenent....\n");
 
+#if 1
+       cli_set_ea_path(cli, fname, "", "", 0);
+#else
        for (i = 0; i < 20; i++) {
                fstring ea_name;
                slprintf(ea_name, sizeof(ea_name), "ea_%d", i);
                if (!cli_set_ea_path(cli, fname, ea_name, "", 0)) {
                        printf("ea_set of name %s failed - %s\n", ea_name, cli_errstr(cli));
+                       talloc_destroy(mem_ctx);
                        return False;
                }
        }
-       
+#endif
+
        if (!cli_get_ea_list_path(cli, fname, mem_ctx, &num_eas, &ea_list)) {
                printf("ea_get list failed - %s\n", cli_errstr(cli));
                correct = False;
        }
 
-       printf("num_eas = %d\n", num_eas);
+       printf("num_eas = %d\n", (int)num_eas);
        for (i = 0; i < num_eas; i++) {
                printf("%d: ea_name = %s. Val = ", i, ea_list[i].name);
-               dump_data(0, ea_list[i].value.data, ea_list[i].value.length);
+               dump_data(0, ea_list[i].value.data,
+                         ea_list[i].value.length);
        }
 
        if (num_eas != 0) {
@@ -4475,7 +4602,7 @@ static BOOL run_dirtest1(int dummy)
 
        printf("starting directory test\n");
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection(&cli, 0)) {
                return False;
        }
 
@@ -4549,8 +4676,8 @@ static BOOL run_dirtest1(int dummy)
 
 static BOOL run_error_map_extract(int dummy) {
        
-       static struct cli_state c_dos;
-       static struct cli_state c_nt;
+       static struct cli_state *c_dos;
+       static struct cli_state *c_nt;
 
        uint32 error;
 
@@ -4563,81 +4690,81 @@ static BOOL run_error_map_extract(int dummy) {
 
        /* NT-Error connection */
 
-       if (!open_nbt_connection(&c_nt)) {
+       if (!(c_nt = open_nbt_connection())) {
                return False;
        }
 
-       c_nt.use_spnego = False;
+       c_nt->use_spnego = False;
 
-       if (!cli_negprot(&c_nt)) {
-               printf("%s rejected the NT-error negprot (%s)\n",host, cli_errstr(&c_nt));
-               cli_shutdown(&c_nt);
+       if (!cli_negprot(c_nt)) {
+               printf("%s rejected the NT-error negprot (%s)\n",host, cli_errstr(c_nt));
+               cli_shutdown(c_nt);
                return False;
        }
 
-       if (!cli_session_setup(&c_nt, "", "", 0, "", 0,
-                              workgroup)) {
-               printf("%s rejected the NT-error initial session setup (%s)\n",host, cli_errstr(&c_nt));
+       if (!NT_STATUS_IS_OK(cli_session_setup(c_nt, "", "", 0, "", 0,
+                                              workgroup))) {
+               printf("%s rejected the NT-error initial session setup (%s)\n",host, cli_errstr(c_nt));
                return False;
        }
 
        /* DOS-Error connection */
 
-       if (!open_nbt_connection(&c_dos)) {
+       if (!(c_dos = open_nbt_connection())) {
                return False;
        }
 
-       c_dos.use_spnego = False;
-       c_dos.force_dos_errors = True;
+       c_dos->use_spnego = False;
+       c_dos->force_dos_errors = True;
 
-       if (!cli_negprot(&c_dos)) {
-               printf("%s rejected the DOS-error negprot (%s)\n",host, cli_errstr(&c_dos));
-               cli_shutdown(&c_dos);
+       if (!cli_negprot(c_dos)) {
+               printf("%s rejected the DOS-error negprot (%s)\n",host, cli_errstr(c_dos));
+               cli_shutdown(c_dos);
                return False;
        }
 
-       if (!cli_session_setup(&c_dos, "", "", 0, "", 0,
-                              workgroup)) {
-               printf("%s rejected the DOS-error initial session setup (%s)\n",host, cli_errstr(&c_dos));
+       if (!NT_STATUS_IS_OK(cli_session_setup(c_dos, "", "", 0, "", 0,
+                                              workgroup))) {
+               printf("%s rejected the DOS-error initial session setup (%s)\n",host, cli_errstr(c_dos));
                return False;
        }
 
        for (error=(0xc0000000 | 0x1); error < (0xc0000000| 0xFFF); error++) {
                fstr_sprintf(user, "%X", error);
 
-               if (cli_session_setup(&c_nt, user, 
-                                      password, strlen(password),
-                                      password, strlen(password),
-                                     workgroup)) {
+               if (NT_STATUS_IS_OK(cli_session_setup(c_nt, user, 
+                                                     password, strlen(password),
+                                                     password, strlen(password),
+                                                     workgroup))) {
                        printf("/** Session setup succeeded.  This shouldn't happen...*/\n");
                }
                
-               flgs2 = SVAL(c_nt.inbuf,smb_flg2);
+               flgs2 = SVAL(c_nt->inbuf,smb_flg2);
                
                /* Case #1: 32-bit NT errors */
                if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
-                       nt_status = NT_STATUS(IVAL(c_nt.inbuf,smb_rcls));
+                       nt_status = NT_STATUS(IVAL(c_nt->inbuf,smb_rcls));
                } else {
                        printf("/** Dos error on NT connection! (%s) */\n", 
-                              cli_errstr(&c_nt));
+                              cli_errstr(c_nt));
                        nt_status = NT_STATUS(0xc0000000);
                }
 
-               if (cli_session_setup(&c_dos, user, 
-                                      password, strlen(password),
-                                      password, strlen(password),
-                                      workgroup)) {
+               if (NT_STATUS_IS_OK(cli_session_setup(c_dos, user, 
+                                                     password, strlen(password),
+                                                     password, strlen(password),
+                                                     workgroup))) {
                        printf("/** Session setup succeeded.  This shouldn't happen...*/\n");
                }
-               flgs2 = SVAL(c_dos.inbuf,smb_flg2), errnum;
+               flgs2 = SVAL(c_dos->inbuf,smb_flg2), errnum;
                
                /* Case #1: 32-bit NT errors */
                if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
                        printf("/** NT error on DOS connection! (%s) */\n", 
-                              cli_errstr(&c_nt));
+                              cli_errstr(c_nt));
                        errnum = errclass = 0;
                } else {
-                       cli_dos_error(&c_dos, &errclass, &errnum);
+                       cli_dos_error(c_dos, &errclass, &errnum);
                }
 
                if (NT_STATUS_V(nt_status) != error) { 
@@ -4654,6 +4781,101 @@ static BOOL run_error_map_extract(int dummy) {
        return True;
 }
 
+static BOOL run_local_substitute(int dummy)
+{
+       TALLOC_CTX *mem_ctx;
+       int diff = 0;
+
+       if ((mem_ctx = talloc_init("run_local_subst")) == NULL) {
+               printf("talloc_init failed\n");
+               return False;
+       }
+
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%U", "bla", "", -1, -1),
+                      "bla");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%u%U", "bla", "", -1, -1),
+                      "blabla");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%g", "", "", -1, -1),
+                      "NO_GROUP");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%G", "", "", -1, -1),
+                      "NO_GROUP");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%g", "", "", -1, 0),
+                      gidtoname(0));
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%G", "", "", -1, 0),
+                      gidtoname(0));
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%D%u", "u", "dom", -1, 0),
+                      "domu");
+       diff |= strcmp(talloc_sub_specified(mem_ctx, "%i %I", "", "", -1, -1),
+                      "0.0.0.0 0.0.0.0");
+
+       /* Different captialization rules in sub_basic... */
+
+       diff |= strcmp(talloc_sub_basic(mem_ctx, "BLA", "dom", "%U%D"),
+                      "blaDOM");
+
+       TALLOC_FREE(mem_ctx);
+       return (diff == 0);
+}
+
+static BOOL run_local_gencache(int dummy)
+{
+       char *val;
+       time_t tm;
+
+       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;
+       }
+
+       if (!gencache_get("foo", &val, &tm)) {
+               d_printf("%s: gencache_get() failed\n", __location__);
+               return False;
+       }
+
+       if (strcmp(val, "bar") != 0) {
+               d_printf("%s: gencache_get() returned %s, expected %s\n",
+                        __location__, val, "bar");
+               SAFE_FREE(val);
+               return False;
+       }
+
+       SAFE_FREE(val);
+
+       if (!gencache_del("foo")) {
+               d_printf("%s: gencache_del() failed\n", __location__);
+               return False;
+       }
+       if (gencache_del("foo")) {
+               d_printf("%s: second gencache_del() succeeded\n",
+                        __location__);
+               return False;
+       }
+                       
+       if (gencache_get("foo", &val, &tm)) {
+               d_printf("%s: gencache_get() on deleted entry "
+                        "succeeded\n", __location__);
+               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;
+}
+
 static double create_procs(BOOL (*fn)(int), BOOL *result)
 {
        int i, status;
@@ -4692,7 +4914,7 @@ static double create_procs(BOOL (*fn)(int), BOOL *result)
                        slprintf(myname,sizeof(myname),"CLIENT%d", i);
 
                        while (1) {
-                               if (torture_open_connection(&current_cli)) break;
+                               if (torture_open_connection(&current_cli, i)) break;
                                if (tries-- == 0) {
                                        printf("pid %d failed to start\n", (int)getpid());
                                        _exit(1);
@@ -4804,6 +5026,8 @@ static struct {
        {"CHKPATH",  torture_chkpath_test, 0},
        {"FDSESS", run_fdsesstest, 0},
        { "EATEST", run_eatest, 0},
+       { "LOCAL-SUBSTITUTE", run_local_substitute, 0},
+       { "LOCAL-GENCACHE", run_local_gencache, 0},
        {NULL, NULL, 0}};
 
 
@@ -4883,6 +5107,7 @@ static void usage(void)
        printf("\t-A showall\n");
        printf("\t-p port\n");
        printf("\t-s seed\n");
+       printf("\t-b unclist_filename   specify multiple shares for multiple connections\n");
        printf("\n\n");
 
        printf("tests are:");
@@ -4913,7 +5138,9 @@ static void usage(void)
        setbuffer(stdout, NULL, 0);
 #endif
 
-       lp_load(dyn_CONFIGFILE,True,False,False);
+       load_case_tables();
+
+       lp_load(dyn_CONFIGFILE,True,False,False,True);
        load_interfaces();
 
        if (argc < 2) {
@@ -4949,7 +5176,7 @@ static void usage(void)
 
        fstrcpy(workgroup, lp_workgroup());
 
-       while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:m:Ld:Ac:ks:")) != EOF) {
+       while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:m:Ld:Ac:ks:b:")) != EOF) {
                switch (opt) {
                case 'p':
                        port_to_use = atoi(optarg);
@@ -5005,6 +5232,10 @@ static void usage(void)
                                gotpass = 1;
                        }
                        break;
+               case 'b':
+                       fstrcpy(multishare_conn_fname, optarg);
+                       use_multishare_conn = True;
+                       break;
                default:
                        printf("Unknown option %c (%d)\n", (char)opt, opt);
                        usage();