From Elis.Pomales@rl.af.mil Wed Sep 13 21:52:38 2000
Date: Mon, 11 Sep 2000 18:40:44 -0000
From: Pomales Elis Contr AFRL/IFEC <Elis.Pomales@rl.af.mil>
To: "'kraxel@strusel007.de'" <kraxel@strusel007.de>
Subject: Changes to your scsi-changer.

Hi!

I've been setting up your scsi-changer software on one of the machines here.
We have a Maxoptix jukebox. Your software works great! But I had to make
some changes. 

Problem 1) with my jukebox (older) I have to add a delay after swaping
media, sleep(8) seems to work, right before getting out of the autojuke
program. If I don't have the sleep the fsck program thinks there is a
problem and bombs. 

Problem 2) kill(SID, PID) should be kill(PID, SIG) according to the man
pages.

Problem 3) Unmounts where not working because getppid() returns the wrong
PID. You see the automounter you run from boot.local (or wherever) startes
another automounter that then calls your program. Well getppid returns the
pid of the second automounter, not the original you ran. What I did (big
hack?) was that I wrote a routine, getautopid:

#define PID      "/var/run/automount.pid"

int
getautopid()
{
    FILE *fp;
    char line[80];
    int pid = -1;
    
    if (NULL == (fp = fopen(PID, "r"))) {
	perror(PROG ": open " PID);
	exit(1);
    }
    
    if (NULL != fgets(line, 79, fp)) {
        pid = atoi(line); 
    }
    
    fclose(fp);
    return pid;
}

This gets the pid using a pid file that I created when I ran the
automounter, as in:
/usr/sbin/automount /jukebox program /usr/sbin/autojuke
ps x | grep /usr/sbin/automount | grep -v grep | awk '{ print  }' >
/var/run/automount.pid

Problem 4) I needed double sided media support. So I added that to the
autojuke program. (I took out volume support though so you may want to edit
this.) The way I did it was I added a routine: 

void
getSlotandSide(char *line, int *slot, int *side)
{
    int i;
    int l = strlen(line) - 1;

    if ((l < 1) || (l > 2)) {
        fprintf(stderr, PROG ": invalid requested slot or side, %s", line);
	exit(1);
    }
    
    for (i = 0; i < l; i++) {
        if (!isdigit(line[i])) {
            fprintf(stderr, PROG ": invalid requested slot or side, %s",
line);
	    exit(1);
	}
    }

    if ((line[l] != 'a') && (line[l] != 'b')) {
	fprintf(stderr, PROG ": invalid requested slot or side, %s", line);
	exit(1);
    }
    
    *side = (line[l] == 'b');
    line[l] = 0;
    *slot = atoi(line) - 1;
}

This just verifies that you typed either digit+a or b OR digit+digit+a or b.
I modified other code but the most important piece I changed was this:

    /* everything fine so far, lets check what key we got... */
    getSlotandSide(argv[1], &slot, &side);
    
    if (slot < 0 || slot >= params.cp_nslots) {
        fprintf(stderr,PROG ": slot %d is out of range\n",slot);
	exit(1);
    }

#if DEBUG
    fprintf(stderr,PROG ": slot %d side %d\n", slot, side);
#endif

    /* check drives */
    for (drive = -1, i = 0; i < params.cp_ndrives; i++) {
	if ((dt[i].cge_status  &  CESTATUS_FULL) &&
	    (dt[i].cge_flags   &  CGE_SRC)       &&
	    (dt[i].cge_srctype == CHET_ST)       &&
	    (dt[i].cge_srcunit == slot)) {
	    drive = i;
	    break;
	}
    }

    if (-1 != drive) {
	/* Requested media is still in a drive. Do we need to flip it? */
        cside = ((dt[drive].cge_flags & CGE_INVERT) == CGE_INVERT);
    
        /* if current side is requested side do nothing otherwise attempt
invert */
        if (cside != side) {
	    /* ok attempt to unmount the disk */
	    if (0 != check_mtab(1, &devs[drive])) {
#if DEBUG
    	        fprintf(stderr,PROG ": sending SIGUSR1 to automount\n");
#endif
                kill(getautopid(), SIGUSR1);
	        sleep(1); /* XXX */
	        if (0 != check_mtab(1, &devs[drive])) {
        	    fprintf(stderr,PROG ": drive is busy with disk %d on
other side\n",slot);
		    exit(1);
	        }
	     }
	    
	    /* flip the disk */
	    memset(&move,0,sizeof(struct changer_move));
	    
	    move.cm_totype   = CHET_DT;
	    move.cm_tounit   = drive;
	    move.cm_fromtype = CHET_DT;
	    move.cm_fromunit = drive;
	    move.cm_flags    = CM_INVERT;

	    if (ioctl(fd,CHIOMOVE,&move)) {
		fprintf(stderr,PROG ": ioctl MOVE (load): %s\n",
			sys_errlist[errno]);
		exit(1);
	    }
	
            /* Let the drive spin up. */
 	    sleep(8);
	}
	
	/* tell automounter we are good to go */
	printf("%s\t:%s\n",mopt,devs[drive]);
	exit(0);
    }

    /* verify info for the slot */
    st.cge_type=CHET_ST;
    st.cge_unit=slot;
    if (ioctl(fd,CHIOGELEM,&st)) {
	fprintf(stderr,PROG ": ioctl CHIOGELEM st %d: %s\n",
		slot,strerror(errno));
	exit(1);
    }

    if (!(st.cge_status & CESTATUS_FULL)) {
	fprintf(stderr,PROG ": slot %d has no media\n",slot);
	exit(1); 
    }

The above code mainly handles when a disk you want is already in the drive
but needs to be flipped. If the disk is in a slot then the modified code is:

    memset(&move,0,sizeof(struct changer_move));
    move.cm_totype   = CHET_DT;
    move.cm_tounit   = drive;
    move.cm_fromtype = CHET_ST;
    move.cm_fromunit = slot;

    /* current side */
    cside = ((st.cge_flags & CGE_INVERT) == CGE_INVERT);
    
    /* if current side is not requested side invert*/
    move.cm_flags    = (cside == side) ? 0 : CM_INVERT;
    
    if (ioctl(fd,CHIOMOVE,&move)) {
	fprintf(stderr,PROG ": ioctl MOVE (load): %s\n",
		sys_errlist[errno]);
	exit(1);
    }
	
    // Let the drive spin up.
    sleep(8); /* XXX */
    
    /* tell automounter we are good to go */
    printf("%s\t:%s\n",mopt,devs[drive]);    
    exit(0);

Here the idea is to flip the disk if you requested the other side. Thats the
only change here, really.

Well that's all I sent the source file as well (will probably make more
sense, sorry). This is the first time I submit changes to any project so I
hope I didn't make a mess.

Hope this helps!
Elis Pomales

 <<autojuke.c>> 

    [ Part 2, Application/OCTET-STREAM (Name: "autojuke.c")  10KB. ]
    [ Unable to print this part. ]

