
/* This program is used to test the UFS fileserver without diddling */
 /* the emulator.  Makes it easier to deal with until I'm confident */
 /* the filesystem won't get hopelessly trashed. */

#include <mach.h>
#include <gnu/types.h>
#include "fs.h"
#include "fsys.h"
#include "io.h"
#include <gnu/file.h>
#include <sys/exec.h>

mach_port_t ufs_control;

void handle_io_requests();
boolean_t io_server();

/* Arg one is the name of the ufs server, arg 2 is the name of the */
 /* filesystem. */
main(ac, av)
     int ac;
     char **av;
{
  /* Create the control port for the filesystem */
  mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
		      &ufs_control);
  mach_port_insert_right (mach_task_self (), ufs_control, ufs_control,
			  MACH_MSG_TYPE_MAKE_SEND);

  /* Create the ufs task */
  create_ufs(av[1]);

  handle_user_requests();
}

task_by_pid (n)
{
  return syscall (-33, n);
}

  


/* All zeros... */
uid_t idblock[20];

/* This fascinating bit of code reads requests typed by the user and
   gives them to the filesystem, spitting the results on stdout. */
handle_user_requests()
{
  int command;
  io_statbuf_t stb;
  fsys_statfsbuf_t fsysb;
  int file, file2;
  int arg1, arg2, arg3;
  int ret;
  time_value_t tv1, tv2;
  filecomp_t name, name2;
  int foo, foo2;

  /* We need to tell the user what root is before we start: */
  
  file = 0;
  ret = fsys_getroot (ufs_control, idblock, 10, &(mach_port_t)file);
  printf("Rootdir is %d, err %d\n", file, ret);
  while (1)
    {
      command = getchar ();
      switch (command)
	{
	case 'S':		/* stat */
	  scanf ("%d\n", &file);
	  ret = io_stat(file, &stb);
	  if (ret == KERN_SUCCESS)
	    printf ("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\
%d %d %d %d %d", stb.stb_fstype, stb.stb_fsid.val[0], stb.stb_fsid.val[1], 
		    stb.stb_file_id,
		    stb.stb_generation_id, stb.stb_rdev, stb.stb_mode,
		    stb.stb_nlink, stb.stb_uid, stb.stb_gid,
		    stb.stb_size, stb.stb_atime.seconds,
		    stb.stb_atime.microseconds, stb.stb_mtime.seconds,
		    stb.stb_mtime.microseconds, stb.stb_ctime.seconds,
		    stb.stb_ctime.microseconds, stb.stb_blksize,
		    stb.stb_blocks, stb.stb_author);
	  break;
	case 'O':		/* chown */
	  scanf ("%d %d %d\n", &file, &arg1, &arg2);
	  ret = file_chown(file, arg1, arg2);
	  break;
	case 'M':		/* chmod */
	  scanf ("%d %o\n", &file, &arg1);
	  ret = file_chmod (file, arg1);
	  break;
	case 'U':		/* utimes */
	  scanf ("%d %d %d %d %d\n", &file, &tv1.seconds, &tv1.microseconds,
		 &tv2.seconds, &tv2.microseconds);
	  ret = file_utimes (file, tv1, tv2);
	  break;
	case 'K':		/* seek */
	  scanf ("%d %d %d\n", &file, &arg1, &arg2);
	  ret = file_seek (file, arg1, arg2, &foo);
	  if (ret == KERN_SUCCESS)
	    printf ("%d", foo);
	  break;
	case 'T':		/* truncate */
	  scanf ("%d %d\n", &file, &arg1);
	  ret = file_truncate (file, arg1);
	  break;
	case 'L':		/* flock */
	  scanf ("%d %d\n", &file, &arg1);
	  ret = file_lock (file, arg1);
	  break;
	case 'F':		/* statfs */
	  scanf ("%d\n", &file);
	  ret = file_statfs (file, &fsysb);
	  if (ret == KERN_SUCCESS)
	    printf ("%d %d %d %d %d %d %d %d %d",
		    fsysb.fsys_stb_type, fsysb.fsys_stb_bsize,
		    fsysb.fsys_stb_blocks, fsysb.fsys_stb_bfree,
		    fsysb.fsys_stb_bavail, fsysb.fsys_stb_files,
		    fsysb.fsys_stb_ffree, fsysb.fsys_stb_fsid_1,
		    fsysb.fsys_stb_fsid_2);
	  break;
	case 'D':		/* directory op */
	  command = getchar ();
	  switch (command)
	    {
	    case 'O':		/* lookup (open) */
	      scanf ("%d %s %d %o\n", &file, name, &arg1, &arg2);
	      ret = dir_pathtrans (file, name, strlen (name) + 1, arg1, arg2,
				   &foo, name2, &(u_long)foo2, &file2);
	      if (ret == KERN_SUCCESS)
		if (foo)
		  printf ("%d %s %d", foo, name2, file2);
		else
		  printf ("%d %d", foo, file2);
	      break;
	    case 'T':		/* lstat */
	      scanf ("%d %s\n", &file, name);
	      ret = dir_lstat (file, name, strlen (name) + 1, &stb);
	      if (ret == KERN_SUCCESS)
		printf ("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\
%d %d %d %d %d", stb.stb_fstype, stb.stb_fsid.val[0], stb.stb_fsid.val[1], 
			stb.stb_file_id,
			stb.stb_generation_id, stb.stb_rdev, stb.stb_mode,
			stb.stb_nlink, stb.stb_uid, stb.stb_gid,
			stb.stb_size, stb.stb_atime.seconds,
			stb.stb_atime.microseconds, stb.stb_mtime.seconds,
			stb.stb_mtime.microseconds, stb.stb_ctime.seconds,
			stb.stb_ctime.microseconds, stb.stb_blksize,
			stb.stb_blocks, stb.stb_author);
	      break;
	    case 'M':		/* mkdir */
	      scanf ("%d %s %o\n", &file, name, &arg1);
	      ret = dir_mkdir (file, name, strlen (name) + 1, arg1);
	      break;
	    case 'R':		/* rmdir */
	      scanf ("%d %s\n", &file, name);
	      ret = dir_rmdir (file, name, strlen (name) + 1);
	      break;
	    case 'U':		/* unlink */
	      scanf ("%d %s\n", &file, name);
	      ret = dir_unlink (file, name, strlen (name) + 1);
	      break;
	    case 'L':		/* link */
	      scanf ("%d %s %d %s\n", &file, &file2, name);
	      ret = dir_link (file, file2, name, strlen (name) + 1);
	      break;
	    case 'S':		/* symlink */
	      scanf ("%d %s %s\n", &file, name, name2);
	      ret = dir_symlink (file, name, strlen (name) + 1, name2,
				 strlen (name2) + 1);
	      break;
	    case 'V':		/* rename (move) */
	      scanf ("%d %s %d %s\n", &file, name, &file2, name2);
	      ret = dir_rename (file, name, strlen (name) + 1,  file2, name2,
				strlen (name2) + 1);
	      break;
	    }
	  break;
	}
      if (ret == KERN_SUCCESS)
	printf ("OK\n");
      else
	printf ("Error: %d\n", ret);
    }
}



/* Create the ufs process */
create_ufs (ufsname)
     char *ufsname;
{
  int pid;
  task_t ufs_task;
  volatile int err1, err2, err3, i;
  
  pid = fork ();
  switch (pid)
    {
    default:			/* parent */
      ufs_task = task_by_pid (pid);

      /* Insert the control port so it can do its receive. */
      err1 = mach_port_insert_right (ufs_task, 500, ufs_control,
				     MACH_MSG_TYPE_MOVE_RECEIVE);

      /* Insert the host priv port */
      err2 = mach_port_insert_right (ufs_task, 501, task_by_pid (-1),
				     MACH_MSG_TYPE_MOVE_SEND);
      /* Insert the device master port */
      err3 = mach_port_insert_right (ufs_task, 502, task_by_pid (-2),
				     MACH_MSG_TYPE_MOVE_SEND);
      break;
      
    case 0:			/* child */
      mach_init ();
      /* Wait for the parent to have finished giving us our ports.  */
      while (err1 = mach_port_get_refs (mach_task_self (), 502,
					MACH_PORT_RIGHT_SEND, &i))
	;
      execl (ufsname, ufsname, 0);
      printf ("child exec failed\n");
      break;
      
    case -1:
      printf ("fork failed\n");
      break;
    }
}

