/* * 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 #include "chio.h" #define PROG "autojuke" #define CHANGER "/dev/sch0" #define CONFIG "/etc/autojuke.conf" #define DEBUG 0 /* set to 1 for debug output */ /* ---------------------------------------------------------------------- */ static 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; } static int cdrom_tray(char *dev, int eject) { int fd = -1; if (-1 == (fd = open(dev,O_RDONLY | O_NONBLOCK))) goto err; if (eject) { if (-1 == ioctl(fd,CDROMEJECT,NULL)) goto err; } else { if (-1 == ioctl(fd,CDROMCLOSETRAY,NULL)) goto err; } close(fd); return 0; err: if (-1 != fd) close(fd); return -1; } int main(int argc, char *argv[]) { struct changer_params params; struct changer_get_element st; struct changer_get_element *dt; struct changer_move move; char **devs,line[80],mopt[80],*h; int fd,i,slot,drive; int try_umount = 0; int eject_cdrom = 0; FILE *fp; if (argc != 2) { fprintf(stderr,"Read the f*** manual!\n\n*plonk*\n\n"); exit(1); } if (-1 == (fd = open(CHANGER,O_RDONLY))) { perror(PROG ": open " CHANGER); exit(1); } /* read changer status information */ if (ioctl(fd,CHIOGPARAMS,¶ms)) { perror(PROG ": ioctl CHIOGPARAMS"); exit(1); } #if DEBUG fprintf(stderr,PROG ": %d drives, %d slots\n", params.cp_ndrives,params.cp_nslots); #endif dt = malloc(sizeof(struct changer_get_element)*params.cp_ndrives); for (i = 0; i < params.cp_ndrives; i++) { dt[i].cge_type=CHET_DT; dt[i].cge_unit=i; if (ioctl(fd,CHIOGELEM,dt+i)) { fprintf(stderr,PROG ":ioctl CHIOGELEM mt %d: %s\n", i,strerror(errno)); exit(1); } if (NULL != (h = strchr(dt[i].cge_pvoltag,' '))) *h = '\0'; if (NULL != (h = strchr(dt[i].cge_avoltag,' '))) *h = '\0'; } /* read config file */ if (NULL == (fp = fopen(CONFIG, "r"))) { perror(PROG ": open " CONFIG); exit(1); } devs = malloc(sizeof(char*)*params.cp_ndrives); for (i = 0; NULL != fgets(line,79,fp);) { if (line[0] == '#' || line[0] == '\n') continue; if (sscanf(line,"try_umount= %d",&try_umount)) continue; if (sscanf(line,"eject_cdrom= %d",&eject_cdrom)) continue; if (line==strstr(line,"mopt=")) { strncpy(mopt,line+5,79); mopt[strlen(mopt)-1]='\0'; continue; } devs[i] = malloc(32); if (!sscanf(line,"dev= %31s",devs[i])) { fprintf(stderr,PROG ": config syntax error: %s",line); exit(1); } #if DEBUG fprintf(stderr,PROG ": drive %d: %s\n",i,devs[i]); #endif i++; } fclose(fp); if (i != params.cp_ndrives) { fprintf(stderr, PROG ": number of drives (%d) does'nt match the\n" PROG ": number of dev=... lines (%d) in " CONFIG "\n", params.cp_ndrives,i); exit(1); } /* everything fine so far, lets check what key we got... */ for (i = 0; argv[1][i];i++) if (!isdigit(argv[1][i])) break; if (!argv[1][i]) { /* we got a number */ slot = atoi(argv[1]); if (slot < 0 || slot >= params.cp_nslots) { fprintf(stderr,PROG ": slot %d is out of range\n",slot); exit(1); } /* 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) { /* Ha! requested media is still in a drive. Nothing to do :-) */ printf("%s\t:%s\n",mopt,devs[drive]); exit(0); } 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); } } else { /* no number -- assume volume tag */ /* check drives */ for (drive = -1, i = 0; i < params.cp_ndrives; i++) { if ((dt[i].cge_status & CESTATUS_FULL) && (dt[i].cge_flags & CGE_PVOLTAG) && (0 == strcmp(argv[1],dt[i].cge_pvoltag))) { drive = i; break; } } if (-1 != drive) { /* Ha! requested media is still in a drive. Nothing to do :-) */ printf("%s\t:%s\n",mopt,devs[drive]); exit(0); } /* Find the tag */ st.cge_type=CHET_ST; for (slot = -1, i = 0; i < params.cp_nslots; i++) { st.cge_unit=i; if (ioctl(fd,CHIOGELEM,&st)) { fprintf(stderr,PROG ": ioctl CHIOGELEM st %d: %s\n", i,strerror(errno)); exit(1); } if (NULL != (h = strchr(st.cge_pvoltag,' '))) *h = '\0'; if (NULL != (h = strchr(st.cge_avoltag,' '))) *h = '\0'; if ((st.cge_status & CESTATUS_FULL) && (st.cge_flags & CGE_PVOLTAG) && (0 == strcmp(argv[1],st.cge_pvoltag))) { slot = i; break; } } if (-1 == slot) { fprintf(stderr,PROG ": volume tag %s not found\n",argv[1]); 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(SIGUSR1,getppid()); 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 (eject_cdrom) { if (0 != cdrom_tray(devs[drive],1)) 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); goto close_error_exit; } 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; if (ioctl(fd,CHIOMOVE,&move)) { fprintf(stderr,PROG ": ioctl MOVE (unload): %s\n", strerror(errno)); goto close_error_exit; } } 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; if (ioctl(fd,CHIOMOVE,&move)) { fprintf(stderr,PROG ": ioctl MOVE (load): %s\n", strerror(errno)); goto close_error_exit; } if (eject_cdrom) cdrom_tray(devs[drive],0); printf("%s\t:%s\n",mopt,devs[drive]); exit(0); close_error_exit: if (eject_cdrom) cdrom_tray(devs[drive],0); exit(1); }