/*
 * drlayout.c
 *
 * Read or modify drive layout info
 *
 * 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 <nasd/nasd_timer.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_od.h>
#include <nasd/nasd_drive_utils.h>

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

char *progname;

char *dev_name;

nasd_layout_type_t old_layout_type;
nasd_layout_type_t new_layout_type;
int set_layout_type = 0;

off_t header_offset = 512;

nasd_od_disk_t disk;

void
usage()
{
  fprintf(stderr, "USAGE: %s [options] devname\n", progname);
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  -s layout_type (sets layout type)\n");
  fflush(stderr);
  exit(1);
}

int
main(
  int     argc,
  char  **argv)
{
  nasd_drive_layout_basic_t basic_layout;
  nasd_status_t rc;
  nasd_uint64 dlen;
  int fd, ret;
  off_t off;
  char c;

  progname = argv[0];

  rc = nasd_threads_init();
  if (rc) {
    fprintf(stderr, "ERROR: could not init nasd threads, error 0x%x (%s)\n",
      rc, nasd_error_string(rc));
    exit(1);
  }

  rc = nasd_mem_init();
  if (rc) {
    fprintf(stderr, "ERROR: could not init nasd memory, error 0x%x (%s)\n",
      rc, nasd_error_string(rc));
    exit(1);
  }

  while (nasd_getopt(argc, argv, "s:", &c)) {
    switch(c) {
      case 's':
        new_layout_type = nasd_optarg[0];
        if (new_layout_type == '\0')
          usage();
        set_layout_type = 1;
        break;
      default:
        fprintf(stderr, "Unknown option '%c'\n", nasd_optopt);
        usage();
    }
  }

  if (nasd_optind >= argc)
    usage();
  dev_name = argv[nasd_optind];
  nasd_optind++;

  if (nasd_optind < argc)
    usage();

  fd = open(dev_name, O_RDWR);
  if (fd < 0) {
    perror(dev_name);
    fprintf(stderr, "ERROR: cannot open %s\n", dev_name);
    exit(1);
  }

  rc = nasd_raw_disk_len(fd, &dlen);
  if (rc) {
    fprintf(stderr, "ERROR: got 0x%x (%s) getting length of %s\n",
      rc, nasd_error_string(rc), dev_name);
    exit(1);
  }

  rc = nasd_drive_compute_basic_layout(dlen, &basic_layout);
  if (rc) {
    fprintf(stderr, "ERROR: got 0x%x (%s) getting basic layout\n",
      rc, nasd_error_string(rc));
    exit(1);
  }

  header_offset = basic_layout.header1_blk << NASD_OD_SECT_SHIFT;

  off = lseek(fd, header_offset, SEEK_SET);
  if (off != header_offset) {
    fprintf(stderr, "ERROR: could not seek to %" NASD_64u_FMT "\n",
      (nasd_uint64)header_offset);
    exit(1);
  }

  ret = read(fd, &disk, sizeof(disk));
  if (ret != sizeof(disk)) {
    if (ret < 0)
      perror("read");
    else
      fprintf(stderr, "WARNING: got %d/%d header bytes\n", ret, sizeof(disk));
    fprintf(stderr, "ERROR: could not read disk header\n");
    exit(1);
  }
  printf("Layout type is '%c'\n", disk.layout_type);

  if (set_layout_type) {
    off = lseek(fd, header_offset, SEEK_SET);
    if (off != header_offset) {
      fprintf(stderr, "ERROR: could not seek to %" NASD_64u_FMT "\n",
        (nasd_uint64)header_offset);
      exit(1);
    }

    disk.layout_type = new_layout_type;
    ret = write(fd, &disk, sizeof(disk));
    if (ret != sizeof(disk)) {
      if (ret < 0)
        perror("write");
      else
        fprintf(stderr, "WARNING: put %d/%d header bytes\n", ret, sizeof(disk));
      fprintf(stderr,
        "ERROR: could not write disk header - DISK MAY BE CORRUPTED\n");
      exit(1);
    }
    printf("Set layout type to '%c'\n", disk.layout_type);
  }

  close(fd);
  nasd_mem_shutdown();
  nasd_threads_shutdown();

  exit(0);
}

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