/* * program "map-file" for linux autofs * * usage: /usr/sbin/automount /jukebox program /usr/sbin/autojuke * */ #include #include #include #include #include #include #include #include #include #include #include #include #define PROG "autojuke" #define CHANGER "/dev/sch0" #define CONFIG "/etc/autojuke.conf" #define PID "/var/run/automount.pid" #define DEBUG 0 /* set to 1 for debug output */ /* ---------------------------------------------------------------------- */ int check_mtab(int n, char **devs) { int i,res; FILE *fp; struct stat st; char line[79],dev[32]; int *fl; /* check for lock file */ for (i = 0; i < 5; i++) { if (-1 == stat("/etc/mtab~",&st)) break; sleep(1); } if (5 == i) { fprintf(stderr,PROG ": /etc/mtab locked\n"); exit(1); } if (NULL == (fp = fopen("/etc/mtab", "r"))) { perror(PROG ": open /etc/mtab"); exit(1); } fl = malloc(n*sizeof(int)); memset(fl,0,n*sizeof(int)); while (NULL != fgets(line,79,fp)) { sscanf(line," %31s",dev); for (i = 0; i < n; i++) { if (0 == strcmp(dev,devs[i])) fl[i] = 1; } } res = -1; for (i = 0; i < n; i++) { if (0 == fl[i]) res = i; } free(fl); fclose(fp); return res; } 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; } 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; /*bm>*/ *slot = atoi(line); /*= 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); } } /* 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); } /* ok, requested media found, check where to put it now */ /* look for a empty drive first... */ for (i = 0, drive = -1; i < params.cp_ndrives; i++) { if (!(dt[i].cge_status & CESTATUS_FULL)) { drive = i; break; } } if (-1 == drive) /* failing that, look for a unmounted drive */ drive = check_mtab(params.cp_ndrives,devs); if (-1 == drive && try_umount) { /* still no success -- tell automount to umount idle mount-points */ #if DEBUG fprintf(stderr,PROG ": sending SIGUSR1 to automount\n"); #endif /*kill(getppid(), SIGUSR1); */ kill(getautopid(), SIGUSR1); sleep(1); /* XXX */ drive = check_mtab(params.cp_ndrives,devs); } if (-1 == drive) { /* bad luck */ fprintf(stderr,PROG ": all drives busy, sorry\n"); exit(1); } if (dt[drive].cge_status & CESTATUS_FULL) { /* Hmm, full. Ok, put back the old media ... */ if (!(dt[drive].cge_flags & CGE_SRC)) { fprintf(stderr,PROG ": source element for drive %d unknown\n", drive); exit(1); } memset(&move,0,sizeof(struct changer_move)); move.cm_totype = dt[drive].cge_srctype; move.cm_tounit = dt[drive].cge_srcunit; move.cm_fromtype = CHET_DT; move.cm_fromunit = drive; /*bm>*/ cside = ((dt[drive].cge_flags & CGE_INVERT) == CGE_INVERT); move.cm_flags = (cside == 0) ? 0 : CM_INVERT; /**/ /* if current side is not requested side invert*/ move.cm_flags = (0 == side) ? 0 : CM_INVERT; /*