nicer way of handling \clients
[samba.git] / source / torture / nbench / nbio.c
1 #define NBDEBUG 0
2
3 /* 
4    Unix SMB/CIFS implementation.
5    SMB torture tester
6    Copyright (C) Andrew Tridgell 1997-1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 #define MAX_FILES 100
26
27 extern int nbench_line_count;
28 static int nbio_id;
29 static int nprocs;
30 static BOOL bypass_io;
31 static int warmup;
32
33 static struct {
34         int fd;
35         int handle;
36 } ftable[MAX_FILES];
37
38 static struct {
39         double bytes_in, bytes_out;
40         int line;
41         int done;
42 } *children;
43
44 double nbio_total(void)
45 {
46         int i;
47         double total = 0;
48         for (i=0;i<nprocs;i++) {
49                 total += children[i].bytes_out + children[i].bytes_in;
50         }
51         return total;
52 }
53
54 void nb_warmup_done(void)
55 {
56         children[nbio_id].bytes_out = 0;
57         children[nbio_id].bytes_in = 0;
58 }
59
60
61 void nb_alarm(void)
62 {
63         int i;
64         int lines=0, num_clients=0;
65         double t;
66
67         if (nbio_id != -1) return;
68
69         for (i=0;i<nprocs;i++) {
70                 lines += children[i].line;
71                 if (!children[i].done) num_clients++;
72         }
73
74         t = end_timer();
75
76         if (warmup) {
77                 printf("%4d  %8d  %.2f MB/sec  warmup %.0f sec   \r", 
78                        num_clients, lines/nprocs, 
79                        1.0e-6 * nbio_total() / t, 
80                        t);
81         } else {
82                 printf("%4d  %8d  %.2f MB/sec  execute %.0f sec   \r", 
83                        num_clients, lines/nprocs, 
84                        1.0e-6 * nbio_total() / t, 
85                        t);
86         }
87
88         if (warmup && t >= warmup) {
89                 start_timer();
90                 warmup = 0;
91         }
92
93         fflush(stdout);
94
95         signal(SIGALRM, nb_alarm);
96         alarm(1);       
97 }
98
99 void nbio_shmem(int n)
100 {
101         nprocs = n;
102         children = shm_setup(sizeof(*children) * nprocs);
103         if (!children) {
104                 printf("Failed to setup shared memory!\n");
105                 exit(1);
106         }
107 }
108
109 static int find_handle(int handle)
110 {
111         int i;
112         children[nbio_id].line = nbench_line_count;
113         for (i=0;i<MAX_FILES;i++) {
114                 if (ftable[i].handle == handle) return i;
115         }
116         printf("(%d) ERROR: handle %d was not found\n", 
117                nbench_line_count, handle);
118         exit(1);
119
120         return -1;              /* Not reached */
121 }
122
123
124 static struct cli_state *c;
125
126 void nb_setup(struct cli_state *cli, int id, int warmupt)
127 {
128         warmup = warmupt;
129         nbio_id = id;
130         c = cli;
131         start_timer();
132         if (children) {
133                 children[nbio_id].done = 0;
134         }
135         if (bypass_io)
136                 printf("skipping I/O\n");
137 }
138
139
140 static void check_status(const char *op, NTSTATUS status, NTSTATUS ret)
141 {
142         if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) {
143                 printf("[%d] Error: %s should have failed with %s\n", 
144                        nbench_line_count, op, nt_errstr(status));
145                 exit(1);
146         }
147
148         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) {
149                 printf("[%d] Error: %s should have succeeded - %s\n", 
150                        nbench_line_count, op, nt_errstr(ret));
151                 exit(1);
152         }
153
154         if (!NT_STATUS_EQUAL(status, ret)) {
155                 printf("[%d] Warning: got status %s but expected %s\n",
156                        nbench_line_count, nt_errstr(ret), nt_errstr(status));
157         }
158 }
159
160
161 void nb_unlink(const char *fname, int attr, NTSTATUS status)
162 {
163         struct smb_unlink io;
164         NTSTATUS ret;
165
166         io.in.pattern = fname;
167
168         io.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
169         if (strchr(fname, '*') == 0) {
170                 io.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
171         }
172
173         ret = smb_raw_unlink(c->tree, &io);
174
175         check_status("Unlink", status, ret);
176 }
177
178
179 void nb_createx(const char *fname, 
180                 unsigned create_options, unsigned create_disposition, int handle,
181                 NTSTATUS status)
182 {
183         union smb_open io;      
184         int i;
185         uint32 desired_access;
186         NTSTATUS ret;
187         TALLOC_CTX *mem_ctx;
188
189         mem_ctx = talloc_init("raw_open");
190
191         if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
192                 desired_access = SA_RIGHT_FILE_READ_DATA;
193         } else {
194                 desired_access = 
195                         SA_RIGHT_FILE_READ_DATA | 
196                         SA_RIGHT_FILE_WRITE_DATA |
197                         SA_RIGHT_FILE_READ_ATTRIBUTES |
198                         SA_RIGHT_FILE_WRITE_ATTRIBUTES;
199         }
200
201         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
202         io.ntcreatex.in.flags = 0;
203         io.ntcreatex.in.root_fid = 0;
204         io.ntcreatex.in.access_mask = desired_access;
205         io.ntcreatex.in.file_attr = 0;
206         io.ntcreatex.in.alloc_size = 0;
207         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE;
208         io.ntcreatex.in.open_disposition = create_disposition;
209         io.ntcreatex.in.create_options = create_options;
210         io.ntcreatex.in.impersonation = 0;
211         io.ntcreatex.in.security_flags = 0;
212         io.ntcreatex.in.fname = fname;
213
214         ret = smb_raw_open(c->tree, mem_ctx, &io);
215
216         talloc_destroy(mem_ctx);
217
218         check_status("NTCreateX", status, ret);
219
220         if (!NT_STATUS_IS_OK(ret)) return;
221
222         for (i=0;i<MAX_FILES;i++) {
223                 if (ftable[i].handle == 0) break;
224         }
225         if (i == MAX_FILES) {
226                 printf("(%d) file table full for %s\n", nbench_line_count, 
227                        fname);
228                 exit(1);
229         }
230         ftable[i].handle = handle;
231         ftable[i].fd = io.ntcreatex.out.fnum;
232 }
233
234 void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status)
235 {
236         union smb_write io;
237         int i;
238         NTSTATUS ret;
239         char *buf;
240
241         i = find_handle(handle);
242
243         if (bypass_io) return;
244
245         buf = malloc(size);
246         memset(buf, 0xab, size);
247
248         io.writex.level = RAW_WRITE_WRITEX;
249         io.writex.in.fnum = ftable[i].fd;
250         io.writex.in.wmode = 0;
251         io.writex.in.remaining = 0;
252         io.writex.in.offset = offset;
253         io.writex.in.count = size;
254         io.writex.in.data = buf;
255
256         ret = smb_raw_write(c->tree, &io);
257
258         free(buf);
259
260         check_status("WriteX", status, ret);
261
262         if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
263                 printf("[%d] Warning: WriteX got count %d expected %d\n", 
264                        nbench_line_count,
265                        io.writex.out.nwritten, ret_size);
266         }       
267
268         children[nbio_id].bytes_out += ret_size;
269 }
270
271 void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status)
272 {
273         union smb_write io;
274         int i;
275         NTSTATUS ret;
276         char *buf;
277
278         i = find_handle(handle);
279
280         if (bypass_io) return;
281
282         buf = malloc(size);
283
284         memset(buf, 0x12, size);
285
286         io.write.level = RAW_WRITE_WRITE;
287         io.write.in.fnum = ftable[i].fd;
288         io.write.in.remaining = 0;
289         io.write.in.offset = offset;
290         io.write.in.count = size;
291         io.write.in.data = buf;
292
293         ret = smb_raw_write(c->tree, &io);
294
295         free(buf);
296
297         check_status("Write", status, ret);
298
299         if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
300                 printf("[%d] Warning: Write got count %d expected %d\n", 
301                        nbench_line_count,
302                        io.write.out.nwritten, ret_size);
303         }       
304
305         children[nbio_id].bytes_out += ret_size;
306 }
307
308
309 void nb_lockx(int handle, unsigned offset, int size, NTSTATUS status)
310 {
311         union smb_lock io;
312         int i;
313         NTSTATUS ret;
314         struct smb_lock_entry lck;
315
316         i = find_handle(handle);
317
318         lck.pid = getpid();
319         lck.offset = offset;
320         lck.count = size;
321
322         io.lockx.level = RAW_LOCK_LOCKX;
323         io.lockx.in.fnum = ftable[i].fd;
324         io.lockx.in.mode = 0;
325         io.lockx.in.timeout = 0;
326         io.lockx.in.ulock_cnt = 0;
327         io.lockx.in.lock_cnt = 1;
328         io.lockx.in.locks = &lck;
329
330         ret = smb_raw_lock(c->tree, &io);
331
332         check_status("LockX", status, ret);
333 }
334
335 void nb_unlockx(int handle, unsigned offset, int size, NTSTATUS status)
336 {
337         union smb_lock io;
338         int i;
339         NTSTATUS ret;
340         struct smb_lock_entry lck;
341
342         i = find_handle(handle);
343
344         lck.pid = getpid();
345         lck.offset = offset;
346         lck.count = size;
347
348         io.lockx.level = RAW_LOCK_LOCKX;
349         io.lockx.in.fnum = ftable[i].fd;
350         io.lockx.in.mode = 0;
351         io.lockx.in.timeout = 0;
352         io.lockx.in.ulock_cnt = 1;
353         io.lockx.in.lock_cnt = 0;
354         io.lockx.in.locks = &lck;
355
356         ret = smb_raw_lock(c->tree, &io);
357
358         check_status("UnlockX", status, ret);
359 }
360
361 void nb_readx(int handle, int offset, int size, int ret_size, NTSTATUS status)
362 {
363         union smb_read io;
364         int i;
365         NTSTATUS ret;
366         char *buf;
367
368         i = find_handle(handle);
369
370         if (bypass_io) return;
371
372         buf = malloc(size);
373
374         io.readx.level = RAW_READ_READX;
375         io.readx.in.fnum = ftable[i].fd;
376         io.readx.in.offset    = offset;
377         io.readx.in.mincnt    = size;
378         io.readx.in.maxcnt    = size;
379         io.readx.in.remaining = 0;
380         io.readx.out.data     = buf;
381                 
382         ret = smb_raw_read(c->tree, &io);
383
384         free(buf);
385
386         check_status("ReadX", status, ret);
387
388         if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
389                 printf("[%d] Warning: ReadX got count %d expected %d\n", 
390                        nbench_line_count,
391                        io.readx.out.nread, ret_size);
392         }       
393
394         children[nbio_id].bytes_in += ret_size;
395 }
396
397 void nb_close(int handle, NTSTATUS status)
398 {
399         int i;
400         NTSTATUS ret;
401         union smb_close io;
402         
403         i = find_handle(handle);
404
405         io.close.level = RAW_CLOSE_CLOSE;
406         io.close.in.fnum = ftable[i].fd;
407         io.close.in.write_time = 0;
408
409         ret = smb_raw_close(c->tree, &io);
410
411         check_status("Close", status, ret);
412
413         if (NT_STATUS_IS_OK(ret)) {
414                 ftable[i].handle = 0;
415         }
416 }
417
418 void nb_rmdir(const char *dname, NTSTATUS status)
419 {
420         NTSTATUS ret;
421         struct smb_rmdir io;
422
423         io.in.path = dname;
424
425         ret = smb_raw_rmdir(c->tree, &io);
426
427         check_status("Rmdir", status, ret);
428 }
429
430 void nb_mkdir(const char *dname, NTSTATUS status)
431 {
432         union smb_mkdir io;
433
434         io.mkdir.level = RAW_MKDIR_MKDIR;
435         io.mkdir.in.path = dname;
436
437         /* NOTE! no error checking. Used for base fileset creation */
438         smb_raw_mkdir(c->tree, &io);
439 }
440
441 void nb_rename(const char *old, const char *new, NTSTATUS status)
442 {
443         NTSTATUS ret;
444         union smb_rename io;
445
446         io.generic.level = RAW_RENAME_RENAME;
447         io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
448         io.rename.in.pattern1 = old;
449         io.rename.in.pattern2 = new;
450
451         ret = smb_raw_rename(c->tree, &io);
452
453         check_status("Rename", status, ret);
454 }
455
456
457 void nb_qpathinfo(const char *fname, int level, NTSTATUS status)
458 {
459         union smb_fileinfo io;
460         TALLOC_CTX *mem_ctx;
461         NTSTATUS ret;
462
463         mem_ctx = talloc_init("nb_qpathinfo");
464
465         io.generic.level = level;
466         io.generic.in.fname = fname;
467
468         ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
469
470         talloc_destroy(mem_ctx);
471
472         check_status("Pathinfo", status, ret);
473 }
474
475
476 void nb_qfileinfo(int fnum, int level, NTSTATUS status)
477 {
478         union smb_fileinfo io;
479         TALLOC_CTX *mem_ctx;
480         NTSTATUS ret;
481         int i;
482
483         i = find_handle(fnum);
484
485         mem_ctx = talloc_init("nb_qfileinfo");
486
487         io.generic.level = level;
488         io.generic.in.fnum = ftable[i].fd;
489
490         ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
491
492         talloc_destroy(mem_ctx);
493
494         check_status("Fileinfo", status, ret);
495 }
496
497 void nb_sfileinfo(int fnum, int level, NTSTATUS status)
498 {
499         union smb_setfileinfo io;
500         NTSTATUS ret;
501         int i;
502
503         if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
504                 printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
505                 return;
506         }
507
508         ZERO_STRUCT(io);
509
510         i = find_handle(fnum);
511
512         io.generic.level = level;
513         io.generic.file.fnum = ftable[i].fd;
514         unix_to_nt_time(&io.basic_info.in.create_time, time(NULL));
515         unix_to_nt_time(&io.basic_info.in.access_time, 0);
516         unix_to_nt_time(&io.basic_info.in.write_time, 0);
517         unix_to_nt_time(&io.basic_info.in.change_time, 0);
518         io.basic_info.in.attrib = 0;
519
520         ret = smb_raw_setfileinfo(c->tree, &io);
521
522         check_status("Setfileinfo", status, ret);
523 }
524
525 void nb_qfsinfo(int level, NTSTATUS status)
526 {
527         union smb_fsinfo io;
528         TALLOC_CTX *mem_ctx;
529         NTSTATUS ret;
530
531         mem_ctx = talloc_init("cli_dskattr");
532
533         io.generic.level = level;
534         ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
535
536         talloc_destroy(mem_ctx);
537         
538         check_status("Fsinfo", status, ret);    
539 }
540
541 /* callback function used for trans2 search */
542 static BOOL findfirst_callback(void *private, union smb_search_data *file)
543 {
544         return True;
545 }
546
547 void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
548 {
549         union smb_search_first io;
550         TALLOC_CTX *mem_ctx;
551         NTSTATUS ret;
552
553         mem_ctx = talloc_init("cli_dskattr");
554
555         io.t2ffirst.level = level;
556         io.t2ffirst.in.max_count = maxcnt;
557         io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
558         io.t2ffirst.in.pattern = mask;
559         io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
560         io.t2ffirst.in.storage_type = 0;
561                         
562         ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
563
564         talloc_destroy(mem_ctx);
565
566         check_status("Search", status, ret);
567
568         if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
569                 printf("[%d] Warning: got count %d expected %d\n", 
570                        nbench_line_count,
571                        io.t2ffirst.out.count, count);
572         }
573 }
574
575 void nb_flush(int fnum, NTSTATUS status)
576 {
577         struct smb_flush io;
578         NTSTATUS ret;
579         int i;
580         i = find_handle(fnum);
581
582         io.in.fnum = ftable[i].fd;
583
584         ret = smb_raw_flush(c->tree, &io);
585
586         check_status("Flush", status, ret);
587 }
588
589 void nb_deltree(const char *dname)
590 {
591         int total_deleted;
592
593         smb_raw_exit(c->session);
594
595         ZERO_STRUCT(ftable);
596
597         total_deleted = cli_deltree(c->tree, dname);
598
599         if (total_deleted == -1) {
600                 printf("Failed to cleanup tree %s - exiting\n", dname);
601                 exit(1);
602         }
603
604         cli_rmdir(c->tree, dname);
605 }
606
607 void nb_cleanup(const char *cname)
608 {
609         char *dname = NULL;
610         asprintf(&dname, "\\clients\\%s", cname);
611         nb_deltree(dname);
612         free(dname);
613         cli_rmdir(c->tree, "clients");
614         children[nbio_id].done = 1;
615 }