1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include "nfsgen.h"
  28 
  29 int64_t io_buff_size = 32 * 1024; /* default to 32KB */
  30 int64_t io_buff_num = 1024;
  31 int64_t io_hold_num = -1;       /* default to no wait */
  32 int64_t io_init_offset = 0;
  33 int64_t io_loop_count = 1;
  34 int64_t lock_init_offset = 0;
  35 int64_t lock_range = 0;
  36 int64_t maxTruncSize = 0;
  37 short lock_type;
  38 int is_read = 0;
  39 int is_write = 0;
  40 int is_lock = 0;
  41 int is_blockinglock = 0;
  42 int is_unlock = 0;
  43 int is_closefile = 0;
  44 int is_truncate = 0;
  45 int is_returndel = 0;
  46 int open_flag = O_RDONLY;
  47 int signaled = 0;
  48 mode_t open_mode = 0664;
  49 unsigned int write_seed = 777;
  50 unsigned int read_seed = 777;
  51 unsigned int sleep_sec = 0;
  52 char *file_name = NULL;
  53 
  54 void
  55 fileOperatorDump()
  56 {
  57         dprint("io_buff_size: %lld\n", io_buff_size);
  58         dprint("io_buff_num: %lld\n", io_buff_num);
  59         dprint("io_hold_num: %lld\n", io_hold_num);
  60         dprint("io_init_offset: %lld\n", io_init_offset);
  61         dprint("io_loop_count: %lld\n", io_loop_count);
  62         dprint("lock_init_offset: %lld\n", lock_init_offset);
  63         dprint("lock_range: %lld\n", lock_range);
  64         dprint("lock_type: %d\n", lock_type);
  65         dprint("is_read: %d\n", is_read);
  66         dprint("is_write: %d\n", is_write);
  67         dprint("is_lock: %d\n", is_lock);
  68         dprint("is_unlock: %d\n", is_unlock);
  69         dprint("is_closefile: %d\n", is_closefile);
  70         dprint("is_truncate: %d\n", is_truncate);
  71         dprint("maxTruncSize: %lld\n", maxTruncSize);
  72         dprint("open_flag: %d\n", open_flag);
  73         dprint("open_mode: %d\n", open_mode);
  74         dprint("write_seed: %d\n", write_seed);
  75         dprint("read_seed: %d\n", read_seed);
  76         dprint("sleep_sec: %d\n", sleep_sec);
  77         dprint("debug: %d\n", debug);
  78         dprint("showerror: %d\n", showerror);
  79         dprint("file_name: %s\n", file_name);
  80         dprint("-----------------------------------------\n\n");
  81 }
  82 
  83 
  84 /*
  85  * signal(SIGUSR1) handler
  86  */
  87 void
  88 handler(int signo)
  89 {
  90         dprint("got signal #%d\n", signo);
  91         signaled = 1;
  92 }
  93 
  94 /*
  95  * fill the buffer with random data
  96  * arguments:
  97  *      $1 : buffer used to contain data
  98  *      $2 : buffer size
  99  *      $3 : seed used to generate random data
 100  */
 101 void
 102 genBuffer(unsigned char *buff, int64_t size, unsigned int *write_seed)
 103 {
 104         int64_t index = 0;
 105         for (index = 0; index < size; index ++) {
 106                 buff[index] = (unsigned char)(rand_r(write_seed) % 256);
 107         }
 108 }
 109 
 110 
 111 /*
 112  * check data in buffer is correct or not
 113  * arguments:
 114  *      $1 : data buffer
 115  *      $2 : buffer size
 116  * return value:
 117  *      On sucess, return 0
 118  *      On error, return 1
 119  */
 120 int
 121 checkBuffer(unsigned char *buff, int64_t buff_size)
 122 {
 123         int index = 0;
 124         int ret = 0;
 125         unsigned char tmp;
 126 
 127         dprint("Started to check buffer data ... \n");
 128         for (index = 0; index < buff_size; index++) {
 129                 tmp = (unsigned char) (rand_r(&read_seed) % 256);
 130                 if (buff[index] != tmp) {
 131                         eprint("check buff failed at %d, expect: %c, \
 132                             real: %c \n", index, buff[index], tmp);
 133                         ret = 1;
 134                         break;
 135                 }
 136         }
 137 
 138         return (ret);
 139 }
 140 
 141 /*
 142  * lock or unlock file with exclusive lock
 143  * arguments:
 144  *      $1 : file descriptor
 145  *      $2 : indicates lock or unlock
 146  * return value:
 147  *      On sucess, return 0
 148  *      On error, return 1
 149  */
 150 int
 151 lockUnlockFile(int fd, int is_lock, short l_type, off64_t l_start, \
 152     off64_t l_len)
 153 {
 154         int ret = 0;
 155         struct flock lock_stat;
 156 
 157         lock_stat.l_whence = SEEK_SET;
 158         lock_stat.l_start = l_start;
 159         lock_stat.l_len = l_len;
 160 
 161         if (is_lock == 1) {
 162                 dprint("Started to lock file ...\n");
 163                 lock_stat.l_type = l_type;
 164                 if (fcntl(fd, (is_blockinglock == 1) ? F_SETLKW : F_SETLK, \
 165                     &lock_stat) < 0) {
 166                         eprint("failed to set lock(unavailable) on file: \
 167                             %s, %s\n", file_name, strerror(errno));
 168                         ret = 1;
 169                 } else {
 170                         print("got %s lock; sleeping...\n", \
 171                             (is_write == 1) ? "exclusive" : "shared");
 172 
 173                         sleep(sleep_sec);
 174                 }
 175         } else {
 176                 dprint("Started to unlock file ...\n");
 177                 lock_stat.l_type = F_UNLCK;
 178                 if (fcntl(fd, F_SETLKW, &lock_stat) < 0) {
 179                         eprint("failed to unlock file, %s, \
 180                             %s\n", file_name, strerror(errno));
 181                         ret = 1;
 182                 }
 183         }
 184 
 185         return (ret);
 186 }
 187 
 188 
 189 /*
 190  * file operator main function to handle file IO
 191  */
 192 int
 193 mainFunc()
 194 {
 195         int ret = 0;
 196         int fd = 0;
 197         int i = 0;
 198         unsigned char *buff = NULL;
 199         int64_t gotBytes = 0;
 200         off64_t truncOffset = 0;
 201 
 202         dprint("Started mainFunc() ...\n");
 203 
 204         /* register signal handler */
 205         signal(SIGUSR1, handler);
 206 
 207         /* open file */
 208         if ((fd = open(file_name, open_flag, open_mode)) < 0) {
 209                 eprint("failed to open file: %s, %s\n", file_name, \
 210                     strerror(errno));
 211                 ret = 1;
 212                 return (ret);
 213         }
 214 
 215         /* lock file */
 216         if (is_lock == 1) {
 217                 if ((ret = lockUnlockFile(fd, 1, lock_type, lock_init_offset, \
 218                     lock_range)) < 0) {
 219                         eprint("failed to lock file: %s, %s\n", file_name, \
 220                             strerror(errno));
 221                         ret = 1;
 222                         close(fd);
 223                         return (ret);
 224                 }
 225         }
 226 
 227         /* generate data  buffer */
 228         if ((buff = (unsigned char *)malloc(io_buff_size)) == NULL) {
 229                 eprint("failed to mallock %d size memory buff, %s\n", \
 230                     io_buff_size, strerror(errno));
 231                 close(fd);
 232                 ret = 1;
 233                 return (ret);
 234         }
 235 
 236         while (io_loop_count > 0) {
 237                 if (is_truncate == 1) {
 238                         io_init_offset = (off64_t)rand_r(&write_seed) \
 239                             % maxTruncSize;
 240                 }
 241 
 242                 /* lseek to init offset */
 243                 if (lseek64(fd, io_init_offset, SEEK_SET) != io_init_offset) {
 244                         eprint("failed to lseek to :%d\n", io_init_offset);
 245                         ret = 1;
 246                         break;
 247                 }
 248 
 249                 /* file IO untill the waitnumber */
 250                 dprint("Started to IO file till io_hold_num ...\n");
 251                 for (i = 0; i < io_hold_num; i++) {
 252                         if (is_write == 1) {
 253                                 genBuffer(buff, io_buff_size, &write_seed);
 254                                 if (nfsgenWrite(fd, buff, io_buff_size) != \
 255                                     io_buff_size) {
 256                                         eprint("failed to write data:%d, %s\n",\
 257                                             errno, strerror(errno));
 258                                         ret = 1;
 259                                         break;
 260                                 } else {
 261                                         /*
 262                                          * read back for check
 263                                          * if is_trucate set
 264                                          */
 265                                         if (is_truncate == 1) {
 266                                                 if (lseek64(fd, \
 267                                                     io_init_offset, \
 268                                                     SEEK_SET) != \
 269                                                     io_init_offset) {
 270                                                         eprint("failed to \
 271                                                             lseek to :%d\n", \
 272                                                             io_init_offset);
 273                                                         ret = 1;
 274                                                         break;
 275                                                 }
 276                                                 if ((gotBytes = nfsgenRead(fd, \
 277                                                     buff, io_buff_size)) != \
 278                                                     io_buff_size) {
 279                                                         eprint("failed to read \
 280                                                             data, exp: %d, \
 281                                                             real: %d \n", \
 282                                                             gotBytes, \
 283                                                             io_buff_size);
 284                                                         ret = 1;
 285                                                         break;
 286                                                 }
 287                                                 if (checkBuffer(buff, \
 288                                                     io_buff_size) \
 289                                                     != 0) {
 290                                                         ret = 1;
 291                                                         break;
 292                                                 }
 293                                         }
 294                                 }
 295                         } else {
 296                                 if ((gotBytes = nfsgenRead(fd, buff, \
 297                                     io_buff_size)) != io_buff_size) {
 298                                         eprint("failed to read data, exp: %d, \
 299                                             real: %d \n", gotBytes, \
 300                                             io_buff_size);
 301                                         ret = 1;
 302                                         break;
 303                                 }
 304                         }
 305                 }
 306 
 307                 if (ret != 0) {
 308                         break;
 309                 }
 310 
 311                 /* okay, truncate file */
 312                 if (is_truncate == 1) {
 313                         dprint("Started to truncate file ...\n");
 314                         if (ftruncate64(fd, (off64_t)rand_r(&write_seed) % \
 315                             maxTruncSize < 0)) {
 316                                 eprint("failed to truncate file to a random \
 317                                     size, %s", strerror(errno));
 318                                 ret = 1;
 319                                 break;
 320                         }
 321                 }
 322 
 323                 /* okay, I'm here, signal outside, I'm ready */
 324                 if (io_hold_num >= 0) {
 325                         print("I am ready, I_am_ready\n");
 326                 }
 327 
 328                 /* go to sleep, wait instruction from user */
 329                 if (io_hold_num >= 0) {
 330                         dprint("Started to wait the user signal comes from \
 331                             outsider ...\n");
 332                         while (signaled == 0) {
 333                                 yield();
 334                         }
 335                 }
 336 
 337                 if (signaled == 1) {
 338                         /* read back data for check */
 339                         print("signalled, read back data for check\n");
 340                         if (lseek(fd, io_init_offset, SEEK_SET) != \
 341                             io_init_offset) {
 342                                 eprint("failed to lseek to :%d\n", \
 343                                     io_init_offset);
 344                                 ret = 1;
 345                                 break;
 346                         }
 347 
 348                         /* read data */
 349                         for (i = 0; i < io_hold_num; i++) {
 350                                 if ((gotBytes = nfsgenRead(fd, buff, \
 351                                     io_buff_size)) != io_buff_size) {
 352                                         eprint("failed to read data, \
 353                                             exp: %d, real: %d \n", \
 354                                             gotBytes, io_buff_size);
 355                                         ret = 1;
 356                                         break;
 357                                 } else {
 358                                         if ((ret = checkBuffer(buff, \
 359                                             io_buff_size)) != 0) {
 360                                                 ret = 1;
 361                                                 break;
 362                                         }
 363                                 }
 364                         } /* end of for */
 365                         if (ret != 0) {
 366                                 break;
 367                         }
 368                 }
 369 
 370                 /* continue IO untill the waitnumber */
 371                 dprint("Started to finish the remaining IO ...\n");
 372                 for (; i < io_buff_num; i++) {
 373                         if (is_write == 1) {
 374                                 genBuffer(buff, io_buff_size, &write_seed);
 375                                 if (nfsgenWrite(fd, buff, io_buff_size) \
 376                                     != io_buff_size) {
 377                                         eprint("failed to write data: \
 378                                             %d, %s\n", errno, \
 379                                             strerror(errno));
 380                                         ret = 1;
 381                                         break;
 382                                 }
 383                         } else {
 384                                 if ((gotBytes = nfsgenRead(fd, buff, \
 385                                     io_buff_size)) != io_buff_size) {
 386                                         eprint("failed to read data, expect \
 387                                             %d, real got %d \n", \
 388                                             gotBytes, io_buff_size);
 389                                         ret = 1;
 390                                         break;
 391                                 }
 392                         }
 393                 } /* end of for */
 394 
 395                 if (ret != 0) {
 396                         break;
 397                 }
 398 
 399                 io_loop_count --;
 400         } /* end of while */
 401 
 402         /* unlock file */
 403         if ((ret == 0) && (is_unlock == 1)) {
 404                 if ((ret = lockUnlockFile(fd, 0, lock_type, lock_init_offset, \
 405                     lock_range)) < 0) {
 406                         eprint("failed to lock file: %s, %s\n", file_name, \
 407                             strerror(errno));
 408                         ret = 1;
 409                 }
 410         }
 411 
 412         /* return delegation type */
 413         if ((ret == 0) && (is_returndel == 1)) {
 414                 i = get_deleg(fd, file_name);
 415                 print("return_delegation_type=%d\n", i);
 416         }
 417 
 418         /* close file */
 419         if (is_closefile == 1) {
 420                 if (close(fd) < 0) {
 421                         eprint("failed to close file: %s, %s\n", file_name, \
 422                             strerror(errno));
 423                         ret = errno;
 424                 }
 425         }
 426 
 427         /* free data buff */
 428         free(buff);
 429 
 430 
 431         return (ret);
 432 }
 433 
 434 
 435 void
 436 usage(char *cmd)
 437 {
 438         printf("%s [options] filename\n", cmd);
 439         printf("options:\n");
 440         printf("\t -o open_flag     specify file open flag \n");
 441         printf("\t                  0: O_RDONLY \n");
 442         printf("\t                  1: O_WRONLY|O_CREAT \n");
 443         printf("\t                  2: O_WRONLY|O_APPEND \n");
 444         printf("\t                  3: O_WRONLY|O_TRUNC \n");
 445         printf("\t                  4: O_RDWR|O_CREAT \n");
 446         printf("\t                  5: O_RDWR|O_APPEND \n");
 447         printf("\t                  6: O_RDWR|O_TRUNC \n");
 448         printf("\t -m open_mode     specify file open mode, \n");
 449         printf("\t                  default to 0664 \n");
 450         printf("\t -L lock_type is_blocking offset range \n");
 451         printf("\t                  lock_type to 0 is read-lock, \n");
 452         printf("\t                  1 is write-lock \n");
 453         printf("\t -B buff_size buff_number hold_number \n");
 454         printf("\t                  specify buffer size, buffer number \n");
 455         printf("\t                  and where IO should be held and wait \n");
 456         printf("\t                  signal comes from outside user \n");
 457         printf("\t -e seed          specify seed to generate \n");
 458         printf("\t                  random data \n");
 459         printf("\t -s sleep_seconds specify sleep seconds \n");
 460         printf("\t -i offset        specify IO initial offset \n");
 461         printf("\t -l count         specify loop count \n");
 462         printf("\t -t maxTruncSize  specify max random truancate size in \n");
 463         printf("\t                  each loop iteration, but user cannot \n");
 464         printf("\t                  specify -t along with hold_number >= 0 \n");
 465         printf("\t                  in -B option \n");
 466         printf("\t -R               read data from file \n");
 467         printf("\t -W               write data into file \n");
 468         printf("\t -c               close file at end \n");
 469         printf("\t -d               return delegation type as return code \n");
 470         printf("\t                  at end \n");
 471         printf("\t -u               unlock file at end \n");
 472         printf("\t -D               trun on debug infomation \n");
 473         printf("\t -h               show this help information \n");
 474 }
 475 
 476 char
 477 *removePrefixBlank(char *src)
 478 {
 479         char *ret = src;
 480         while (*ret == ' ') {
 481                 ret ++; }
 482 
 483         return (ret);
 484 }
 485 
 486 int
 487 main(int argc, char *argv[])
 488 {
 489         int c = 0;
 490         int ret = 0;
 491         int tmp = 0;
 492         char *poptarg = NULL;
 493         char *envBuff = NULL;
 494 
 495         if (argc < 2) {
 496                 usage(argv[0]);
 497                 return (1);
 498         }
 499         while ((c = getopt(argc, argv, "o:m:L:B:e:s:i:l:t:RWcduDh")) != -1) {
 500                 switch (c) {
 501                         case 'o':
 502                                 tmp = strtol(optarg, NULL, 0);
 503                                 switch (tmp) {
 504                                         case 0:
 505                                                 open_flag = O_RDONLY;
 506                                                 break;
 507                                         case 1:
 508                                                 open_flag = O_WRONLY|O_CREAT;
 509                                                 break;
 510                                         case 2:
 511                                                 open_flag = \
 512                                                     O_WRONLY|O_APPEND|O_CREAT;
 513                                                 break;
 514                                         case 3:
 515                                                 open_flag = \
 516                                                     O_WRONLY|O_TRUNC|O_CREAT;
 517                                                 break;
 518                                         case 4:
 519                                                 open_flag = \
 520                                                     O_RDWR|O_CREAT|O_CREAT;
 521                                                 break;
 522                                         case 5:
 523                                                 open_flag = \
 524                                                     O_RDWR|O_APPEND|O_CREAT;
 525                                                 break;
 526                                         case 6:
 527                                                 open_flag = \
 528                                                     O_RDWR|O_TRUNC|O_CREAT;
 529                                                 break;
 530                                         case 7:
 531                                                 open_flag = O_WRONLY;
 532                                                 break;
 533                                         default:
 534                                                 print("Invalid open flag \
 535                                                     parameter\n");
 536                                                 usage(argv[0]);
 537                                                 return (1);
 538                                 }
 539                                 break;
 540                         case 'm':
 541                                 open_mode = (mode_t)strtol(optarg, NULL, 0);
 542                                 break;
 543                         case 'L':
 544                                 is_lock = 1;
 545                                 poptarg = (char *)optarg;
 546                                 tmp = strtol(optarg, NULL, 0);
 547                                 poptarg = \
 548                                     strstr(removePrefixBlank(poptarg), " ");
 549                                 is_blockinglock = strtol(poptarg, NULL, 0);
 550                                 poptarg = \
 551                                     strstr(removePrefixBlank(poptarg), " ");
 552                                 lock_init_offset = \
 553                                     (off64_t)strtol(poptarg, NULL, 0);
 554                                 poptarg = \
 555                                     strstr(removePrefixBlank(poptarg), " ");
 556                                 lock_range = (off64_t)strtol(poptarg, NULL, 0);
 557                                 switch (tmp) {
 558                                         case 0:
 559                                                 lock_type = F_RDLCK;
 560                                                 break;
 561                                         case 1:
 562                                                 lock_type = F_WRLCK;
 563                                                 break;
 564                                         default:
 565                                                 print("Invalid lock \
 566                                                     parameter\n");
 567                                                 usage(argv[0]);
 568                                                 return (1);
 569                                 }
 570                                 break;
 571                         case 'B':
 572                                 poptarg = (char *)optarg;
 573                                 io_buff_size = \
 574                                     (int64_t)strtol(poptarg, NULL, 0);
 575                                 poptarg = \
 576                                     strstr(removePrefixBlank(poptarg), " ");
 577                                 io_buff_num = (int64_t)strtol(poptarg, NULL, 0);
 578                                 poptarg = \
 579                                     strstr(removePrefixBlank(poptarg), " ");
 580                                 io_hold_num = (int64_t)strtol(poptarg, NULL, 0);
 581                                 break;
 582                         case 'e':
 583                                 write_seed = (unsigned int)strtol(optarg, \
 584                                     NULL, 0);
 585                                 read_seed = write_seed;
 586                                 break;
 587                         case 's':
 588                                 sleep_sec = (unsigned int)strtol(optarg, \
 589                                     NULL, 0);
 590                                 break;
 591                         case 'i':
 592                                 io_init_offset = (int64_t)strtol(optarg, \
 593                                     NULL, 0);
 594                                 break;
 595                         case 'l':
 596                                 io_loop_count = (int64_t)strtol(optarg, \
 597                                     NULL, 0);
 598                                 break;
 599                         case 't':
 600                                 is_truncate = 1;
 601                                 maxTruncSize = (int64_t)strtol(optarg, NULL, 0);
 602                                 break;
 603                         case 'R':
 604                                 is_read = 1;
 605                                 break;
 606                         case 'W':
 607                                 is_write = 1;
 608                                 break;
 609                         case 'c':
 610                                 is_closefile = 1;
 611                                 break;
 612                         case 'd':
 613                                 is_returndel = 1;
 614                                 break;
 615                         case 'u':
 616                                 is_unlock = 1;
 617                                 break;
 618                         case 'D':
 619                                 debug = 1;
 620                                 break;
 621                         case 'h':
 622                                 usage(argv[0]);
 623                                 break;
 624                         default:
 625                                 usage(argv[0]);
 626                                 return (1);
 627                 }
 628         }
 629 
 630         /* get filename */
 631         file_name = argv[optind];
 632         if (file_name == NULL) {
 633                 print("no file_name specified\n");
 634                 usage(argv[0]);
 635                 return (1);
 636         }
 637 
 638         /* check for read and write */
 639         if (((is_read == 1) && (is_write == 1)) || \
 640             ((is_read == 0) && (is_write == 0))) {
 641                 print("User need to speicfy at least one of -R and -W option, \
 642                     -R and -W are exclusive options\n");
 643                 usage(argv[0]);
 644                 return (1);
 645         }
 646 
 647         /* check -t and hold_number in -B option */
 648         if ((is_truncate == 1) && (io_hold_num >= 0)) {
 649                 print("Limitation: user cannot specify -t and hold_num \
 650                     large than -1 at the same time \n");
 651                 usage(argv[0]);
 652                 return (1);
 653         }
 654 
 655         /* check FILE_OPERATOR_DEBUG in case of user didn't specify -D option */
 656         if (debug == 0) {
 657                 if ((envBuff = getenv("FILE_OPERATOR_DEBUG")) != NULL) {
 658                         if (strcasecmp(envBuff, "ON") == 0) {
 659                                 debug = 1;
 660                         }
 661                 }
 662         }
 663 
 664         /*
 665          * file_operator default to print out error info unless user
 666          * specified env SHOWERROR=OFF
 667          */
 668         showerror = 1;
 669         if ((envBuff = getenv("SHOWERROR")) != NULL) {
 670                 if (strcasecmp(envBuff, "OFF") == 0) {
 671                         showerror = 0;
 672                 }
 673         }
 674 
 675 
 676         fileOperatorDump();
 677 
 678         /* okay, go to the mainFunc */
 679         if ((ret = mainFunc()) == 0) {
 680                 print("completed successfully!\n");
 681         }
 682 
 683         return (ret);
 684 }