r23779: Change from v2 or later to v3 or later.
[amitay/samba.git] / source3 / torture / locktest.c
index 54cf0dd351898d121b82efffb4cbc8fd26469b86..97242541d48a628edab02643bb45460727febc7e 100644 (file)
@@ -1,12 +1,11 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 2.0
+   Unix SMB/CIFS implementation.
    randomised byte range lock tester
    Copyright (C) Andrew Tridgell 1999
    
    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,
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#define NO_SYSLOG
-
 #include "includes.h"
 
-static fstring password;
-static fstring username;
+static fstring password[2];
+static fstring username[2];
+static int got_user;
 static int got_pass;
+static BOOL use_kerberos;
 static int numops = 1000;
 static BOOL showall;
 static BOOL analyze;
 static BOOL hide_unlock_fails;
 static BOOL use_oplocks;
+static unsigned lock_range = 100;
+static unsigned lock_base = 0;
+static unsigned min_length = 0;
+static BOOL exact_error_codes;
+static BOOL zero_zero;
 
-#define FILENAME "\\locktest.dat"
-#define LOCKRANGE 1000
-#define LOCKBASE 0
+extern char *optarg;
+extern int optind;
 
-/*
-#define LOCKBASE (0x40000000 - 50)
-*/
+#define FILENAME "\\locktest.dat"
 
 #define READ_PCT 50
-#define LOCK_PCT 35
-#define UNLOCK_PCT 55
+#define LOCK_PCT 45
+#define UNLOCK_PCT 70
 #define RANGE_MULTIPLE 1
 #define NSERVERS 2
 #define NCONNECTIONS 2
@@ -51,9 +52,25 @@ static BOOL use_oplocks;
 
 #define NASTY_POSIX_LOCK_HACK 0
 
+enum lock_op {OP_LOCK, OP_UNLOCK, OP_REOPEN};
+
+static const char *lock_op_type(int op)
+{
+       if (op == WRITE_LOCK) return "write";
+       else if (op == READ_LOCK) return "read";
+       else return "other";
+}
+
+static const char *lock_op_name(enum lock_op op)
+{
+       if (op == OP_LOCK) return "lock";
+       else if (op == OP_UNLOCK) return "unlock";
+       else return "reopen";
+}
 
 struct record {
-       char r1, r2;
+       enum lock_op lock_op;
+       enum brl_type lock_type;
        char conn, f;
        SMB_BIG_UINT start, len;
        char needed;
@@ -63,18 +80,49 @@ struct record {
 
 #if PRESETS
 static struct record preset[] = {
-{36,  5, 0, 0, 0,  8, 1},
-{ 2,  6, 0, 1, 0,  1, 1},
-{53, 92, 0, 0, 0,  0, 1},
-{99, 11, 0, 0, 7,  1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 0, 1},
+{OP_UNLOCK, 0       , 0, 0, 2, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, READ_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 1, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
+{OP_LOCK, WRITE_LOCK, 0, 0, 2, 0, 1},
+{OP_LOCK, READ_LOCK, 0, 0, 3, 1, 1},
+{OP_LOCK, WRITE_LOCK, 0, 0, 0, 0, 1},
+{OP_REOPEN, 0, 0, 0, 0, 0, 1},
+
 };
 #endif
 
 static struct record *recorded;
 
-static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid, 
-                     enum brl_type lock_type,
-                     br_off start, br_off size)
+static void print_brl(struct file_id id,
+                       struct server_id pid, 
+                       enum brl_type lock_type,
+                       enum brl_flavour lock_flav,
+                       br_off start,
+                       br_off size,
+                       void *private_data)
 {
 #if NASTY_POSIX_LOCK_HACK
        {
@@ -90,8 +138,8 @@ static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid,
        }
 #endif
 
-       printf("%6d   %05x:%05x    %s  %.0f:%.0f(%.0f)\n", 
-              (int)pid, (int)dev, (int)ino, 
+       printf("%s   %s    %s  %.0f:%.0f(%.0f)\n", 
+              procid_str_static(&pid), file_id_static_string(&id),
               lock_type==READ_LOCK?"R":"W",
               (double)start, (double)start+size-1,(double)size);
 
@@ -100,7 +148,7 @@ static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid,
 
 static void show_locks(void)
 {
-       brl_forall(print_brl);
+       brl_forall(print_brl, NULL);
        /* system("cat /proc/locks"); */
 }
 
@@ -108,16 +156,16 @@ static void show_locks(void)
 /***************************************************** 
 return a connection to a server
 *******************************************************/
-struct cli_state *connect_one(char *share)
+static struct cli_state *connect_one(char *share, int snum)
 {
        struct cli_state *c;
        struct nmb_name called, calling;
        char *server_n;
        fstring server;
        struct in_addr ip;
-       extern struct in_addr ipzero;
        fstring myname;
        static int count;
+       NTSTATUS status;
 
        fstrcpy(server,share+2);
        share = strchr_m(server,'\\');
@@ -127,23 +175,30 @@ struct cli_state *connect_one(char *share)
 
        server_n = server;
        
-       ip = ipzero;
+        zero_ip(&ip);
 
-       slprintf(myname,sizeof(myname), "lock-%u-%u", getpid(), count++);
+       slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++);
 
        make_nmb_name(&calling, myname, 0x0);
        make_nmb_name(&called , server, 0x20);
 
  again:
-       ip = ipzero;
+        zero_ip(&ip);
 
        /* have to open a new connection */
-       if (!(c=cli_initialise(NULL)) || (cli_set_port(c, 139) == 0) ||
-           !cli_connect(c, server_n, &ip)) {
+       if (!(c=cli_initialise())) {
                DEBUG(0,("Connection to %s failed\n", server_n));
                return NULL;
        }
 
+       status = cli_connect(c, server_n, &ip);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Connection to %s failed. Error %s\n", server_n, nt_errstr(status) ));
+               return NULL;
+       }
+
+       c->use_kerberos = use_kerberos;
+
        if (!cli_session_request(c, &calling, &called)) {
                DEBUG(0,("session request to %s failed\n", called.name));
                cli_shutdown(c);
@@ -165,14 +220,22 @@ struct cli_state *connect_one(char *share)
        if (!got_pass) {
                char *pass = getpass("Password: ");
                if (pass) {
-                       pstrcpy(password, pass);
+                       fstrcpy(password[0], pass);
+                       fstrcpy(password[1], pass);
                }
        }
 
-       if (!cli_session_setup(c, username, 
-                              password, strlen(password),
-                              password, strlen(password),
-                              lp_workgroup())) {
+       if (got_pass == 1) {
+               fstrcpy(password[1], password[0]);
+               fstrcpy(username[1], username[0]);
+       }
+
+       if (!NT_STATUS_IS_OK(cli_session_setup(c, username[snum], 
+                                              password[snum],
+                                              strlen(password[snum]),
+                                              password[snum],
+                                              strlen(password[snum]),
+                                              lp_workgroup()))) {
                DEBUG(0,("session setup failed: %s\n", cli_errstr(c)));
                return NULL;
        }
@@ -192,7 +255,7 @@ struct cli_state *connect_one(char *share)
        DEBUG(4,(" session setup ok\n"));
 
        if (!cli_send_tconX(c, share, "?????",
-                           password, strlen(password)+1)) {
+                           password[snum], strlen(password[snum])+1)) {
                DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
                cli_shutdown(c);
                return NULL;
@@ -215,14 +278,15 @@ static void reconnect(struct cli_state *cli[NSERVERS][NCONNECTIONS], int fnum[NS
        for (conn=0;conn<NCONNECTIONS;conn++) {
                if (cli[server][conn]) {
                        for (f=0;f<NFILES;f++) {
-                               cli_close(cli[server][conn], fnum[server][conn][f]);
+                               if (fnum[server][conn][f] != -1) {
+                                       cli_close(cli[server][conn], fnum[server][conn][f]);
+                                       fnum[server][conn][f] = -1;
+                               }
                        }
                        cli_ulogoff(cli[server][conn]);
                        cli_shutdown(cli[server][conn]);
-                       free(cli[server][conn]);
-                       cli[server][conn] = NULL;
                }
-               cli[server][conn] = connect_one(share[server]);
+               cli[server][conn] = connect_one(share[server], server);
                if (!cli[server][conn]) {
                        DEBUG(0,("Failed to connect to %s\n", share[server]));
                        exit(1);
@@ -240,53 +304,61 @@ static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
        unsigned f = rec->f;
        SMB_BIG_UINT start = rec->start;
        SMB_BIG_UINT len = rec->len;
-       unsigned r1 = rec->r1;
-       unsigned r2 = rec->r2;
-       unsigned op;
+       enum brl_type op = rec->lock_type;
        int server;
        BOOL ret[NSERVERS];
+       NTSTATUS status[NSERVERS];
 
-       if (r1 < READ_PCT) {
-               op = READ_LOCK; 
-       } else {
-               op = WRITE_LOCK; 
-       }
-
-       if (r2 < LOCK_PCT) {
+       switch (rec->lock_op) {
+       case OP_LOCK:
                /* set a lock */
                for (server=0;server<NSERVERS;server++) {
                        ret[server] = cli_lock64(cli[server][conn], 
                                                 fnum[server][conn][f],
                                                 start, len, LOCK_TIMEOUT, op);
+                       status[server] = cli_nt_error(cli[server][conn]);
+                       if (!exact_error_codes && 
+                           NT_STATUS_EQUAL(status[server], 
+                                           NT_STATUS_FILE_LOCK_CONFLICT)) {
+                               status[server] = NT_STATUS_LOCK_NOT_GRANTED;
+                       }
                }
-               if (showall || ret[0] != ret[1]) {
-                       printf("lock   conn=%u f=%u range=%.0f:%.0f(%.0f) op=%s -> %u:%u\n",
+               if (showall || !NT_STATUS_EQUAL(status[0],status[1])) {
+                       printf("lock   conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s\n",
                               conn, f, 
-                              (double)start, (double)start+len-1, (double)len,
+                              (double)start, (double)len,
                               op==READ_LOCK?"READ_LOCK":"WRITE_LOCK",
-                              ret[0], ret[1]);
+                              nt_errstr(status[0]), nt_errstr(status[1]));
                }
-               if (showall || ret[0] != ret[1]) show_locks();
-               if (ret[0] != ret[1]) return False;
-       } else if (r2 < LOCK_PCT+UNLOCK_PCT) {
+               if (showall || !NT_STATUS_EQUAL(status[0],status[1])) show_locks();
+               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] = cli_unlock64(cli[server][conn], 
                                                   fnum[server][conn][f],
                                                   start, len);
+                       status[server] = cli_nt_error(cli[server][conn]);
                }
-               if (showall || (!hide_unlock_fails && (ret[0] != ret[1]))) {
-                       printf("unlock conn=%u f=%u range=%.0f:%.0f(%.0f)       -> %u:%u\n",
+               if (showall || 
+                   (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1]))) {
+                       printf("unlock conn=%u f=%u range=%.0f(%.0f)       -> %s:%s\n",
                               conn, f, 
-                              (double)start, (double)start+len-1, (double)len,
-                              ret[0], ret[1]);
+                              (double)start, (double)len,
+                              nt_errstr(status[0]), nt_errstr(status[1]));
                }
-               if (showall || ret[0] != ret[1]) show_locks();
-               if (!hide_unlock_fails && ret[0] != ret[1]) return False;
-       } else {
+               if (showall || !NT_STATUS_EQUAL(status[0],status[1])) show_locks();
+               if (!hide_unlock_fails && !NT_STATUS_EQUAL(status[0],status[1])) 
+                       return False;
+               break;
+
+       case OP_REOPEN:
                /* reopen the file */
                for (server=0;server<NSERVERS;server++) {
                        cli_close(cli[server][conn], fnum[server][conn][f]);
+                       fnum[server][conn][f] = -1;
                }
                for (server=0;server<NSERVERS;server++) {
                        fnum[server][conn][f] = cli_open(cli[server][conn], FILENAME,
@@ -302,7 +374,9 @@ static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
                               conn, f);
                        show_locks();
                }
+               break;
        }
+
        return True;
 }
 
@@ -372,12 +446,12 @@ static void test_locks(char *share[NSERVERS])
 {
        struct cli_state *cli[NSERVERS][NCONNECTIONS];
        int fnum[NSERVERS][NCONNECTIONS][NFILES];
-       int n, i, n1; 
+       int n, i, n1, skip, r1, r2
 
        ZERO_STRUCT(fnum);
        ZERO_STRUCT(cli);
 
-       recorded = (struct record *)malloc(sizeof(*recorded) * numops);
+       recorded = SMB_MALLOC_ARRAY(struct record, numops);
 
        for (n=0; n<numops; n++) {
 #if PRESETS
@@ -387,14 +461,29 @@ static void test_locks(char *share[NSERVERS])
 #endif
                        recorded[n].conn = random() % NCONNECTIONS;
                        recorded[n].f = random() % NFILES;
-                       recorded[n].start = LOCKBASE + ((unsigned)random() % (LOCKRANGE-1));
-                       recorded[n].len =  
-                               random() % (LOCKRANGE-(recorded[n].start-LOCKBASE));
+                       recorded[n].start = lock_base + ((unsigned)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].r1 = random() % 100;
-                       recorded[n].r2 = random() % 100;
+                       r1 = random() % 100;
+                       r2 = random() % 100;
+                       if (r1 < READ_PCT) {
+                               recorded[n].lock_type = READ_LOCK;
+                       } else {
+                               recorded[n].lock_type = WRITE_LOCK;
+                       }
+                       if (r2 < LOCK_PCT) {
+                               recorded[n].lock_op = OP_LOCK;
+                       } else if (r2 < UNLOCK_PCT) {
+                               recorded[n].lock_op = OP_UNLOCK;
+                       } else {
+                               recorded[n].lock_op = OP_REOPEN;
+                       }
                        recorded[n].needed = True;
+                       if (!zero_zero && recorded[n].start==0 && recorded[n].len==0) {
+                               recorded[n].len = 1;
+                       }
 #if PRESETS
                }
 #endif
@@ -407,6 +496,8 @@ static void test_locks(char *share[NSERVERS])
        if (n == numops || !analyze) return;
        n++;
 
+       skip = n/2;
+
        while (1) {
                n1 = n;
 
@@ -414,26 +505,37 @@ static void test_locks(char *share[NSERVERS])
                reconnect(cli, fnum, share);
                open_files(cli, fnum);
 
-               for (i=0;i<n-1;i++) {
-                       int m;
-                       recorded[i].needed = False;
+               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;
+                       }
 
                        close_files(cli, fnum);
                        open_files(cli, fnum);
 
                        m = retest(cli, fnum, n);
                        if (m == n) {
-                               recorded[i].needed = True;
+                               for (j=i;j<i+skip;j++) {
+                                       recorded[j].needed = True;
+                               }
                        } else {
-                               if (i < m) {
-                                       memmove(&recorded[i], &recorded[i+1],
-                                               (m-i)*sizeof(recorded[0]));
+                               if (i+(skip-1) < m) {
+                                       memmove(&recorded[i], &recorded[i+skip],
+                                               (m-(i+skip-1))*sizeof(recorded[0]));
                                }
-                               n = m;
+                               n = m-(skip-1);
                                i--;
                        }
                }
 
+               if (skip > 1) {
+                       skip = skip/2;
+                       printf("skip=%d\n", skip);
+                       continue;
+               }
+
                if (n1 == n) break;
        }
 
@@ -448,9 +550,9 @@ static void test_locks(char *share[NSERVERS])
        close_files(cli, fnum);
 
        for (i=0;i<n;i++) {
-               printf("{%u, %u, %u, %u, %.0f, %.0f, %u},\n",
-                      recorded[i].r1,
-                      recorded[i].r2,
+               printf("{%s, %s, conn = %u, file = %u, start = %.0f, len = %.0f, %u},\n",
+                      lock_op_name(recorded[i].lock_op),
+                      lock_op_type(recorded[i].lock_type),
                       recorded[i].conn,
                       recorded[i].f,
                       (double)recorded[i].start,
@@ -467,12 +569,19 @@ static void usage(void)
 "Usage:\n\
   locktest //server1/share1 //server2/share2 [options..]\n\
   options:\n\
-        -U user%%pass\n\
+        -U user%%pass        (may be specified twice)\n\
+        -k               use kerberos\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\
 ");
 }
 
@@ -482,17 +591,15 @@ static void usage(void)
  int main(int argc,char *argv[])
 {
        char *share[NSERVERS];
-       extern char *optarg;
-       extern int optind;
-       extern FILE *dbf;
        int opt;
        char *p;
        int seed, server;
-       static pstring servicesf = CONFIGFILE;
 
        setlinebuf(stdout);
 
-       dbf = stderr;
+       load_case_tables();
+
+       dbf = x_stderr;
 
        if (argc < 3 || argv[1][0] == '-') {
                usage();
@@ -509,28 +616,49 @@ static void usage(void)
        argc -= NSERVERS;
        argv += NSERVERS;
 
-       TimeInit();
-
-       lp_load(servicesf,True,False,False);
+       lp_load(dyn_CONFIGFILE,True,False,False,True);
        load_interfaces();
 
        if (getenv("USER")) {
-               pstrcpy(username,getenv("USER"));
+               fstrcpy(username[0],getenv("USER"));
+               fstrcpy(username[1],getenv("USER"));
        }
 
        seed = time(NULL);
 
-       while ((opt = getopt(argc, argv, "U:s:ho:aAW:O")) != EOF) {
+       while ((opt = getopt(argc, argv, "U:s:ho:aAW:OkR:B:M:EZ")) != EOF) {
                switch (opt) {
+               case 'k':
+#ifdef HAVE_KRB5
+                       use_kerberos = True;
+#else
+                       d_printf("No kerberos support compiled in\n");
+                       exit(1);
+#endif
+                       break;
                case 'U':
-                       pstrcpy(username,optarg);
-                       p = strchr_m(username,'%');
+                       got_user = 1;
+                       if (got_pass == 2) {
+                               d_printf("Max of 2 usernames\n");
+                               exit(1);
+                       }
+                       fstrcpy(username[got_pass],optarg);
+                       p = strchr_m(username[got_pass],'%');
                        if (p) {
                                *p = 0;
-                               pstrcpy(password, p+1);
-                               got_pass = 1;
+                               fstrcpy(password[got_pass], p+1);
+                               got_pass++;
                        }
                        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;
@@ -549,6 +677,12 @@ static void usage(void)
                case 'A':
                        analyze = True;
                        break;
+               case 'Z':
+                       zero_zero = True;
+                       break;
+               case 'E':
+                       exact_error_codes = True;
+                       break;
                case 'h':
                        usage();
                        exit(1);
@@ -558,13 +692,14 @@ static void usage(void)
                }
        }
 
+       if(use_kerberos && !got_user) got_pass = True;
+
        argc -= optind;
        argv += optind;
 
        DEBUG(0,("seed=%u\n", seed));
        srandom(seed);
 
-       locking_init(1);
        test_locks(share);
 
        return(0);