/*
 * pcreatedelete.c
 *
 * Test drive create/delete by creating and deleting many objects,
 * and verifying contents of list-of-objects-object
 *
 * Author: Jason Grosman
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>
#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_pdrive_client.h>
#include <nasd/nasd_pdrive_client_kpdev.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_security.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_getopt.h>
#include <nasd/nasd_types_marshall.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int do_delete(nasd_identifier_t nasdid);

nasd_error_string_t err_str;

#define OBJ_BUF_LEN 10

int  Verbose = 0;
int  Dirty = 0;
int  NumberObjs;
int  Filled = 0;

int randomize_deletions = 0;
int npasses             = 1;
int disable_pass_checks = 0;
int flush_before_delete = 0;
int sync_between_passes = 0;

nasd_error_string_t error_text; 
nasd_uint16 protection;         
nasd_drive_handle_t    h;       
nasd_identifier_t      nasdid;  
char                  *server_name;
int                    partnum;  
nasd_rpc_status_t      status;   
nasd_status_t          rc;       
nasd_sec_keyring_t     keys;

int                       binding_type;
int                       binding_args_len;
void                     *binding_args;
char                     *binding_port = NASD_PDRIVE_PORT;
nasd_drive_param_kpdev_t  kpdev_args;
int                       nondefault_binding = 0;


char *master_password; 
char * progname;



void
usage()
{
  int i;
  fprintf(stderr, "USAGE: %s [options] servername partnum master_password\n", progname);
  fflush(stderr); fprintf(stderr, "Options:\n");
  fprintf(stderr, "  -D Leave partition dirty. (Don't delete objects created)\n");
  fprintf(stderr, "  -d number of deletions(>=0). (default : random)\n");
  fprintf(stderr, "  -e randomize deletions\n");
  fprintf(stderr, "  -f Running on a non-empty file-system\n");
  fprintf(stderr, "  -F flush objects before deleting\n");
  fprintf(stderr, "  -k use kernel device\n");
  fprintf(stderr, "  -l use colocated drive\n");
  fprintf(stderr, "  -n number of objects to create (default : 20)\n");
  fprintf(stderr, "  -p number of passes\n");
  fprintf(stderr, "  -P disable per-pass checks\n");
  fprintf(stderr, "  -R run Regression test. (multiple passes of creates/deletes)\n");
  fprintf(stderr, "  -r random_seed (default: getpid())\n");
  fprintf(stderr, "  -s sec_level\n");
  fprintf(stderr, "  where sec_level is one of\n");
  for(i = 0; i <= NASD_MAX_SECURITY_LEVEL; i++) {
    fprintf(stderr, "     %d %s\n", i, nasd_sec_level_string(i));
  }
  fprintf(stderr, "  -S sync between passes\n");
#if NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_DCE
  fprintf(stderr, "  -T use DCE-TCP\n");
#endif /* NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_DCE */
  fprintf(stderr, "  -v Verbose mode \n");
  exit(1);
}

void endgame(nasd_identifier_t *array, int Num)
{
int i;
 if (!Dirty) {
 printf("Deleting objects created by this test.\n");
 for (i=0;i<Num;i++)
   {
     if (array[i] == NASDID_NULL) continue;
     do_delete(array[i]);
   }
 }
}

nasd_identifier_t
do_create()
{
  nasd_security_param_t sec_param;
  nasd_p_create_dr_args_t args;
  nasd_p_create_dr_res_t res;
  nasd_attribute_t *ap;

  sec_param.type = NASD_BLACK_KEY;
  sec_param.partnum = partnum;
  sec_param.actual_protection = protection;

  bzero(&args,sizeof(nasd_p_create_dr_args_t));
  args.in_partnum = partnum;
 
  ap = &args.in_attribute;
  ap->object_len = 3000;
  /* Testing standard AV */ 

  args.in_attribute.av=7;
  args.in_fieldmask = (NASD_ATTR_OBJECT_LEN | NASD_ATTR_AV);
  nasd_cl_p_create_dr(h, keys.black_key, &sec_param, NULL, &args,
    &res, &status); 

  if (status) {
    fprintf(stderr, "ERROR: status=0x%x (%s) nasd_status=0x%x (%s)\n",
      status, nasd_cl_error_string(h, status, error_text),
      res.nasd_status, nasd_error_string(res.nasd_status));
    fflush(stderr);
    exit(2);
  }

  if (res.nasd_status) {
    fprintf(stderr, "NASD ERROR: 0x%x (%s)\n", res.nasd_status,
      nasd_error_string(res.nasd_status));
    fflush(stderr);
    exit(2);
  }
 nasdid = res.out_identifier;

 if (Verbose) printf("New object identifier 0x%" NASD_ID_FMT "\n", nasdid);
  return nasdid; 
}


int
do_delete(nasd_identifier_t nasdid)
{
  nasd_security_param_t sec_param;
  nasd_p_remove_dr_args_t args;
  nasd_p_remove_dr_res_t res;
  nasd_p_flush_obj_dr_args_t fl_args;
  nasd_p_flush_obj_dr_res_t fl_res;
  nasd_timespec_t tm;
  nasd_cookie_t cookie;

  /* build the capability -- ordinarily the file manager would do this */
  nasd_drive_handle_get_time(h, &tm);
  tm.ts_sec += (60*60);
  nasd_sec_build_capability(partnum, nasdid,
    (NASD_ACCESS_RIGHTS_FLUSH | NASD_ACCESS_RIGHTS_REMOVE), 0, tm.ts_sec,
    protection, NASD_BLACK_CAPABILITY, 0, 0, 7, keys.black_key, &cookie);

  sec_param.type = NASD_BLACK_CAPABILITY;
  sec_param.partnum = partnum;
  sec_param.actual_protection = protection;

  if (flush_before_delete) {
    bzero(&fl_args, sizeof(fl_args));
    fl_args.in_identifier = nasdid;
    fl_args.in_partnum = partnum;
    nasd_cl_p_flush_obj_dr(h, cookie.key, &sec_param,
      &cookie.capability, &fl_args,
      &fl_res, &status);
    if (fl_res.nasd_status || status) {
      fprintf(stderr, "WARNING: got nasd_status 0x%x (%s) status 0x%x (%s) flushing 0x%" NASD_ID_FMT "\n",
        fl_res.nasd_status, nasd_error_string(fl_res.nasd_status),
        status, nasd_cl_error_string(h, status, error_text),
        nasdid);
      fflush(stderr);
    }
  }

  bzero(&args, sizeof(args)); 
  args.in_partnum = partnum;
  args.in_identifier = nasdid;

  nasd_cl_p_remove_dr(h, cookie.key, &sec_param, &cookie.capability, &args,
    &res, &status); 

  if (res.nasd_status || status) {
    fprintf(stderr, "nasd_status=0x%x (%s) status=0x%x (%s)\n",
      res.nasd_status, nasd_error_string(res.nasd_status),
      status, nasd_cl_error_string(h, status, error_text));
    return 1;
  }

  
  if (Verbose)  printf("Deleted identifier 0x%" NASD_ID_FMT "\n", nasdid);
  return 0 ;
}


int act_vs_exp(nasd_identifier_t *array, int Num)
{
  nasd_identifier_otw_t objs_otw[OBJ_BUF_LEN];
  nasd_identifier_t objs[OBJ_BUF_LEN];
  nasd_security_param_t sec_param;
  nasd_p_smpl_op_dr_args_t rd_args;
  nasd_p_fastread_dr_res_t rd_res;
  nasd_ctrl_part_info_t ptinfo;
  nasd_timespec_t tm;
  nasd_offset_t off;
  nasd_len_t len;
  int i,j;
  nasd_cookie_t cookie;

  sec_param.type = NASD_BLACK_CAPABILITY;
  sec_param.partnum = partnum;
  sec_param.actual_protection = protection;

  /* build the capability -- ordinarily the file manager would do this */
  nasd_drive_handle_get_time(h, &tm);
  tm.ts_sec += (60*60);
  nasd_sec_build_capability(partnum,
    (nasd_identifier_t) NASD_CTRL_PART_INFO, NASD_ACCESS_RIGHTS_READ,
    0, tm.ts_sec,
    protection, NASD_BLACK_CAPABILITY, 0, 0, 0, keys.black_key, &cookie);

  rc = nasd_cl_p_ctrl_get_part_info(h, cookie.key, &sec_param,
    &cookie.capability, partnum, &ptinfo);
  if (rc) {
    fprintf(stderr, "ERROR: got 0x%x (%s) from nasd_cl_p_get_part_info\n",
      rc, nasd_error_string(rc));
    fflush(stderr);
    exit(1);
  }

  off = 0;
  do {
    nasd_sec_build_capability(partnum,
      (nasd_identifier_t) NASD_CTRL_PART_OBJS,
      NASD_ACCESS_RIGHTS_READ,
      0, tm.ts_sec,
      protection, NASD_BLACK_CAPABILITY, off,
      off+sizeof(objs_otw), 0, keys.black_key, &cookie);

    rd_args.in_partnum = partnum;
    rd_args.in_identifier = (nasd_identifier_t)NASD_CTRL_PART_OBJS;
    rd_args.in_offset = off;
    rd_args.in_len = sizeof(objs_otw);
    nasd_cl_p_read2_simple_dr(h, cookie.key, &sec_param, &cookie.capability,
      &rd_args, objs_otw, &rd_res, &status);
    len = rd_res.out_datalen; 
    if (status || rd_res.nasd_status) {
      fprintf(stderr,
        "Error issuing read, off=%" NASD_64s_FMT
        " status=0x%x (%s) nasd_status=0x%x (%s)\n",
        off, status, nasd_cl_error_string(h, status, err_str),
        rd_res.nasd_status, nasd_error_string(rd_res.nasd_status));
      fflush(stderr);
      exit(2);
    }
    for(i=0;i<len/sizeof(nasd_identifier_t);i++) {
      nasd_identifier_t_unmarshall(objs_otw[i], &objs[i]);
    }
    for(i=0;i<len/sizeof(nasd_identifier_t);i++) {
      if (Verbose)
        printf("Searching for 0x%" NASD_ID_FMT "\n", objs[i]);

      if (objs[i] == ptinfo.first_obj)
        continue;

      for (j=0;j<Num;j++){
        if (array[j] == objs[i]) {
          if (Verbose)
            printf("found  0x%" NASD_ID_FMT "\n", objs[i]);
          break;
        }
      }

      if (j == Num) {
        fprintf(stderr, "Test Failed\n");
        fprintf(stderr, "There was a NASD object in the partition that was "
          "not the root object or created by this test.\n");
        fprintf(stderr, "Offending  object : 0x%" NASD_ID_FMT "\n", objs[i]);
        endgame(array, Num);
        exit(2);
      }
    }
    off += len;
  } while(len);

  printf("Success : All objects in partition accounted for.\n");
  return 0;
}

int exp_vs_act(nasd_identifier_t nasdid)
{
  nasd_identifier_otw_t objs_otw[OBJ_BUF_LEN];
  nasd_identifier_t objs[OBJ_BUF_LEN];
  nasd_security_param_t sec_param;
  nasd_p_smpl_op_dr_args_t rd_args;
  nasd_p_fastread_dr_res_t rd_res;
  nasd_error_string_t err_str;
  nasd_timespec_t tm;
  nasd_offset_t off;
  nasd_len_t len;
  int i;
  nasd_cookie_t cookie;

  sec_param.type = NASD_BLACK_CAPABILITY;
  sec_param.partnum = partnum;
  sec_param.actual_protection = protection;

  off = 0;
  do {
    nasd_sec_build_capability(partnum,
      (nasd_identifier_t) NASD_CTRL_PART_OBJS,
      NASD_ACCESS_RIGHTS_READ,
      0, tm.ts_sec,
      protection, NASD_BLACK_CAPABILITY, off,
      off+sizeof(objs_otw), 0, keys.black_key, &cookie);

    rd_args.in_partnum = partnum;
    rd_args.in_identifier = (nasd_identifier_t)NASD_CTRL_PART_OBJS;
    rd_args.in_offset = off;
    rd_args.in_len = sizeof(objs_otw);
    nasd_cl_p_read2_simple_dr(h, keys.part_key, &sec_param, NULL,
      &rd_args, objs_otw, &rd_res, &status);
    len = rd_res.out_datalen;
    if (status || rd_res.nasd_status) {
      fprintf(stderr,
        "Error issuing read, off=%"NASD_64s_FMT" status=0x%x (%s) nasd_status=0x%x (%s)\n",
        off, status, nasd_cl_error_string(h, status, err_str),
        rd_res.nasd_status, nasd_error_string(rd_res.nasd_status));
      fflush(stderr);
      exit(2);
    }
    for(i=0;i<len/sizeof(nasd_identifier_t);i++) {
      nasd_identifier_t_unmarshall(objs_otw[i], &objs[i]);
    }
    for(i=0;i<len/sizeof(nasd_identifier_t);i++) {
      if (objs[i] == nasdid) {
        if (Verbose)
          printf("Found 0x%" NASD_ID_FMT "\n", nasdid);
        return 0;
      }
    }
    off += len;
  } while(len);
  
  return -1;
}



void do_checks(
  nasd_identifier_t  *array,
  int                 Num)
{
  int nobjs, len, obj_buf_len, i, j, real_count;
  nasd_identifier_otw_t *ids_in_drive_otw;
  nasd_p_getattr_dr_args_t ga_args;
  nasd_p_smpl_op_dr_args_t rd_args;
  nasd_p_fastread_dr_res_t rd_res;
  nasd_identifier_t *ids_in_drive;
  nasd_p_getattr_dr_res_t ga_res;
  nasd_rpc_status_t status;
  nasd_security_param_t sec_param;
  nasd_cookie_t cookie;
  nasd_timespec_t tm;

  real_count = 0;
  for(i=0;i<Num;i++) {
    if (array[i] == NASDID_NULL)
      continue;
    real_count++;
  }

  if (!Filled) {
    printf("Checking...\n");
    act_vs_exp(array, Num);
  }

  printf("Checking...\n");

  bzero((char *)&ga_args, sizeof(ga_args));

  /* build the capability -- ordinarily the file manager would do this */
  nasd_drive_handle_get_time(h, &tm);
  tm.ts_sec += (60*60);
  nasd_sec_build_capability(partnum,
    (nasd_identifier_t)NASD_CTRL_PART_OBJS,
    (NASD_ACCESS_RIGHTS_GETATTR | NASD_ACCESS_RIGHTS_READ), 0, tm.ts_sec,
    protection, NASD_BLACK_CAPABILITY, 0, 0, 0, keys.black_key, &cookie);

  sec_param.type = NASD_BLACK_CAPABILITY;
  sec_param.partnum = partnum;
  sec_param.actual_protection = protection;

  ga_args.in_partnum = partnum;
  ga_args.in_identifier = (nasd_identifier_t)NASD_CTRL_PART_OBJS;

  nasd_cl_p_getattr_dr(h, cookie.key, &sec_param, &cookie.capability,
    &ga_args, &ga_res, &status);

  if (status || ga_res.nasd_status) {
    fprintf(stderr, "ERROR: could not get attributes for "
      "list-of-objects-object nasd_status 0x%x (%s) "
      "status 0x%x (%s)\n",
      ga_res.nasd_status, nasd_error_string(ga_res.nasd_status),
      status, nasd_cl_error_string(h, status, error_text));
    endgame(array, Num);
    exit(2);
  }

  len = ga_res.out_attribute.object_len;
  nobjs = len / sizeof(nasd_identifier_t);
  obj_buf_len = nobjs * sizeof(nasd_identifier_t);

  if (obj_buf_len != len) {
    fprintf(stderr, "Test failed! Nonsensical list-of-objects-object "
      "length %d\n", len);
    endgame(array, Num);
    exit(2);
  }

  if (!Filled) {
    if ((real_count + 1) != nobjs) {
      fprintf(stderr, "Test failed! Expected %d objects, "
        "attribute claims %d\n",
        real_count+1, nobjs);
      endgame(array, Num);
      exit(2);
    }
  }

  NASD_Malloc(ids_in_drive, obj_buf_len, (nasd_identifier_t *));
  if (ids_in_drive == NULL) {
    fprintf(stderr, "ERROR: could not allocate ids array for %d ids\n", nobjs);
    endgame(array, Num);
    exit(2);
  }
  NASD_Malloc(ids_in_drive_otw, obj_buf_len, (nasd_identifier_otw_t *));
  if (ids_in_drive_otw == NULL) {
    fprintf(stderr, "ERROR: could not allocate ids array for %d ids\n", nobjs);
    NASD_Free(ids_in_drive, obj_buf_len);
    endgame(array, Num);
    exit(2);
  }

  rd_args.in_partnum = partnum;
  rd_args.in_identifier = (nasd_identifier_t)NASD_CTRL_PART_OBJS;
  rd_args.in_offset = 0;
  rd_args.in_len = obj_buf_len;

  nasd_cl_p_read2_simple_dr(h, cookie.key, &sec_param, &cookie.capability,
    &rd_args, ids_in_drive_otw,
    &rd_res, &status);

  if (status || rd_res.nasd_status) {
    fprintf(stderr,
      "Error issuing read, status=0x%x (%s) nasd_status=0x%x (%s)\n",
      status, nasd_cl_error_string(h, status, err_str),
      rd_res.nasd_status, nasd_error_string(rd_res.nasd_status));
    endgame(array, Num);
    exit(2);
  }

  if (rd_res.out_datalen != obj_buf_len) {
    fprintf(stderr, "Error reading list-of-objects object\n");
    fprintf(stderr, "   got %d bytes, wanted %d\n",
      (int)rd_res.out_datalen, obj_buf_len);
    endgame(array, Num);
    exit(2);
  }

  for(i=0;i<rd_res.out_datalen/sizeof(nasd_identifier_t);i++) {
    nasd_identifier_t_unmarshall(ids_in_drive_otw[i], &ids_in_drive[i]);
  }

  for(i=0;i<Num;i++) {
    if (array[i] == NASDID_NULL)
      continue;
    for(j=0;j<nobjs;j++) {
      if (ids_in_drive[j] == array[i])
        break;
    }
    if (j == nobjs) {
      fprintf(stderr, "Test Failed : An object created by this test was not "
        "found in the partition\n");
      fprintf(stderr, "Offending Object :  0x%" NASD_ID_FMT "\n", array[i]);
      endgame(array, Num);
      exit(2);
    }
  }

  NASD_Free(ids_in_drive, obj_buf_len);
}


void
do_regress ()
{
  int num,i,j,place;
  nasd_identifier_t * array;
  nasd_status_t rc;

  j= 0;

  /*init array*/ 
  NASD_Malloc(array, sizeof(nasd_identifier_t) * 200, (nasd_identifier_t *));
  for (i = 0;i<150;i++)
    array[i] = NASDID_NULL;
  
  
  /*pass one*/
  printf ("Pass One.\n");
  num = rand()%20 +  80;
  if (Verbose) printf("Creating %d objects.\n",num);

  for (i = 0;i<num;i++) {
    array[j] = do_create();
    j++;
  }
  
  do_checks(array,j);
  
  num = rand()%10 + 10;
  if (Verbose) printf("Deleting %d objects.\n",num);
  
  for(i=0;i<num;i++) {
    do {
      place = rand()%j;
    } while (!array[place]);
    do_delete(array[place]);
    array[place] = NASDID_NULL;
  }

  do_checks(array, j);

  /*pass two*/
  printf ("Pass Two.\n");
  num = rand()%10 +  20;
  if (Verbose) printf("Creating %d objects.\n",num);
  
  for (i = 0;i<num;i++) {
    array[j] = do_create();
    j++;
  }
  
  do_checks(array, j);
  
  num = rand()%10 + 30;
    if (Verbose) printf("Deleting %d objects.\n",num);
  
  for(i=0;i<num;i++){
    do {
      place = rand()%j;
    } while (!array[place]);
    do_delete(array[place]);
    array[place] = NASDID_NULL;
  }

  do_checks(array, j);

  /*pass three*/
  printf ("Pass Three.\n");
  num = rand()%10 +  10;
  if (Verbose) printf("Creating %d objects.\n",num);

  for (i = 0;i<num;i++) {
    array[j] = do_create();
    j++;
  }
  
  do_checks(array, j);
  
  num = rand()%10 + 10;
  if (Verbose) printf("Deleting %d objects.\n",num);
  
  for(i=0;i<num;i++){
    do {
      place = rand()%j;
    } while (!array[place]);
    do_delete(array[place]);
    array[place] = NASDID_NULL;
  }

  do_checks(array, j);
  
  /*pass four*/
  printf ("Pass Four.\n");

  num = rand()%10 +  10;
  if (Verbose) printf("Creating %d objects.\n",num);
  
  for (i = 0;i<num;i++) {
    array[j] = do_create();
    j++;
  }
  
  do_checks(array, j);
  
  num = rand()%5 + 5;
  if (Verbose) printf("Deleting %d objects.\n",num);
  
  for(i=0;i<num;i++){
    do {
      place = rand()%j;
    } while (!array[place]);
    do_delete(array[place]);
    array[place] = NASDID_NULL;
  }

  do_checks(array, j);

  endgame(array, j);

  NASD_Free(array, sizeof(nasd_identifier_t) * 200);

  rc = nasd_unbind_drive(&h);
  if (rc) {
    fprintf(stderr, "ERROR: got 0x%x (%s) from nasd_unbind_drive()\n",
      rc, nasd_error_string(rc));
    fflush(stderr);
    exit(2);
  }

  nasd_cl_p_shutdown();

  printf("Regression test successfully completed.\n");
  exit(0);
}


void
do_sync()
{
  nasd_rpc_status_t status;
  nasd_status_t rc;

  nasd_cl_p_sync_dr(h, &rc, &status);

  if (status || rc) {
    fprintf(stderr, "ERROR: nasd_cl_p_sync_dr status=0x%x (%s) nasd_status=0x%x (%s)\n",
      status, nasd_cl_error_string(h, status, error_text),
      rc, nasd_error_string(rc));
    fflush(stderr);
    exit(2);
  }
}




int
main (int argc, char **argv)
{
  
  char c;
  int i,numToDel,numOfDel = -1, pass;
  int Regress = 0, array2cnt, array1cnt, arraytmpcnt, j;
  int seed;
  nasd_identifier_t *array, *array2, *array_tmp;
  int sec_level = 0;

  seed = getpid();
  NumberObjs = 20; /*default*/

  progname = argv[0];

  binding_type = NASD_BIND_DEFAULT;
  binding_args = NULL;
  binding_args_len = 0;

  while (nasd_getopt(argc, argv, "Dd:efFkln:p:PRr:s:STv", &c)) {
    switch(c) {
    case 'e':
      randomize_deletions = 1;
      break;
    case 'S':
      sync_between_passes = 1;
      break;
    case 'F':
      flush_before_delete = 1;
      break;
    case 'P':
      disable_pass_checks = 1;
      break;
    case 'v':
      Verbose = 1;
      break;
    case 'f':
      Filled = 1;
      break;
    case 'n':
      if (sscanf(nasd_optarg, "%d", &NumberObjs) != 1) {
        usage();
      }
      break; 
    case 'p':
      if (sscanf(nasd_optarg, "%d", &npasses) != 1) {
        usage();
      }
      break; 
    case 'k':
      if (nondefault_binding)
        usage();
      nondefault_binding = 1;
      binding_type = NASD_BIND_KPDEV_DEFAULT;
      binding_args = &kpdev_args;
      binding_args_len = sizeof(kpdev_args);
      strcpy(kpdev_args.devname, "/dev/nasdkp0");
      break;
    case 'l':
      if (nondefault_binding)
        usage();
      nondefault_binding = 1;
      binding_type = NASD_BIND_COLOCATE;
      binding_args = &kpdev_args;
      binding_args_len = sizeof(kpdev_args);
      strcpy(kpdev_args.devname, "/dev/nasdkp0");
      break;
    case 's':
      sec_level = atoi(nasd_optarg);
      break;
    case 'd' :
      if (sscanf(nasd_optarg, "%d", &numOfDel) != 1) {
        usage();
      }
      if (numOfDel < 0) {
        usage();
      }
      break;
    case 'D':
      Dirty = 1;
      break;
    case 'R':
      Regress = 1;
      break;
    case 'r':
      seed = atoi(nasd_optarg);
      break;
#if NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_DCE
    case 'T':
      if (nondefault_binding)
        usage();
      nondefault_binding = 1;
      binding_type = NASD_BIND_DCE_DIRECT_TCP;
      break;
#endif /* NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_DCE */
    default:
      fprintf(stderr, "Unknown option '%c'\n", nasd_optopt);
      usage();
    }
  }
  
  if (nasd_optind >= argc)
    usage();
  
  server_name = argv[nasd_optind];

  nasd_optind++;
  if (nasd_optind >= argc)
    usage();

  if (sscanf(argv[nasd_optind], "%d", &partnum) != 1)
    usage();

  nasd_optind++;
  if (nasd_optind >= argc)
    usage();

  master_password=argv[nasd_optind];

  rc = nasd_sec_seclevel_to_protection(sec_level, &protection);
  if(rc) {
    fprintf(stderr, "ERROR: invalid security level %d\n", sec_level);
    usage();
  }

  printf("Security level %d, protection 0x%x\n", sec_level, protection);

  nasd_sec_password_to_keys(master_password, partnum, &keys);

  rc = nasd_cl_p_init(); 
  if (rc) {
    printf("ERROR (%s:%d): cannot init client library, rc=%ld\n",
      __FILE__, __LINE__, (long)rc);
    return(rc);
  }

  rc = nasd_bind_to_drive(server_name, binding_port,
    binding_type,binding_args,binding_args_len, &h); 
  
  if (rc) { 
    fprintf(stderr, "ERROR: cannot bind to server %s\n", server_name);
    fflush(stderr);
    return 1;
  }


  printf("Random Seed is %d\n",seed);
  srand(seed);

  if (Regress) 
    do_regress(); /* Instead of doing the standard tests, switch to regrssion
                     test mode.*/

  NASD_Malloc(array, NumberObjs * sizeof(nasd_identifier_t), (nasd_identifier_t *));

 array2 = NULL;
 array2cnt = 0;
 for(pass=0;pass<npasses;pass++) {
  printf("Creating %d NASD objects in partition %d pass %d.\n",NumberObjs,partnum,pass);
  array1cnt = 0;
  for (i=0;i<NumberObjs;i++)
    {
      array[i] = do_create();
      if (array[i] != NASDID_NULL)
        array1cnt++;
    }


  if (numOfDel == -1) {
    numOfDel = (rand() % (NumberObjs-1)) + 1;
  }

  printf("Number of deletions : %d\n",numOfDel);
  if (numOfDel > 0) {
    for (i=0;i<numOfDel;i++) {
      if (randomize_deletions)
        numToDel = rand() % (NumberObjs);
      else
        numToDel = i;
      if (array[numToDel] == NASDID_NULL)
        continue;
      if (Verbose)
        printf("Deleting : array# : %d, ID :0x%" NASD_ID_FMT "\n",numToDel, array[numToDel]);
      do_delete(array[numToDel]);
      array[numToDel] = NASDID_NULL;
      array1cnt--;
    }
  }

  if (array2) {
    arraytmpcnt = array1cnt + array2cnt;
    NASD_Malloc(array_tmp, arraytmpcnt * sizeof(nasd_identifier_t),
      (nasd_identifier_t *));
    for(i=0;i<array2cnt;i++) {
      array_tmp[i] = array2[i];
    }
    NASD_Free(array2, array2cnt * sizeof(nasd_identifier_t));
  }
  else {
    array2cnt = 0;
    arraytmpcnt = array1cnt;
    NASD_Malloc(array_tmp, arraytmpcnt * sizeof(nasd_identifier_t),
      (nasd_identifier_t *));
  }
  for(i=j=0;i<NumberObjs;i++) {
    if (array[i] != NASDID_NULL) {
      array_tmp[j+array2cnt] = array[i];
      j++;
    }
  }
  array2 = array_tmp;
  array2cnt = arraytmpcnt;

  if (disable_pass_checks == 0) {    
    do_checks(array2, array2cnt);
  }
  printf("Done pass %d\n", pass);

  if (sync_between_passes) {
    do_sync();
  }
 }

  if (disable_pass_checks) {
    do_checks(array2, array2cnt);
  }
  endgame(array2, array2cnt);

  if (array2) {
    NASD_Free(array2, array2cnt * sizeof(nasd_identifier_t));
  }
  NASD_Free(array, NumberObjs * sizeof(nasd_identifier_t));

  rc = nasd_unbind_drive(&h);
  if (rc) {
    fprintf(stderr, "ERROR: got 0x%x (%s) from nasd_unbind_drive()\n",
      rc, nasd_error_string(rc));
    fflush(stderr);
    exit(2);
  }

  nasd_cl_p_shutdown();

  printf("Successfully Completed.\n");

  exit(0);
}  

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
