/*
 * plspart.c
 *
 * List objects in a partition
 *
 * Author: Jim Zelenka
 */
/*
 * 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_getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_pdrive_client.h>
#include <nasd/nasd_pdrive_client_kpdev.h>
#include <nasd/nasd_security.h>
#include <nasd/nasd_edrfs_types.h>
#include <nasd/nasd_edrfs_types_marshall.h>
#include <nasd/nasd_types_marshall.h>

char *progname;

nasd_drive_handle_t  h;
int                  partnum;

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;
nasd_sec_keyring_t         keys;
nasd_uint16                protection;

#define OBJ_BUF_LEN 10

void (*show_entry)(nasd_identifier_t nid);

extern char *_nasd_timestr_r();
#define DOTIME(_ts_,_str_) nasd_timestr_r((_ts_),_str_), (_ts_).ts_sec, (_ts_).ts_nsec

void
usage()
{
  int i;
  fprintf(stderr, "USAGE: %s [options] servername partnum master_password\n",
    progname);
  fflush(stderr);
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  -k use kernel device\n");
  fprintf(stderr, "  -M use message queues\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));
  }
#if NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_DCE
  fprintf(stderr, "  -T use DCE-TCP\n");
#endif /* NASD_RPC_PACKAGE == NASD_RPC_PACKAGE_DCE */
  exit(1);
}

void
show_entry_simple(
  nasd_identifier_t  nid)
{
  printf("0x%" NASD_ID_FMT "\n", nid);
}

void
show_entry_jimz(
  nasd_identifier_t  nid)
{
  char t1[128], t2[128], t3[128], t4[128], t5[128];
  nasd_error_string_t error_text;
  nasd_security_param_t sec_param;
  nasd_p_getattr_dr_args_t args;
  nasd_p_getattr_dr_res_t res;
  nasd_rpc_status_t status;
  nasd_attribute_t *attr;
  nasd_cookie_t cookie;
  nasd_timespec_t tm;

  args.in_partnum = partnum;
  args.in_identifier = nid;

  nasd_drive_handle_get_time(h, &tm);
  tm.ts_sec+=(60*60);
  nasd_sec_build_capability(args.in_partnum, args.in_identifier,
    NASD_ACCESS_RIGHTS_GETATTR, 0, tm.ts_sec,
    protection, NASD_BLACK_CAPABILITY, 0,
    0, 7, keys.black_key, &cookie);

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

  nasd_cl_p_getattr_dr(h, cookie.key, &sec_param,
                       &cookie.capability, &args, &res, &status);
  if (res.nasd_status || status) {
    fprintf(stderr, "ERROR: nasd_status=0x%x (%s) status=0x%x (%s) nid=0x%" NASD_ID_FMT "\n",
      res.nasd_status, nasd_error_string(res.nasd_status),
      status, nasd_cl_error_string(h, status, error_text), nid);
    exit(1);
  }

  attr = &res.out_attribute;

  printf("0x%" NASD_ID_FMT "  len %16" NASD_64u_FMT
    "  amtime=%s(%d:%09d) mdtime=%s(%d:%09d) crtime=%s(%d:%09d)"
    " fsamtime=%s(%d:%09d) fsmdtime=%s(%d:%09d)\n",
    nid, (nasd_uint64)attr->object_len,
    DOTIME(attr->attr_modify_time, t1),
    DOTIME(attr->object_modify_time, t2),
    DOTIME(attr->object_create_time, t3),
    DOTIME(attr->fs_attr_modify_time, t4),
    DOTIME(attr->fs_object_modify_time, t5));
}

void
show_entry_jimz_edrfs(
  nasd_identifier_t  nid)
{
  nasd_edrfs_attributes_t *edrfsattr;
  nasd_error_string_t error_text;
  nasd_security_param_t sec_param;
  nasd_p_getattr_dr_args_t args;
  nasd_p_getattr_dr_res_t res;
  nasd_rpc_status_t status;
  nasd_attribute_t *attr;
  nasd_cookie_t cookie;
  nasd_timespec_t tm;

  args.in_partnum = partnum;
  args.in_identifier = nid;

  nasd_drive_handle_get_time(h, &tm);
  tm.ts_sec+=(60*60);
  nasd_sec_build_capability(args.in_partnum, args.in_identifier,
    NASD_ACCESS_RIGHTS_GETATTR, 0, tm.ts_sec,
    protection, NASD_BLACK_CAPABILITY, 0,
    0, 7, keys.black_key, &cookie);

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

  nasd_cl_p_getattr_dr(h, cookie.key, &sec_param, &cookie.capability,
                       &args, &res, &status);
  if (res.nasd_status || status) {
    fprintf(stderr, "ERROR: nasd_status=0x%x (%s) status=0x%x (%s) nid=0x%" NASD_ID_FMT "\n",
      res.nasd_status, nasd_error_string(res.nasd_status),
      status, nasd_cl_error_string(h, status, error_text), nid);
    exit(1);
  }

  attr = &res.out_attribute;
  nasd_edrfs_attributes_t_unmarshall((nasd_otw_base_t *)
                                     attr->fs_specific,
                                     edrfsattr);
  printf("0x%" NASD_ID_FMT "  type 0x%02x mode 0x%x nlink %d uid %u gid %u",
    nid, edrfsattr->type&0xff, edrfsattr->mode, edrfsattr->nlink,
    edrfsattr->uid, edrfsattr->gid);
  printf("\n");
}

void
show_entry_jimz_blocks(
  nasd_identifier_t  nid)
{
  nasd_error_string_t error_text;
  nasd_security_param_t sec_param;
  nasd_p_getattr_dr_args_t args;
  nasd_p_getattr_dr_res_t res;
  nasd_rpc_status_t status;
  nasd_attribute_t *attr;
  nasd_cookie_t cookie;
  nasd_timespec_t tm;

  args.in_partnum = partnum;
  args.in_identifier = nid;

  nasd_drive_handle_get_time(h, &tm);
  tm.ts_sec+=(60*60);
  nasd_sec_build_capability(args.in_partnum, args.in_identifier,
    NASD_ACCESS_RIGHTS_GETATTR, 0, tm.ts_sec,
    protection, NASD_BLACK_CAPABILITY, 0,
    0, 7, keys.black_key, &cookie);

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

  nasd_cl_p_getattr_dr(h, cookie.key, &sec_param, &cookie.capability,
                       &args, &res, &status);
  if (res.nasd_status || status) {
    fprintf(stderr, "ERROR: nasd_status=0x%x (%s) status=0x%x (%s) nid=0x%" NASD_ID_FMT "\n",
      res.nasd_status, nasd_error_string(res.nasd_status),
      status, nasd_cl_error_string(h, status, error_text), nid);
    exit(1);
  }

  attr = &res.out_attribute;

  printf("0x%" NASD_ID_FMT "  len %16" NASD_64u_FMT
    "  blocks %16" NASD_64u_FMT "  prealloc %16" NASD_64u_FMT "\n",
    nid, attr->object_len, attr->blocks_used, attr->block_preallocation);
}

int
main(
  int     argc,
  char  **argv)
{
  nasd_identifier_otw_t objs_otw[OBJ_BUF_LEN];
  char *master_password, *server_name;
  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_rpc_status_t status;
  nasd_identifier_t obj;
  nasd_offset_t off;
  nasd_status_t rc;
  nasd_len_t len;
  char c;
  int i;
  int sec_level = 0;

  progname = argv[0];
  show_entry = show_entry_simple;

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

  while(nasd_getopt(argc, argv, "jkMns:Tv", &c)) {
    switch(c) {
      case 'j':
        show_entry = show_entry_jimz;
        break;
      case 'n':
        show_entry = show_entry_jimz_edrfs;
        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 'M':
        if (nondefault_binding)
          usage();
        nondefault_binding = 1;
        binding_type = NASD_BIND_MSGQ;
        break;
      case 's':
        sec_level = 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 */
      case 'v':
        show_entry = show_entry_jimz_blocks;
        break;
      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];

  nasd_optind++;
  if (nasd_optind < argc)
    usage();

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

  rc = nasd_cl_p_init();
  if (rc) {
    fprintf(stderr,"ERROR (%s:%d): cannot init client library, rc=0x%x (%s)\n",
      __FILE__, __LINE__, rc, nasd_error_string(rc));
    fflush(stderr);
    exit(1);
  }

  nasd_sec_password_to_keys(master_password, partnum, &keys);

  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);
    exit(1);
  }

  off = 0;
  do {
    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);
    sec_param.type = NASD_PARTITION_KEY;
    sec_param.partnum = partnum;
    if(protection != NASD_NO_PROTECTION)
      sec_param.actual_protection = NASD_INTEGRITY_OPS | protection;
    else
      sec_param.actual_protection = NASD_NO_PROTECTION;
    nasd_cl_p_read_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(1);
    }
    for(i=0;i<len/sizeof(nasd_identifier_t);i++) {
      nasd_identifier_t_unmarshall(objs_otw[i], &obj);
      show_entry(obj);
    }
    off += len;
  } while(len);

  exit(0);
}

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