aboutsummaryrefslogtreecommitdiffstats
path: root/todo/autojuke.c
diff options
context:
space:
mode:
Diffstat (limited to 'todo/autojuke.c')
-rw-r--r--todo/autojuke.c355
1 files changed, 355 insertions, 0 deletions
diff --git a/todo/autojuke.c b/todo/autojuke.c
new file mode 100644
index 0000000..f6aa0b5
--- /dev/null
+++ b/todo/autojuke.c
@@ -0,0 +1,355 @@
+/*
+ * 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 <strings.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 <linux/chio.h>
+
+#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);
+ /*<bm*/
+}
+
+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,try_umount,cside,side;
+ FILE *fp;
+
+ if (argc != 2) {
+ fprintf(stderr,"Please use the automounter to run this program.");
+ 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 (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... */
+ 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);
+ }
+ }
+
+ /* 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;
+ /*<bm*/
+ if (ioctl(fd,CHIOMOVE,&move)) {
+ fprintf(stderr,PROG ": ioctl MOVE (unload): %s\n",
+ sys_errlist[errno]);
+ exit(1);
+ }
+ }
+
+ 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;
+
+ /*bm>*/
+ /* if current side is not requested side invert*/
+ move.cm_flags = (0 == side) ? 0 : CM_INVERT;
+ /*<bm*/
+ 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);
+}
+