/* $Id: ccfs.C,v 1.5 2006/02/13 05:32:23 sit Exp $ */

#include "amisc.h"
#include "async.h"
#include "arpc.h"
#include "dns.h"
#include "nfsserv.h"
#include "classfscli.h"
#include "blockdbc.h"
#include "fs.h"

#ifdef LOCKS
#include "lock_client.h"
#endif /* LOCKS */

static void
mounted (nfs_fh3 fh, int err)
{
  if(err == 0){
    printf("root file handle: %s\n",
           fs::fh2hex(fh).cstr());
    fflush(stdout);
  } else {
    fatal << "classfsd reports: " << strerror (err) << "\n";
  }
}

static void
usage ()
{
  fprintf(stderr, "Usage: ccfs dir-name blockdb-host blockdb-port [root-file-handle]\n");
  exit (1);
}

static void
got_root(str mntname, nfsserv_udp *nu, bool ok, nfs_fh3 fh)
{
  if(ok){
    classmount (nu->getfd (), fh.data, mntname, wrap (mounted, fh));
  } else {
    fprintf(stderr, "ccfs: got_root failed\n");
    exit(1);
  }
}

// ask classfsd to make us an NFS server
ptr<nfsserv_udp> nfss_udp = New refcounted<nfsserv_udp>;
ptr<nfsserv_fixup> nfss = New refcounted<nfsserv_fixup> (nfss_udp);

// just lookup up block server's host name
void
got_bs(char *dirname, char *blockport, char *roothandle,
       ptr<hostent> h, int err)
{
  if(!h || err != 0){
    fprintf(stderr, "could not resolve block server host name\n");
    exit(1);
  }

  struct sockaddr_in sin;
  bzero(&sin, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = htons(atoi(blockport));
  sin.sin_addr = *(in_addr*)h->h_addr;

  // attach to the block server
  blockdbc *db = New blockdbc(sin);
  db->test();

#ifdef LOCKS
  // attach to the lock server
  lock_client *lc = New lock_client(sin);
#endif /* LOCKS */

  // create a file server object
#ifdef LOCKS
  fs *f = New fs(db, lc);
#else /* LOCKS */
  fs *f = New fs(db);
#endif /* LOCKS */

  // get hold of NFS RPCs from classfs file system
  nfss->setcb (wrap (f, &fs::dispatch));

  // ask file server to create a new file system,
  // then once we know the root file handle,
  // tell classfsd about it.
  f->new_root(roothandle,
              wrap(got_root, dirname, nfss_udp));

#if 0
  lc->test();
#endif
}

int
main (int argc, char **argv)
{
  setprogname (argv[0]);
  if (argc != 4 && argc != 5)
    usage ();
  for(int i = 0; argv[3][i] != '\0'; i++)
    if(!isdigit(argv[3][i]))
      usage();

  srandom(getpid());

  // look up block server's host name
  dns_hostbyname(argv[2],
                 wrap(&got_bs, argv[1], argv[3], argc==5?argv[4]:0),
                 true, true);

  amain ();
}
