r23779: Change from v2 or later to v3 or later.
[amitay/samba.git] / source3 / torture / locktest.c
index 0339576b111a75f6fffec131511d29fe4a49c918..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 5
-#define LOCKBASE 0
-#define MINLENGTH 0
-
-#define ZERO_ZERO 1
+extern char *optarg;
+extern int optind;
 
-/*
-#define LOCKBASE (0x40000000 - 50)
-*/
+#define FILENAME "\\locktest.dat"
 
 #define READ_PCT 50
 #define LOCK_PCT 45
@@ -56,9 +54,23 @@ static BOOL use_oplocks;
 
 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 {
        enum lock_op lock_op;
-       int lock_type;
+       enum brl_type lock_type;
        char conn, f;
        SMB_BIG_UINT start, len;
        char needed;
@@ -104,9 +116,13 @@ static struct record preset[] = {
 
 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
        {
@@ -122,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);
 
@@ -132,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"); */
 }
 
@@ -140,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,'\\');
@@ -159,22 +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_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);
@@ -196,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;
        }
@@ -223,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;
@@ -246,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);
@@ -271,9 +304,10 @@ 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 op = rec->lock_type;
+       enum brl_type op = rec->lock_type;
        int server;
        BOOL ret[NSERVERS];
+       NTSTATUS status[NSERVERS];
 
        switch (rec->lock_op) {
        case OP_LOCK:
@@ -282,16 +316,22 @@ static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
                        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) 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)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;
+               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:
@@ -300,21 +340,25 @@ static BOOL test_one(struct cli_state *cli[NSERVERS][NCONNECTIONS],
                        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)       -> %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)len,
-                              ret[0], ret[1]);
+                              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;
+               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,
@@ -407,7 +451,7 @@ static void test_locks(char *share[NSERVERS])
        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
@@ -417,9 +461,9 @@ 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 =  MINLENGTH +
-                               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;
                        r1 = random() % 100;
@@ -437,12 +481,9 @@ static void test_locks(char *share[NSERVERS])
                                recorded[n].lock_op = OP_REOPEN;
                        }
                        recorded[n].needed = True;
-#if !ZERO_ZERO
-                       if (recorded[n].start == 0 &&
-                           recorded[n].len == 0) {
+                       if (!zero_zero && recorded[n].start==0 && recorded[n].len==0) {
                                recorded[n].len = 1;
                        }
-#endif
 #if PRESETS
                }
 #endif
@@ -509,9 +550,9 @@ static void test_locks(char *share[NSERVERS])
        close_files(cli, fnum);
 
        for (i=0;i<n;i++) {
-               printf("{%d, %d, %u, %u, %.0f, %.0f, %u},\n",
-                      recorded[i].lock_op,
-                      recorded[i].lock_type,
+               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,
@@ -528,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\
 ");
 }
 
@@ -543,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();
@@ -570,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;
@@ -610,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);
@@ -619,6 +692,8 @@ static void usage(void)
                }
        }
 
+       if(use_kerberos && !got_user) got_pass = True;
+
        argc -= optind;
        argv += optind;