#include <stdio.h>
#include <sys/file.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/devgetinfo.h>
#include <sys/devio.h>
#include <sys/mount.h>
#include <cdfs/cdfsmount.h>
#include <cdfs/cdfs.h>
#include <cdfs/rrip.h>
#include <signal.h>
#include <excpt.h>
#include <io/cam/cdrom.h>
struct {
  int file;
  int mounted;
  unsigned char dev[512];
  char mount_point[512];
}CD[16];

signal_handler(int sig)
{
  int i, j;
  for(i=0; i<16; i++){
    if(CD[i].mounted){
      j=umount(CD[i].mount_point , 2);
      if(j<0){
	return;
      }
      CD[i].mounted=0;
      CD[i].file = open(CD[i].dev, O_NDELAY|O_RDONLY);
      ioctl(CD[i].file, CDROM_EJECT_CADDY);
      close(CD[i].file);
    }
  }
}

EXCEPTION_DISPOSITION die(system_exrec_type *exceptionRecord,
			  void *establisherFrame,
			  CONTEXT *contextRecord,
			  DISPATCHER_CONTEXT *dispatcherContext){
    printf ("Handler: executing...\n");
    printf ("The signal code is 0x%0lx0\n", exceptionRecord->ExceptionCode);
    printf ("The exception PC is 0x%0lx0\n", contextRecord->sc_pc);
    printf ("Exception Masks: ");
/* Print flag mask values */
    if (exceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
	printf ("NONCONTINUABLE ");
    if (exceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)
	printf ("UNWINDING ");
    if (exceptionRecord->ExceptionFlags & EXCEPTION_EXIT_UNWIND)
	printf ("EXIT_UNWIND ");
    if (exceptionRecord->ExceptionFlags & EXCEPTION_STACK_INVALID)
	printf ("STACK_INVALID ");
    if (exceptionRecord->ExceptionFlags & EXCEPTION_NESTED_CALL)
	printf ("NESTED_CALL ");
    if (exceptionRecord->ExceptionFlags & EXCEPTION_TARGET_UNWIND)
	printf ("TARGET_UNWIND ");
    if (exceptionRecord->ExceptionFlags & EXCEPTION_COLLIDED_UNWIND)
	printf ("COLLIDED_UNWIND \n");

    unlink ("/var/adm/vold.pid");
    exit(0);
}

    
main(int argc, char **argv, char **envp){
    
    
    unsigned char pid[10],*buff;
    int i,j,dir, id;
    struct dirent *dptr;
    struct stat sbuf;
    struct cdfs_args cdbuf;
    struct ufs_args ufsbuf;

    device_info_t devbuf;

    id=open("/var/adm/vold.pid",O_WRONLY|O_CREAT);
    sprintf(pid, "%d\n",getpid());
    write(id, pid, strlen(pid));
    close(id);

    for(i=0; i<12; i++){
      CD[i].file=0;
      CD[i].mounted = 0;
      CD[i].dev[0]='\0';
      if(i>0)
	sprintf(CD[i].mount_point,"/cdrom%d",i);
    }
    sprintf(CD[0].mount_point,"/cdrom");
    
    signal(SIGUSR1, signal_handler);
    signal(SIGUSR2, SIG_IGN);
    signal(SIGHUP, SIG_IGN);
    set_unhandled_exception(die);
    
    
    dir=open("/dev",O_RDONLY);
    fstat(dir, &sbuf);
    buff = (unsigned char *)malloc(sbuf.st_size);
    read(dir, buff, sbuf.st_size);
    i=0;
    j=0;
    
    while(i<sbuf.st_size){
      (unsigned char *)dptr=buff+i;
      if(!strncmp(dptr->d_name,"rrz",3) && 
	 dptr->d_name[dptr->d_namlen - 1] == 'c' && j<16){
	strcpy(CD[j].dev,"/dev/");
	strncat(CD[j].dev, dptr->d_name, dptr->d_namlen);
	CD[j].dev[dptr->d_namlen+5]='\0';
	CD[j].file = open(CD[j].dev, O_NDELAY|O_RDONLY);
	if(CD[j].file >=0){
	  ioctl(CD[j].file, DEVGETINFO, &devbuf, sizeof(struct devget));
	  if(devbuf.v1.devinfo.disk.status&DKDEV_REMOVABLE){
	    if(devbuf.v1.devinfo.disk.status&DKDEV_READY){
	      char name[10];
	      sprintf(name,"/dev/%s",CD[j].dev+6);
	      cdbuf.fspec=name;
	      ufsbuf.fspec=name;

	      ufsbuf.exflags=0;
	      ufsbuf.exroot=0;
	      
	      cdbuf.exroot=-2;
	      cdbuf.flags=M_DEFFMODE|M_DEFUID|M_DEFGID|M_RRIP|M_NOVERSION;
	      cdbuf.version=1;
	      cdbuf.default_uid=0;
	      cdbuf.default_gid=0;
	      cdbuf.default_fmode=0555;
	      cdbuf.default_dmode=0555;
	      cdbuf.map_uid_ct=0;
	      cdbuf.map_uid=NULL;
	      cdbuf.map_gid_ct=0;
	      cdbuf.map_gid=NULL;
  
	      if(!mount(MOUNT_CDFS,CD[j].mount_point,M_RDONLY,&cdbuf))
		CD[j].mounted=1;
	      else if(!mount(MOUNT_UFS,CD[j].mount_point,M_RDONLY,&ufsbuf))
		CD[j].mounted=1;
	      close(CD[j].file);
	    }
	    if(devbuf.v1.devinfo.disk.status&DKDEV_OFFLINE){
	      CD[j].mounted=0;
	      close (CD[j].file);
	    }
	    j++;
	  }
	  else{
	    close (CD[j].file);
	  }
	}
      }
      i = i+(int)dptr->d_reclen;
    }
    
    while(1){
      j=0;
	while(CD[j].dev[0] != '\0'){
	  CD[j].file = open(CD[j].dev, O_NDELAY|O_RDONLY);
	  if(CD[j].file>=0){
	    if(ioctl(CD[j].file, 
		     DEVGETINFO, &devbuf, sizeof(struct devget)) <0)
	      devbuf.v1.devinfo.disk.status=0;
	    if(devbuf.v1.devinfo.disk.status&DKDEV_READY){
	      if(!CD[j].mounted){
		char name[10];

		ufsbuf.exflags=0;
		ufsbuf.exroot=0;
		
		cdbuf.exroot=-2;
		cdbuf.flags=M_DEFFMODE|M_DEFUID|M_DEFGID|M_RRIP|M_NOVERSION;
		cdbuf.version=1;
		cdbuf.default_uid=0;
		cdbuf.default_gid=0;
		cdbuf.default_fmode=0555;
		cdbuf.default_dmode=0555;
		cdbuf.map_uid_ct=0;
		cdbuf.map_uid=NULL;
		cdbuf.map_gid_ct=0;
		cdbuf.map_gid=NULL;

		sprintf(name,"/dev/%s",CD[j].dev+6);
		cdbuf.fspec=name;
		ufsbuf.fspec=name;
		if(!mount(MOUNT_CDFS,CD[j].mount_point,M_RDONLY,&cdbuf))
		  CD[j].mounted=1;
		else if(!mount(MOUNT_UFS,CD[j].mount_point,M_RDONLY,&ufsbuf))
		  CD[j].mounted=1;
	      }
	    }
	    if(devbuf.v1.devinfo.disk.status&DKDEV_OFFLINE){
	      CD[j].mounted=0;
	    }
	  }
	  close(CD[j].file);
	  j++;
	}
    sleep(60);
    }
}
	

