aboutsummaryrefslogtreecommitdiffstats
path: root/autojuke.c
diff options
context:
space:
mode:
Diffstat (limited to 'autojuke.c')
-rw-r--r--autojuke.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/autojuke.c b/autojuke.c
new file mode 100644
index 0000000..c27f135
--- /dev/null
+++ b/autojuke.c
@@ -0,0 +1,344 @@
+/*
+ * program "map-file" for linux autofs
+ *
+ * usage: /usr/sbin/automount /jukebox program /usr/sbin/autojuke
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <asm/types.h>
+#include <linux/cdrom.h>
+
+#include "chio.h"
+
+#define PROG "autojuke"
+#define CHANGER "/dev/sch0"
+#define CONFIG "/etc/autojuke.conf"
+
+#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;
+}
+
+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,&params)) {
+ 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);
+}