/*
 * nasd_kedrfs_server.c
 *
 * in-kernel NASD EDRFS server user binary
 * (reads mounts file and makes syscall to start server)
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1997,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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <nasd/nasd_getopt.h>
#include <nasd/nasd_general.h>
#include <nasd/nasd_pdrive.h>
#include <nasd/nasd_sys.h>
#include <nasd/nasd_edrfs_server.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

char *progname;
char *mountfile = "./nasd_edrfs_mounts";

int svc_threads = 15;
int stack_size = 0;
int colocate = 0;

void
usage()
{
  fprintf(stderr, "USAGE: %s [options]\n", progname);
  fprintf(stderr, "Options:\n");
  fprintf(stderr, "  -l colocate with drive\n");
  fprintf(stderr, "  -m mountfile [default %s]\n", mountfile);
  fprintf(stderr, "  -s stack size (0 = DCE default) [default %d]\n",
    stack_size);
  fprintf(stderr, "  -t service threads [default %d]\n", svc_threads);
  fflush(stderr);
  exit(1);
}

int
main(
  int     argc,
  char  **argv)
{
  char buf[1024], *path, *drive, *part;
  struct nasd_edrfs_config edrfscfg;
  int ret, line, p, portnum;
  struct nasd_edrfs_mount *m;
  nasd_uint32 net_addr;
  struct in_addr addr;
  struct hostent *he;
  nasd_status_t rc;
  char c, *env;
  FILE *f;

  progname = argv[0];

  setbuf(stdout, NULL);
  setbuf(stderr, NULL);

  env = getenv("NASD_EDRFS_MNTFILE");
  if (env) {
    mountfile = env;
  }

  while (nasd_getopt(argc, argv, "lm:s:t:", &c)) {
    switch(c) {
      case 'l':
        colocate = 1;
        break;
      case 'm':
        mountfile = nasd_optarg;
        break;
      case 's':
        if (sscanf(nasd_optarg, "%d", &stack_size) != 1)
          usage();
        break;
      case 't':
        if (sscanf(nasd_optarg, "%d", &svc_threads) != 1)
          usage();
        break;
      default:
        fprintf(stderr, "Unknown option '%c'\n", c);
        usage();
    }
  }
  if (nasd_optind < argc)
    usage();

  if (svc_threads < 1)
    usage();

  edrfscfg.mount_array_len = 0;
  edrfscfg.mount_array = (struct nasd_edrfs_mount *)
    malloc((edrfscfg.mount_array_len+1)*sizeof(struct nasd_edrfs_mount));
  edrfscfg.verbose = 1;
  edrfscfg.svc_threads = svc_threads;
  edrfscfg.stack_size = stack_size;
  edrfscfg.colocate = colocate;

  if (sscanf(NASD_EDRFS_SERVER_PORT, "%hu", &edrfscfg.ipport) != 1) {
    NASD_PANIC();
  }

  ret = sscanf(NASD_PDRIVE_PORT, "%d", &portnum);
  if (ret != 1) {
    NASD_PANIC();
  }
  f = fopen(mountfile, "r");
  if (f == NULL) {
    fprintf(stderr, "EDRFS: Could not open %s for reading\n", mountfile);
    fflush(stderr);
    return(NASD_FAIL);
  }

  line = 0;
  while(fgets(buf, 1024, f) != NULL) {
    line++;
    buf[1023] = '\0';
    if ((buf[0] == '\0') || (buf[0] == '#'))
      continue;
    path = strtok(buf, " \t\n");
    if (path == NULL)
      continue;
    drive = strtok(NULL, " \t\n");
    if (drive == NULL) {
      fprintf(stderr, "Error parsing %s at line %d: no drive name\n",
        mountfile, line);
      fflush(stderr);
      exit(1);
    }
    part = strtok(NULL, " \t\n");
    if (part == NULL) {
      fprintf(stderr, "Error parsing %s at line %d: no partition number\n",
        mountfile, line);
      fflush(stderr);
      exit(1);
    }
    if (sscanf(part, "%d", &p) != 1) {
      fprintf(stderr, "Error parsing %s at line %d: bad partition number\n",
        mountfile, line);
      fflush(stderr);
      exit(1);
    }
    if ((p < 0) || (p > 64)) {
      fprintf(stderr, "Error parsing %s at line %d: bad partition number\n",
        mountfile, line);
      fflush(stderr);
      exit(1);
    }
    he = gethostbyname(drive);
    if (he == NULL) {
      fprintf(stderr, "Error resolving hostname %s (file %s line %d)\n",
        drive, mountfile, line);
      fflush(stderr);
      exit(1);
    }
    bcopy(he->h_addr_list[0], (char *)&net_addr, 4);

    edrfscfg.mount_array = (struct nasd_edrfs_mount *)realloc(edrfscfg.mount_array,
      (edrfscfg.mount_array_len+1)*sizeof(struct nasd_edrfs_mount));
    m = &edrfscfg.mount_array[edrfscfg.mount_array_len];
    edrfscfg.mount_array_len++;

    addr.s_addr = net_addr;
    strcpy(m->drive_ip_addr, inet_ntoa(addr));
    bcopy(path, m->path, NASD_MIN(MAXPATHLEN,strlen(path)));
    m->path[NASD_MIN(MAXPATHLEN-1,strlen(path))] = '\0';
    bcopy(drive, m->name, NASD_MIN(MAXPATHLEN,strlen(drive)));
    m->name[NASD_MIN(MAXPATHLEN-1,strlen(drive))] = '\0';
    m->portnum = portnum;
    m->partnum = p;
    m->net_addr = net_addr;
  }
  fclose(f);
  if (edrfscfg.mount_array_len == 0) {
    fprintf(stderr, "ERROR: no mounts found in %s\n", mountfile);
    fflush(stderr);
    exit(1);
  }

  printf("Ready to launch EDRFS server.\n");
  fflush(stdout);
  fflush(stderr);
  rc = nasd_srv(NASD_SC_EDRFS_SRV_GO, &edrfscfg);
  fprintf(stderr, "nasd_srv(NASD_SC_EDRFS_SRV_GO): rc=%d errno=%d (%s)\n",
	  rc, errno, strerror(errno));

  exit(0);
}
