subunit: Support formatting compatible with upstream subunit, for consistency.
[sfrench/samba-autobuild/.git] / source4 / torture / locktest.c
index 4554f52e4113000366c1e08cf2a09aab251eb8e9..b3ee8fc28f9d47b8105d4f35fd7bf1074a29f9d0 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,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "lib/events/events.h"
 #include "system/filesys.h"
 #include "system/time.h"
-#include "pstring.h"
+#include "auth/credentials/credentials.h"
 #include "auth/gensec/gensec.h"
 #include "libcli/libcli.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
 
 static int numops = 1000;
-static BOOL showall;
-static BOOL analyze;
-static BOOL hide_unlock_fails;
-static BOOL use_oplocks;
-static uint_t lock_range = 100;
-static uint_t lock_base = 0;
-static uint_t min_length = 0;
-static BOOL exact_error_codes;
-static BOOL zero_zero;
+static int showall;
+static int analyze;
+static int hide_unlock_fails;
+static int use_oplocks;
+static unsigned int lock_range = 100;
+static unsigned int lock_base = 0;
+static unsigned int min_length = 0;
+static int exact_error_codes;
+static int zero_zero;
 
 #define FILENAME "\\locktest.dat"
 
@@ -57,6 +60,7 @@ struct record {
        char conn, f;
        uint64_t start, len;
        char needed;
+       uint16_t pid;
 };
 
 #define PRESETS 0
@@ -102,16 +106,24 @@ static struct record *recorded;
 /***************************************************** 
 return a connection to a server
 *******************************************************/
-static struct smbcli_state *connect_one(char *share, int snum, int conn)
+static struct smbcli_state *connect_one(struct tevent_context *ev,
+                                       struct loadparm_context *lp_ctx,
+                                       TALLOC_CTX *mem_ctx,
+                                       char *share, int snum, int conn)
 {
        struct smbcli_state *c;
-       fstring server, myname;
+       char *server, *myname;
        NTSTATUS status;
        int retries = 10;
+       struct smbcli_options options;
+       struct smbcli_session_options session_options;
+
+       lp_smbcli_options(lp_ctx, &options);
+       lp_smbcli_session_options(lp_ctx, &session_options);
 
        printf("connect_one(%s, %d, %d)\n", share, snum, conn);
 
-       fstrcpy(server,share+2);
+       server = talloc_strdup(mem_ctx, share+2);
        share = strchr_m(server,'\\');
        if (!share) return NULL;
        *share = 0;
@@ -121,10 +133,10 @@ static struct smbcli_state *connect_one(char *share, int snum, int conn)
                char **unc_list = NULL;
                int num_unc_names;
                const char *p;
-               p = lp_parm_string(-1, "torture", "unclist");
+               p = lp_parm_string(lp_ctx, NULL, "torture", "unclist");
                if (p) {
                        char *h, *s;
-                       unc_list = file_lines_load(p, &num_unc_names, NULL);
+                       unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
                        if (!unc_list || num_unc_names <= 0) {
                                printf("Failed to load unc names list from '%s'\n", p);
                                exit(1);
@@ -136,21 +148,27 @@ static struct smbcli_state *connect_one(char *share, int snum, int conn)
                                       unc_list[conn % num_unc_names]);
                                exit(1);
                        }
-                       fstrcpy(server, h);
-                       fstrcpy(share, s);
+                       server = talloc_strdup(mem_ctx, h);
+                       share = talloc_strdup(mem_ctx, s);
                }
        }
 
 
-       slprintf(myname,sizeof(myname), "lock-%u-%u", getpid(), snum);
+       myname = talloc_asprintf(mem_ctx, "lock-%u-%u", getpid(), snum);
        cli_credentials_set_workstation(servers[snum], myname, CRED_SPECIFIED);
 
        do {
                printf("\\\\%s\\%s\n", server, share);
                status = smbcli_full_connection(NULL, &c, 
                                                server, 
+                                               lp_smb_ports(lp_ctx),
                                                share, NULL,
-                                               servers[snum], NULL);
+                                               lp_socket_options(lp_ctx),
+                                               servers[snum], 
+                                               lp_resolve_context(lp_ctx),
+                                               ev, &options, &session_options,
+                                               lp_iconv_convenience(lp_ctx),
+                                               lp_gensec_settings(mem_ctx, lp_ctx));
                if (!NT_STATUS_IS_OK(status)) {
                        sleep(2);
                }
@@ -164,7 +182,10 @@ static struct smbcli_state *connect_one(char *share, int snum, int conn)
 }
 
 
-static void reconnect(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES],
+static void reconnect(struct tevent_context *ev,
+                     struct loadparm_context *lp_ctx,
+                         TALLOC_CTX *mem_ctx,
+                     struct smbcli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NSERVERS][NCONNECTIONS][NFILES],
                      char *share[NSERVERS])
 {
        int server, conn, f;
@@ -180,7 +201,8 @@ static void reconnect(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], int fnum
                        }
                        talloc_free(cli[server][conn]);
                }
-               cli[server][conn] = connect_one(share[server], server, conn);
+               cli[server][conn] = connect_one(ev, lp_ctx, mem_ctx, share[server], 
+                                               server, conn);
                if (!cli[server][conn]) {
                        DEBUG(0,("Failed to connect to %s\n", share[server]));
                        exit(1);
@@ -190,26 +212,52 @@ static void reconnect(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], int fnum
 
 
 
-static BOOL test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], 
+static bool test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], 
                     int fnum[NSERVERS][NCONNECTIONS][NFILES],
                     struct record *rec)
 {
-       uint_t conn = rec->conn;
-       uint_t f = rec->f;
+       unsigned int conn = rec->conn;
+       unsigned int f = rec->f;
        uint64_t start = rec->start;
        uint64_t len = rec->len;
        enum brl_type op = rec->lock_type;
        int server;
-       BOOL ret[NSERVERS];
+       bool ret[NSERVERS];
        NTSTATUS status[NSERVERS];
 
        switch (rec->lock_op) {
        case OP_LOCK:
                /* set a lock */
                for (server=0;server<NSERVERS;server++) {
-                       ret[server] = NT_STATUS_IS_OK(smbcli_lock64(cli[server][conn]->tree, 
-                                                fnum[server][conn][f],
-                                                start, len, LOCK_TIMEOUT, op));
+                       NTSTATUS res;
+                       struct smbcli_tree *tree=cli[server][conn]->tree;
+                       int fn=fnum[server][conn][f];
+
+                       if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+                               res=smbcli_lock(tree, fn, start, len, LOCK_TIMEOUT, rec->lock_op);
+                       } else {
+                               union smb_lock parms;
+                               int ltype;
+                               struct smb_lock_entry lock[1];
+
+                               parms.lockx.level = RAW_LOCK_LOCKX;
+                               parms.lockx.in.file.fnum = fn;
+       
+                               ltype = (rec->lock_op == READ_LOCK? 1 : 0);
+                               ltype |= LOCKING_ANDX_LARGE_FILES;
+                               parms.lockx.in.mode = ltype;
+                               parms.lockx.in.timeout = LOCK_TIMEOUT;
+                               parms.lockx.in.ulock_cnt = 0;
+                               parms.lockx.in.lock_cnt = 1;
+                               lock[0].pid = rec->pid;
+                               lock[0].offset = start;
+                               lock[0].count = len;
+                               parms.lockx.in.locks = &lock[0];
+
+                               res = smb_raw_lock(tree, &parms);
+                       }
+
+                       ret[server] = NT_STATUS_IS_OK(res); 
                        status[server] = smbcli_nt_error(cli[server][conn]->tree);
                        if (!exact_error_codes && 
                            NT_STATUS_EQUAL(status[server], 
@@ -224,15 +272,38 @@ static BOOL test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
                               op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
                               nt_errstr(status[0]), nt_errstr(status[1]));
                }
-               if (!NT_STATUS_EQUAL(status[0],status[1])) return False;
+               if (!NT_STATUS_EQUAL(status[0],status[1])) return false;
                break;
                
        case OP_UNLOCK:
                /* unset a lock */
                for (server=0;server<NSERVERS;server++) {
-                       ret[server] = NT_STATUS_IS_OK(smbcli_unlock64(cli[server][conn]->tree, 
-                                                  fnum[server][conn][f],
-                                                  start, len));
+                       NTSTATUS res;
+                       struct smbcli_tree *tree=cli[server][conn]->tree;
+                       int fn=fnum[server][conn][f];
+
+
+                       if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+                               res=smbcli_unlock(tree, fn, start, len);
+                       } else {
+                               union smb_lock parms;
+                               struct smb_lock_entry lock[1];
+
+                               parms.lockx.level = RAW_LOCK_LOCKX;
+                               parms.lockx.in.file.fnum = fn;
+                               parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+                               parms.lockx.in.timeout = 0;
+                               parms.lockx.in.ulock_cnt = 1;
+                               parms.lockx.in.lock_cnt = 0;
+                               lock[0].pid = rec->pid;
+                               lock[0].count = len;
+                               lock[0].offset = start;
+                               parms.lockx.in.locks = &lock[0];
+
+                               res = smb_raw_lock(tree, &parms);
+                       }
+
+                       ret[server] = NT_STATUS_IS_OK(res);
                        status[server] = smbcli_nt_error(cli[server][conn]->tree);
                }
                if (showall || 
@@ -243,7 +314,7 @@ static BOOL test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
                               nt_errstr(status[0]), nt_errstr(status[1]));
                }
                if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1])) 
-                       return False;
+                       return false;
                break;
 
        case OP_REOPEN:
@@ -258,7 +329,7 @@ static BOOL test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
                                                         DENY_NONE);
                        if (fnum[server][conn][f] == -1) {
                                printf("failed to reopen on share%d\n", server);
-                               return False;
+                               return false;
                        }
                }
                if (showall) {
@@ -268,7 +339,7 @@ static BOOL test_one(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
                break;
        }
 
-       return True;
+       return true;
 }
 
 static void close_files(struct smbcli_state *cli[NSERVERS][NCONNECTIONS], 
@@ -314,7 +385,7 @@ static int retest(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
                   int n)
 {
        int i;
-       printf("testing %u ...\n", n);
+       printf("Testing %u ...\n", n);
        for (i=0; i<n; i++) {
                if (i && i % 100 == 0) {
                        printf("%u\n", i);
@@ -333,7 +404,10 @@ static int retest(struct smbcli_state *cli[NSERVERS][NCONNECTIONS],
    we then do random locking ops in tamdem on the 4 fnums from each
    server and ensure that the results match
  */
-static void test_locks(char *share[NSERVERS])
+static int test_locks(struct tevent_context *ev,
+                     struct loadparm_context *lp_ctx,
+                         TALLOC_CTX *mem_ctx,
+                     char *share[NSERVERS])
 {
        struct smbcli_state *cli[NSERVERS][NCONNECTIONS];
        int fnum[NSERVERS][NCONNECTIONS][NFILES];
@@ -352,11 +426,15 @@ static void test_locks(char *share[NSERVERS])
 #endif
                        recorded[n].conn = random() % NCONNECTIONS;
                        recorded[n].f = random() % NFILES;
-                       recorded[n].start = lock_base + ((uint_t)random() % (lock_range-1));
+                       recorded[n].start = lock_base + ((unsigned int)random() % (lock_range-1));
                        recorded[n].len =  min_length +
                                random() % (lock_range-(recorded[n].start-lock_base));
                        recorded[n].start *= RANGE_MULTIPLE;
                        recorded[n].len *= RANGE_MULTIPLE;
+                       recorded[n].pid = random()%3;
+                       if (recorded[n].pid == 2) {
+                               recorded[n].pid = 0xFFFF; /* see if its magic */
+                       }
                        r1 = random() % 100;
                        r2 = random() % 100;
                        if (r1 < READ_PCT) {
@@ -371,7 +449,7 @@ static void test_locks(char *share[NSERVERS])
                        } else {
                                recorded[n].lock_op = OP_REOPEN;
                        }
-                       recorded[n].needed = True;
+                       recorded[n].needed = true;
                        if (!zero_zero && recorded[n].start==0 && recorded[n].len==0) {
                                recorded[n].len = 1;
                        }
@@ -380,11 +458,16 @@ static void test_locks(char *share[NSERVERS])
 #endif
        }
 
-       reconnect(cli, fnum, share);
+       reconnect(ev, lp_ctx, mem_ctx, cli, fnum, share);
        open_files(cli, fnum);
        n = retest(cli, fnum, numops);
 
-       if (n == numops || !analyze) return;
+       if (n == numops || !analyze) {
+               if (n != numops) {
+                       return 1;
+               }
+               return 0;
+       }
        n++;
 
        skip = n/2;
@@ -393,14 +476,14 @@ static void test_locks(char *share[NSERVERS])
                n1 = n;
 
                close_files(cli, fnum);
-               reconnect(cli, fnum, share);
+               reconnect(ev, lp_ctx, mem_ctx, cli, fnum, share);
                open_files(cli, fnum);
 
                for (i=0;i<n-skip;i+=skip) {
                        int m, j;
                        printf("excluding %d-%d\n", i, i+skip-1);
                        for (j=i;j<i+skip;j++) {
-                               recorded[j].needed = False;
+                               recorded[j].needed = false;
                        }
 
                        close_files(cli, fnum);
@@ -409,7 +492,7 @@ static void test_locks(char *share[NSERVERS])
                        m = retest(cli, fnum, n);
                        if (m == n) {
                                for (j=i;j<i+skip;j++) {
-                                       recorded[j].needed = True;
+                                       recorded[j].needed = true;
                                }
                        } else {
                                if (i+(skip-1) < m) {
@@ -431,9 +514,9 @@ static void test_locks(char *share[NSERVERS])
        }
 
        close_files(cli, fnum);
-       reconnect(cli, fnum, share);
+       reconnect(ev, lp_ctx, mem_ctx, cli, fnum, share);
        open_files(cli, fnum);
-       showall = True;
+       showall = true;
        n1 = retest(cli, fnum, n);
        if (n1 != n-1) {
                printf("ERROR - inconsistent result (%u %u)\n", n1, n);
@@ -450,30 +533,16 @@ static void test_locks(char *share[NSERVERS])
                       (double)recorded[i].len,
                       recorded[i].needed);
        }       
+
+       return 1;
 }
 
 
 
-static void usage(void)
+static void usage(poptContext pc)
 {
-       printf(
-"Usage:\n\
-  locktest //server1/share1 //server2/share2 [options..]\n\
-  options:\n\
-        -U user%%pass        (may be specified twice)\n\
-        -s seed\n\
-        -o numops\n\
-        -u          hide unlock fails\n\
-        -a          (show all ops)\n\
-        -A          analyse for minimal ops\n\
-        -O          use oplocks\n\
-        -E          enable exact error code checking\n\
-        -Z          enable the zero/zero lock\n\
-        -R range    set lock range\n\
-        -B base     set lock base\n\
-        -M min      set min lock length\n\
-        -l filename unclist file\n\
-");
+       printf("Usage:\n\tlocktest //server1/share1 //server2/share2 [options..]\n");
+       poptPrintUsage(pc, stdout, 0);
 }
 
 /****************************************************************************
@@ -485,113 +554,103 @@ static void usage(void)
        int opt;
        int seed, server;
        int username_count=0;
+       struct tevent_context *ev;
+       struct loadparm_context *lp_ctx;
+       poptContext pc;
+       int argc_new, i;
+       char **argv_new;
+       enum {OPT_UNCLIST=1000};
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               {"seed",          0, POPT_ARG_INT,  &seed,      0,      "Seed to use for randomizer",   NULL},
+               {"num-ops",       0, POPT_ARG_INT,  &numops,    0,      "num ops",      NULL},
+               {"lockrange",     0, POPT_ARG_INT,  &lock_range,0,      "locking range", NULL},
+               {"lockbase",      0, POPT_ARG_INT,  &lock_base, 0,      "locking base", NULL},
+               {"minlength",     0, POPT_ARG_INT,  &min_length,0,      "min lock length", NULL},
+               {"hidefails",     0, POPT_ARG_NONE, &hide_unlock_fails,0,"hide unlock fails", NULL},
+               {"oplocks",       0, POPT_ARG_NONE, &use_oplocks,0,      "use oplocks", NULL},
+               {"showall",       0, POPT_ARG_NONE, &showall,    0,      "display all operations", NULL},
+               {"analyse",       0, POPT_ARG_NONE, &analyze,    0,      "do backtrack analysis", NULL},
+               {"zerozero",      0, POPT_ARG_NONE, &zero_zero,    0,      "do zero/zero lock", NULL},
+               {"exacterrors",   0, POPT_ARG_NONE, &exact_error_codes,0,"use exact error codes", NULL},
+               {"unclist",       0, POPT_ARG_STRING,   NULL,   OPT_UNCLIST,    "unclist",      NULL},
+               { "user", 'U',       POPT_ARG_STRING, NULL, 'U', "Set the network username", "[DOMAIN/]USERNAME[%PASSWORD]" },
+               POPT_COMMON_SAMBA
+               POPT_COMMON_CONNECTION
+               POPT_COMMON_CREDENTIALS
+               POPT_COMMON_VERSION
+               { NULL }
+       };
 
        setlinebuf(stdout);
+       seed = time(NULL);
 
-       setup_logging("locktest", DEBUG_STDOUT);
-
-       if (argc < 3 || argv[1][0] == '-') {
-               usage();
-               exit(1);
-       }
-
-       setup_logging(argv[0], DEBUG_STDOUT);
-
-       for (server=0;server<NSERVERS;server++) {
-               share[server] = argv[1+server];
-               all_string_sub(share[server],"/","\\",0);
-       }
-
-       argc -= NSERVERS;
-       argv += NSERVERS;
+       pc = poptGetContext("locktest", argc, (const char **) argv, long_options, 
+                           POPT_CONTEXT_KEEP_FIRST);
 
-       lp_load();
+       poptSetOtherOptionHelp(pc, "<unc1> <unc2>");
 
+       lp_ctx = cmdline_lp_ctx;
        servers[0] = cli_credentials_init(talloc_autofree_context());
        servers[1] = cli_credentials_init(talloc_autofree_context());
-       cli_credentials_guess(servers[0]);
-       cli_credentials_guess(servers[1]);
+       cli_credentials_guess(servers[0], lp_ctx);
+       cli_credentials_guess(servers[1], lp_ctx);
 
-       seed = time(NULL);
-
-       while ((opt = getopt(argc, argv, "U:s:ho:aAW:OR:B:M:EZW:l:")) != EOF) {
+       while((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
+               case OPT_UNCLIST:
+                       lp_set_cmdline(cmdline_lp_ctx, "torture:unclist", poptGetOptArg(pc));
+                       break;
                case 'U':
                        if (username_count == 2) {
-                               usage();
+                               usage(pc);
                                exit(1);
                        }
-                       cli_credentials_parse_string(servers[username_count], 
-                                                    optarg, CRED_SPECIFIED);
+                       cli_credentials_parse_string(servers[username_count], poptGetOptArg(pc), CRED_SPECIFIED);
                        username_count++;
                        break;
-               case 'R':
-                       lock_range = strtol(optarg, NULL, 0);
-                       break;
-               case 'B':
-                       lock_base = strtol(optarg, NULL, 0);
-                       break;
-               case 'M':
-                       min_length = strtol(optarg, NULL, 0);
-                       break;
-               case 's':
-                       seed = atoi(optarg);
-                       break;
-               case 'u':
-                       hide_unlock_fails = True;
-                       break;
-               case 'o':
-                       numops = atoi(optarg);
-                       break;
-               case 'O':
-                       use_oplocks = True;
-                       break;
-               case 'a':
-                       showall = True;
-                       break;
-               case 'A':
-                       analyze = True;
-                       break;
-               case 'Z':
-                       zero_zero = True;
-                       break;
-               case 'E':
-                       exact_error_codes = True;
-                       break;
-               case 'l':
-                       lp_set_cmdline("torture:unclist", optarg);
-                       break;
-               case 'W':
-                       lp_set_cmdline("workgroup", optarg);
+               }
+       }
+
+       argv_new = discard_const_p(char *, poptGetArgs(pc));
+       argc_new = argc;
+       for (i=0; i<argc; i++) {
+               if (argv_new[i] == NULL) {
+                       argc_new = i;
                        break;
-               case 'h':
-                       usage();
-                       exit(1);
-               default:
-                       printf("Unknown option %c (%d)\n", (char)opt, opt);
-                       exit(1);
                }
        }
 
+       if (!(argc_new >= 3)) {
+               usage(pc);
+               exit(1);
+       }
+
+       setup_logging("locktest", DEBUG_STDOUT);
+
+       for (server=0;server<NSERVERS;server++) {
+               share[server] = argv_new[1+server];
+               all_string_sub(share[server],"/","\\",0);
+       }
+
+       lp_ctx = cmdline_lp_ctx;
+
        if (username_count == 0) {
-               usage();
+               usage(pc);
                return -1;
        }
        if (username_count == 1) {
                servers[1] = servers[0];
        }
 
-       gensec_init();
+       ev = s4_event_context_init(talloc_autofree_context());
 
-       argc -= optind;
-       argv += optind;
+       gensec_init(lp_ctx);
 
        DEBUG(0,("seed=%u base=%d range=%d min_length=%d\n", 
                 seed, lock_base, lock_range, min_length));
        srandom(seed);
 
-       test_locks(share);
-
-       return(0);
+       return test_locks(ev, lp_ctx, NULL, share);
 }