Imported Upstream version 3.1.0
[debian/amanda] / changer-src / chg-scsi-chio.c
index 2ac644481f5776d0c31abf1a89e6d7cb3e7895e8..3489c67ef4730d35357495e3bbc3768e227d48da 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  $Id: chg-scsi-chio.c,v 1.1.2.3.6.3 2003/01/26 19:20:56 martinea Exp $
+ *  $Id: chg-scsi-chio.c,v 1.12 2006/07/25 18:18:46 martinea Exp $
  *
- *  chg-scsi.c -- generic SCSI changer driver
+ *  chg-scsi-chio.c -- generic SCSI changer driver
  *
  *  This program provides a driver to control generic
  *  SCSI changers, no matter what platform.  The host/OS
 #include "amanda.h"
 #include "conffile.h"
 #include "libscsi.h"
+#include "scsi-defs.h"
+int Tape_Ready1 ( char *tapedev , int wait);
 
 char *tapestatfile = NULL;
 
 /*----------------------------------------------------------------------------*/
-/* Some stuff for our own configurationfile */
-typedef struct {  /* The information we can get for any drive (configuration) */
-  int drivenum;      /* Which drive to use in the library */
-  int start;         /* Which is the first slot we may use */
-  int end;           /* The last slot we are allowed to use */
-  int cleanslot;     /* Where the cleaningcartridge stays */
-  char *scsitapedev; /* Where can we send raw SCSI commands to the tape */
-  char *device;      /* Which device is associated to the drivenum */
-  char *slotfile;    /* Where we should have our memory */   
-  char *cleanfile;   /* Where we count how many cleanings we did */
-  char *timefile;    /* Where we count the time the tape was used*/
-  char *tapestatfile;/* Where can we place some drive stats */
-}config_t; 
-
-typedef struct {
-  int number_of_configs; /* How many different configurations are used */
-  int eject;             /* Do the drives need an eject-command */
-  int sleep;             /* How many seconds to wait for the drive to get ready */
-  int cleanmax;          /* How many runs could be done with one cleaning tape */
-  char *device;          /* Which device is our changer */
-  config_t *conf;
-}changer_t;
 
 typedef enum{
   NUMDRIVE,EJECT,SLEEP,CLEANMAX,DRIVE,START,END,CLEAN,DEVICE,STATFILE,CLEANFILE,DRIVENUM,
@@ -92,124 +72,169 @@ typedef enum{
 
 typedef struct {
   char *word;
-  int token;
+  token_t token;
 } tokentable_t;
 
 tokentable_t t_table[]={
-  { "number_configs",NUMDRIVE},
-  { "eject",EJECT},
-  { "sleep",SLEEP},
-  { "cleanmax",CLEANMAX},
-  { "config",DRIVE},
-  { "startuse",START},
-  { "enduse",END},
-  { "cleancart",CLEAN},
-  { "dev",DEVICE},
-  { "statfile",STATFILE},
-  { "cleanfile",CLEANFILE},
-  { "drivenum",DRIVENUM},
-  { "changerdev",CHANGERDEV},
-  { "usagecount",USAGECOUNT},
-  { "scsitapedev", SCSITAPEDEV},
-  { "tapestatus", TAPESTATFILE},
-  { NULL,-1 }
+  { "number_configs",  NUMDRIVE},
+  { "eject",           EJECT},
+  { "sleep",           SLEEP},
+  { "cleanmax",                CLEANMAX},
+  { "config",          DRIVE},
+  { "startuse",                START},
+  { "enduse",          END},
+  { "cleancart",       CLEAN},
+  { "dev",             DEVICE},
+  { "statfile",                STATFILE},
+  { "cleanfile",       CLEANFILE},
+  { "drivenum",                DRIVENUM},
+  { "changerdev",      CHANGERDEV},
+  { "usagecount",      USAGECOUNT},
+  { "scsitapedev",     SCSITAPEDEV},
+  { "tapestatus",      TAPESTATFILE},
+  { NULL,              -1 }
 };
 
-void init_changer_struct(changer_t *chg,int number_of_config)
-     /* Initialize datasructures with default values */
+changer_t *changer;
+
+void   init_changer_struct(changer_t *chg, size_t number_of_config);
+void   dump_changer_struct(changer_t *chg);
+void   free_changer_struct(changer_t **changer);
+void   parse_line(char *linebuffer,int *token,char **value);
+int    read_config(char *configfile, changer_t *chg);
+int    get_current_slot(char *count_file);
+void   put_current_slot(char *count_file,int slot);
+void   usage(char *argv[]);
+int    get_relative_target(int fd,int nslots,char *parameter,int loaded, 
+                        char *changer_file,int slot_offset,int maxslot);
+int    is_positive_number(char *tmp);
+int    ask_clean(char *tapedev);
+void   clean_tape(int fd,char *tapedev,char *cnt_file, int drivenum, 
+                int cleancart, int maxclean,char *usagetime);
+int    main(int argc, char *argv[]);
+
+
+/*
+ * Initialize data structures with default values
+*/
+void
+init_changer_struct(
+    changer_t *        chg,
+    size_t     number_of_config)
 {
-  int i;
-  
+  size_t i;
+  memset(chg, 0, SIZEOF(*chg));
   chg->number_of_configs = number_of_config;
   chg->eject = 1;
   chg->sleep = 0;
   chg->cleanmax = 0;
   chg->device = NULL;
-  chg->conf = malloc(sizeof(config_t)*number_of_config);
-  if (chg->conf != NULL){
-    for (i=0; i < number_of_config; i++){
-      chg->conf[i].drivenum   = 0;
-      chg->conf[i].start      = -1;
-      chg->conf[i].end        = -1;
-      chg->conf[i].cleanslot  = -1;
-      chg->conf[i].device     = NULL;
-      chg->conf[i].slotfile   = NULL;
-      chg->conf[i].cleanfile  = NULL;
-      chg->conf[i].timefile  = NULL;
-      chg->conf[i].scsitapedev = NULL;
-      chg->conf[i].tapestatfile = NULL;
-    }
+  chg->conf = alloc(SIZEOF(config_t) * number_of_config);
+  for (i=0; i < number_of_config; i++){
+    chg->conf[i].drivenum     = 0;
+    chg->conf[i].start        = -1;
+    chg->conf[i].end          = -1;
+    chg->conf[i].cleanslot    = -1;
+    chg->conf[i].device       = NULL;
+    chg->conf[i].slotfile     = NULL;
+    chg->conf[i].cleanfile    = NULL;
+    chg->conf[i].timefile     = NULL;
+    chg->conf[i].scsitapedev  = NULL;
+    chg->conf[i].tapestatfile = NULL;
+    chg->conf[i].changerident = NULL;
+    chg->conf[i].tapeident    = NULL;
   }
 }
 
-void dump_changer_struct(changer_t chg)
-     /* Dump of information for debug */
+/*
+ * Dump of information for debug
+*/
+void
+dump_changer_struct(
+    changer_t *        chg)
 {
   int i;
 
-  dbprintf(("Number of configurations: %d\n",chg.number_of_configs));
-  dbprintf(("Tapes need eject: %s\n",(chg.eject>0?"Yes":"No")));
-  dbprintf(("Tapes need sleep: %d seconds\n",chg.sleep));
-  dbprintf(("Cleancycles     : %d\n",chg.cleanmax));
-  dbprintf(("Changerdevice   : %s\n",chg.device));
-  for (i=0; i<chg.number_of_configs; i++){
-    dbprintf(("Tapeconfig Nr: %d\n",i));
-    dbprintf(("  Drivenumber   : %d\n",chg.conf[i].drivenum));
-    dbprintf(("  Startslot     : %d\n",chg.conf[i].start));
-    dbprintf(("  Endslot       : %d\n",chg.conf[i].end));
-    dbprintf(("  Cleanslot     : %d\n",chg.conf[i].cleanslot));
-    if (chg.conf[i].device != NULL)
-      dbprintf(("  Devicename    : %s\n",chg.conf[i].device));
+  dbprintf(_("Number of configurations: %d\n"), chg->number_of_configs);
+  dbprintf(_("Tapes need eject: %s\n"), (chg->eject>0 ? _("Yes") : _("No")));
+  dbprintf(_("Tapes need sleep: %lld seconds\n"), (long long)chg->sleep);
+  dbprintf(_("Clean cycles    : %d\n"), chg->cleanmax);
+  dbprintf(_("Changer device  : %s\n"), chg->device);
+  for (i = 0; i < chg->number_of_configs; i++){
+    dbprintf(_("Tape config Nr: %d\n"), i);
+    dbprintf(_("  Drive number  : %d\n"), chg->conf[i].drivenum);
+    dbprintf(_("  Start slot    : %d\n"), chg->conf[i].start);
+    dbprintf(_("  End slot      : %d\n"), chg->conf[i].end);
+    dbprintf(_("  Clean slot    : %d\n"), chg->conf[i].cleanslot);
+    if (chg->conf[i].device != NULL)
+      dbprintf(_("  Device name   : %s\n"), chg->conf[i].device);
     else
-      dbprintf(("  Devicename    : none\n"));
-    if (chg.conf[i].scsitapedev != NULL)
-      dbprintf(("  SCSITapedev   : %s\n",chg.conf[i].scsitapedev));
+      dbprintf(_("  Device name   : none\n"));
+    if (chg->conf[i].scsitapedev != NULL)
+      dbprintf(_("  SCSI Tape dev : %s\n"), chg->conf[i].scsitapedev);
     else
-      dbprintf(("  SCSITapedev   : none\n"));
-    if (chg.conf[i].tapestatfile != NULL)
-      dbprintf(("  statfile      : %s\n", chg.conf[i].tapestatfile));
+      dbprintf(_("  SCSI Tape dev : none\n"));
+    if (chg->conf[i].tapestatfile != NULL)
+      dbprintf(_("  stat file     : %s\n"), chg->conf[i].tapestatfile);
     else
-      dbprintf(("  statfile      : none\n"));
-    if (chg.conf[i].slotfile != NULL)
-      dbprintf(("  Slotfile      : %s\n",chg.conf[i].slotfile));
+      dbprintf(_("  stat file     : none\n"));
+    if (chg->conf[i].slotfile != NULL)
+      dbprintf(_("  Slot file     : %s\n"), chg->conf[i].slotfile);
     else
-      dbprintf(("  Slotfile      : none\n"));
-    if (chg.conf[i].cleanfile != NULL)
-      dbprintf(("  Cleanfile     : %s\n",chg.conf[i].cleanfile));
+      dbprintf(_("  Slot file     : none\n"));
+    if (chg->conf[i].cleanfile != NULL)
+      dbprintf(_("  Clean file    : %s\n"), chg->conf[i].cleanfile);
     else
-      dbprintf(("  Cleanfile     : none\n"));
-    if (chg.conf[i].timefile != NULL)
-      dbprintf(("  Usagecount    : %s\n",chg.conf[i].timefile));
+      dbprintf(_("  Clean file    : none\n"));
+    if (chg->conf[i].timefile != NULL)
+      dbprintf(_("  Usage count   : %s\n"), chg->conf[i].timefile);
     else
-      dbprintf(("  Usagecount    : none\n"));
+      dbprintf(_("  Usage count   : none\n"));
   }
 }
 
-void free_changer_struct(changer_t *chg)
-     /* Free all allocated memory */
+/*
+ * Free all allocated memory
+ */
+void
+free_changer_struct(
+changer_t **changer)
 {
+  changer_t *chg;
   int i;
 
+  assert(changer != NULL);
+  assert(*changer != NULL);
+
+  chg = *changer;
   if (chg->device != NULL)
-    free(chg->device);
+    amfree(chg->device);
   for (i=0; i<chg->number_of_configs; i++){
     if (chg->conf[i].device != NULL)
-      free(chg->conf[i].device);
+      amfree(chg->conf[i].device);
     if (chg->conf[i].slotfile != NULL)
-      free(chg->conf[i].slotfile);
+      amfree(chg->conf[i].slotfile);
     if (chg->conf[i].cleanfile != NULL)
-      free(chg->conf[i].cleanfile);
+      amfree(chg->conf[i].cleanfile);
     if (chg->conf[i].timefile != NULL)
-      free(chg->conf[i].timefile);
+      amfree(chg->conf[i].timefile);
   }
   if (chg->conf != NULL)
-    free(chg->conf);
+    amfree(chg->conf);
   chg->conf = NULL;
   chg->device = NULL;
+  amfree(*changer);
 }
 
-void parse_line(char *linebuffer,int *token,char **value)
-     /* This function parses a line, and returns the token an value */
+/*
+ * This function parses a line, and returns a token and value
+ */
+void
+parse_line(
+    char *     linebuffer,
+    int *      token,
+    char **    value)
 {
   char *tok;
   int i;
@@ -235,14 +260,19 @@ void parse_line(char *linebuffer,int *token,char **value)
   return;
 }
 
-int read_config(char *configfile, changer_t *chg)
-     /* This function reads the specified configfile and fills the structure */
+/*
+ * This function reads the specified configfile and fills the structure
+*/
+int
+read_config(
+    char *     configfile,
+    changer_t *        chg)
 {
-  int numconf;
+  size_t numconf;
   FILE *file;
   int init_flag = 0;
-  int drivenum=0;
-  char *linebuffer = NULL;
+  size_t drivenum=0;
+  char *linebuffer;
   int token;
   char *value;
 
@@ -253,23 +283,26 @@ int read_config(char *configfile, changer_t *chg)
     return (-1);
   }
 
-  amfree(linebuffer);
-  while (NULL!=(linebuffer=agets(file))){
+  while (NULL != (linebuffer = agets(file))) {
+      if (linebuffer[0] == '\0') {
+       amfree(linebuffer);
+       continue;
+      }
       parse_line(linebuffer,&token,&value);
       if (token != -1){
         if (0==init_flag) {
           if (token != NUMDRIVE){
-            init_changer_struct(chg,numconf);
+            init_changer_struct(chg, numconf);
           } else {
             numconf = atoi(value);
-            init_changer_struct(chg,numconf);
+            init_changer_struct(chg, numconf);
           }
           init_flag=1;
         }
         switch (token){
-        case NUMDRIVE: if (atoi(value) != numconf)
-          fprintf(stderr,"Error: number_drives at wrong place, should be "\
-                  "first in file\n");
+        case NUMDRIVE: if ((size_t)atoi(value) != numconf)
+          g_fprintf(stderr,_("Error: number_drives at wrong place, should be "
+                  "first in file\n"));
         break;
         case EJECT:
           chg->eject = atoi(value);
@@ -292,75 +325,75 @@ int read_config(char *configfile, changer_t *chg)
         case DRIVE:
           drivenum = atoi(value);
           if(drivenum >= numconf){
-            fprintf(stderr,"Error: drive must be less than number_drives\n");
+            g_fprintf(stderr,_("Error: drive must be less than number_drives\n"));
           }
           break;
         case DRIVENUM:
           if (drivenum < numconf){
             chg->conf[drivenum].drivenum = atoi(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " drivenum ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " drivenum ignored\n"));
           }
           break;
         case START:
           if (drivenum < numconf){
             chg->conf[drivenum].start = atoi(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " startuse ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " startuse ignored\n"));
           }
           break;
         case END:
           if (drivenum < numconf){
             chg->conf[drivenum].end = atoi(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " enduse ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " enduse ignored\n"));
           }
           break;
         case CLEAN:
           if (drivenum < numconf){
             chg->conf[drivenum].cleanslot = atoi(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " cleanslot ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " cleanslot ignored\n"));
           }
           break;
         case DEVICE:
           if (drivenum < numconf){
             chg->conf[drivenum].device = stralloc(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " device ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " device ignored\n"));
           }
           break;
         case STATFILE:
           if (drivenum < numconf){
             chg->conf[drivenum].slotfile = stralloc(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " slotfile ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " slotfile ignored\n"));
           }
           break;
         case CLEANFILE:
           if (drivenum < numconf){
             chg->conf[drivenum].cleanfile = stralloc(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " cleanfile ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " cleanfile ignored\n"));
           }
           break;
         case USAGECOUNT:
           if (drivenum < numconf){
             chg->conf[drivenum].timefile = stralloc(value);
           } else {
-            fprintf(stderr,"Error: drive is not less than number_drives"\
-                    " usagecount ignored\n");
+            g_fprintf(stderr,_("Error: drive is not less than number_drives"
+                    " usagecount ignored\n"));
           }
           break;
         default:
-          fprintf(stderr,"Error: Unknown token\n");
+          g_fprintf(stderr,_("Error: Unknown token\n"));
           break;
         }
       }
@@ -383,11 +416,17 @@ int get_current_slot(char *count_file)
   FILE *inf;
   int retval;
   if ((inf=fopen(count_file,"r")) == NULL) {
-    fprintf(stderr, "%s: unable to open current slot file (%s)\n",
+    g_fprintf(stderr, _("%s: unable to open current slot file (%s)\n"),
             get_pname(), count_file);
     return 0;
   }
-  fscanf(inf,"%d",&retval);
+
+  if (fscanf(inf, "%d", &retval) != 1) {
+    g_fprintf(stderr, _("%s: unable to read current slot file (%s)\n"),
+            get_pname(), count_file);
+    retval = 0;
+  }
+
   fclose(inf);
   return retval;
 }
@@ -397,11 +436,11 @@ void put_current_slot(char *count_file,int slot)
   FILE *inf;
 
   if ((inf=fopen(count_file,"w")) == NULL) {
-    fprintf(stderr, "%s: unable to open current slot file (%s)\n",
+    g_fprintf(stderr, _("%s: unable to open current slot file (%s)\n"),
             get_pname(), count_file);
     exit(2);
   }
-  fprintf(inf, "%d\n", slot);
+  g_fprintf(inf, "%d\n", slot);
   fclose(inf);
 }
 
@@ -423,6 +462,8 @@ typedef struct com_stru
 } command;
 
 
+void   parse_args(int argc, char *argv[], command *rval);
+
 /* major command line args */
 #define COMCOUNT 5
 #define COM_SLOT 0
@@ -466,13 +507,13 @@ int is_positive_number(char *tmp) /* is the string a valid positive int? */
 void usage(char *argv[])
 {
   int cnt;
-  printf("%s: Usage error.\n", argv[0]);
+  g_printf(_("%s: Usage error.\n"), argv[0]);
   for (cnt=0; cnt < COMCOUNT; cnt++){
-    printf("      %s    %s",argv[0],argdefs[cnt].str);
+    g_printf("      %s    %s",argv[0],argdefs[cnt].str);
     if (argdefs[cnt].takesparam)
-      printf(" <param>\n");
+      g_printf(_(" <param>\n"));
     else
-      printf("\n");
+      g_printf("\n");
   }
   exit(2);
 }
@@ -481,30 +522,48 @@ void usage(char *argv[])
 void parse_args(int argc, char *argv[],command *rval)
 {
   int i=0;
-  if ((argc<2)||(argc>3))
+  if ((argc < 2) || (argc > 3)) {
     usage(argv);
+    /*NOTREACHED*/
+  }
+
   while ((i<COMCOUNT)&&(strcmp(argdefs[i].str,argv[1])))
     i++;
-  if (i==COMCOUNT)
+  if (i == COMCOUNT) {
     usage(argv);
+    /*NOTREACHED*/
+  }
   rval->command_code = argdefs[i].command_code;
   if (argdefs[i].takesparam) {
-    if (argc<3)
+    if (argc < 3) {
       usage(argv);
+      /*NOTREACHED*/
+    }
     rval->parameter=argv[2];      
   }
   else {
-    if (argc>2)
+    if (argc > 2) {
       usage(argv);
+      /*NOTREACHED*/
+    }
     rval->parameter=0;
   }
 }
 
 /* used to find actual slot number from keywords next, prev, first, etc */
-int get_relative_target(int fd,int nslots,char *parameter,int loaded, 
-                        char *changer_file,int slot_offset,int maxslot)
+int
+get_relative_target(
+    int                fd,
+    int                nslots,
+    char *     parameter,
+    int                loaded, 
+    char *     changer_file,
+    int                slot_offset,
+    int                maxslot)
 {
   int current_slot,i;
+
+  (void)loaded;                /* Quiet unused warning */
   if (changer_file != NULL)
     {
       current_slot=get_current_slot(changer_file);
@@ -519,52 +578,70 @@ int get_relative_target(int fd,int nslots,char *parameter,int loaded,
   }
 
   i=0;
-  while((i<SLOTCOUNT)&&(strcmp(slotdefs[i].str,parameter)))
+  while((i < SLOTCOUNT) && (strcmp(slotdefs[i].str,parameter)))
     i++;
 
   switch(i) {
   case SLOT_CUR:
-    return current_slot;
     break;
+
   case SLOT_NEXT:
     if (++current_slot==nslots+slot_offset)
       return slot_offset;
-    else
-      return current_slot;
     break;
+
   case SLOT_PREV:
     if (--current_slot<slot_offset)
       return maxslot;
-    else
-      return current_slot;
     break;
+
   case SLOT_FIRST:
     return slot_offset;
-    break;
+
   case SLOT_LAST:
     return maxslot;
-    break;
+
   default: 
-    printf("<none> no slot `%s'\n",parameter);
+    g_printf(_("<none> no slot `%s'\n"),parameter);
     close(fd);
     exit(2);
-  };
+    /*NOTREACHED*/
+  }
+  return current_slot;
 }
 
-int ask_clean(char *tapedev)
-     /* This function should ask the drive if it wants to be cleaned */
+/*
+ * This function should ask the drive if it wants to be cleaned
+ */
+int
+ask_clean(
+    char *     tapedev)
 {
   return get_clean_state(tapedev);
 }
 
-void clean_tape(int fd,char *tapedev,char *cnt_file, int drivenum, 
-                int cleancart, int maxclean,char *usagetime)
-     /* This function should move the cleaning cartridge into the drive */
+/*
+ * This function should move the cleaning cartridge into the drive
+ */
+void
+clean_tape(
+    int                fd,
+    char *     tapedev,
+    char *     cnt_file,
+    int                drivenum,
+    int                cleancart,
+    int                maxclean,
+    char *     usagetime)
 {
-  int counter=-1;
+  int counter;
+  char *mailer;
+
   if (cleancart == -1 ){
     return;
   }
+
+  mailer = getconf_str(CNF_MAILER);
+
   /* Now we should increment the counter */
   if (cnt_file != NULL){
     counter = get_current_slot(cnt_file);
@@ -573,25 +650,42 @@ void clean_tape(int fd,char *tapedev,char *cnt_file, int drivenum,
       /* Now we should inform the administrator */
       char *mail_cmd;
       FILE *mailf;
-      mail_cmd = vstralloc(MAILER,
-                           " -s", " \"", "AMANDA PROBLEM: PLEASE FIX", "\"",
-                           " ", getconf_str(CNF_MAILTO),
-                           NULL);
-      if((mailf = popen(mail_cmd, "w")) == NULL){
-        error("could not open pipe to \"%s\": %s",
-              mail_cmd, strerror(errno));
-        printf("Mail failed\n");
-        return;
+      int mail_pipe_opened = 1;
+      if (mailer && *mailer != '\0') {
+        if (getconf_seen(CNF_MAILTO) && strlen(getconf_str(CNF_MAILTO)) > 0 && 
+           validate_mailto(getconf_str(CNF_MAILTO))) {
+          mail_cmd = vstralloc(mailer,
+                             " -s", " \"", _("AMANDA PROBLEM: PLEASE FIX"), "\"",
+                             " ", getconf_str(CNF_MAILTO),
+                             NULL);
+          if ((mailf = popen(mail_cmd, "w")) == NULL) {
+                 g_printf(_("Mail failed\n"));
+                 error(_("could not open pipe to \"%s\": %s"),
+                       mail_cmd, strerror(errno));
+                 /*NOTREACHED*/
+         }
+        } else {
+          mail_pipe_opened = 0;
+          mailf = stderr;
+           g_fprintf(mailf, _("\nNo mail recipient specified, output redirected to stderr"));
+        }
+      } else {
+        mail_pipe_opened = 0;
+        mailf = stderr;
+        g_fprintf(mailf, _("\nNo mailer specified; output redirected to stderr"));
       }
-      fprintf(mailf,"\nThe usage count of your cleaning tape in slot %d",
-              cleancart);
-      fprintf(mailf,"\nis more than %d. (cleanmax)",maxclean);
-      fprintf(mailf,"\nTapedrive %s needs to be cleaned",tapedev);
-      fprintf(mailf,"\nPlease insert a new cleaning tape and reset");
-      fprintf(mailf,"\nthe countingfile %s",cnt_file);
-
-      if(pclose(mailf) != 0)
-        error("mail command failed: %s", mail_cmd);
+      g_fprintf(mailf, _("\nThe usage count of your cleaning tape in slot %d"),
+             cleancart);
+      g_fprintf(mailf,_("\nis more than %d. (cleanmax)"),maxclean);
+      g_fprintf(mailf,_("\nTapedrive %s needs to be cleaned"),tapedev);
+      g_fprintf(mailf,_("\nPlease insert a new cleaning tape and reset"));
+      g_fprintf(mailf,_("\nthe countingfile %s"),cnt_file);
+
+      if(mail_pipe_opened == 1 && pclose(mailf) != 0) {
+        error(_("mail command failed: %s"), mail_cmd);
+               /*NOTREACHED*/
+      }
+      
 
       return;
     }
@@ -605,11 +699,15 @@ void clean_tape(int fd,char *tapedev,char *cnt_file, int drivenum,
 }
 /* ----------------------------------------------------------------------*/
 
-int main(int argc, char *argv[])
+int
+main(
+    int                argc,
+    char **    argv)
 {
-  int loaded,target,oldtarget;
+  int loaded;
+  int target = -1;
+  int oldtarget;
   command com;   /* a little DOS joke */
-  changer_t chg;
   
   /*
    * drive_num really should be something from the config file, but..
@@ -619,7 +717,7 @@ int main(int argc, char *argv[])
    */
   int    drive_num = 0;
   int need_eject = 0; /* Does the drive need an eject command ? */
-  int need_sleep = 0; /* How many seconds to wait for the drive to get ready */
+  unsigned need_sleep = 0; /* How many seconds to wait for the drive to get ready */
   int clean_slot = -1;
   int maxclean = 0;
   char *clean_file=NULL;
@@ -629,61 +727,81 @@ int main(int argc, char *argv[])
   int slot_offset;
   int confnum;
 
-  int fd, rc, slotcnt, drivecnt;
+  int fd, slotcnt, drivecnt;
   int endstatus = 0;
-  char *changer_dev, *tape_device;
+  char *changer_dev = NULL;
+  char *tape_device = NULL;
   char *changer_file = NULL;
   char *scsitapedevice = NULL;
 
+  /*
+   * Configure program for internationalization:
+   *   1) Only set the message locale for now.
+   *   2) Set textdomain for all amanda related programs to "amanda"
+   *      We don't want to be forced to support dozens of message catalogs.
+   */  
+  setlocale(LC_MESSAGES, "C");
+  textdomain("amanda"); 
+
   set_pname("chg-scsi");
-  dbopen();
+
+  /* Don't die when child closes pipe */
+  signal(SIGPIPE, SIG_IGN);
+
+  dbopen(DBG_SUBDIR_SERVER);
   parse_args(argc,argv,&com);
 
-  if(read_conffile(CONFFILE_NAME)) {
-    fprintf(stderr, "%s: could not find config file \"%s\"",
-                   changer_dev, conffile);
-    exit(1);
+  changer = alloc(SIZEOF(changer_t));
+  config_init(CONFIG_INIT_USE_CWD, NULL);
+
+  if (config_errors(NULL) >= CFGERR_WARNINGS) {
+    config_print_errors();
+    if (config_errors(NULL) >= CFGERR_ERRORS) {
+      g_critical(_("errors processing config file"));
+    }
   }
 
-  changer_dev = getconf_str(CNF_CHNGRDEV);
-  changer_file = getconf_str(CNF_CHNGRFILE);
+  changer_dev = getconf_str(CNF_CHANGERDEV);
+  changer_file = getconf_str(CNF_CHANGERFILE);
   tape_device = getconf_str(CNF_TAPEDEV);
 
   /* Get the configuration parameters */
+
   if (strlen(tape_device)==1){
-    read_config(changer_file,&chg);
+    read_config(changer_file, changer);
     confnum=atoi(tape_device);
-    use_slots    = chg.conf[confnum].end-chg.conf[confnum].start+1;
-    slot_offset  = chg.conf[confnum].start;
-    drive_num    = chg.conf[confnum].drivenum;
-    need_eject   = chg.eject;
-    need_sleep   = chg.sleep;
-    clean_file   = stralloc(chg.conf[confnum].cleanfile);
-    clean_slot   = chg.conf[confnum].cleanslot;
-    maxclean     = chg.cleanmax;
-    if (NULL != chg.conf[confnum].timefile)
-      time_file = stralloc(chg.conf[confnum].timefile);
-    if (NULL != chg.conf[confnum].slotfile)
-      changer_file = stralloc(chg.conf[confnum].slotfile);
+    use_slots    = changer->conf[confnum].end-changer->conf[confnum].start+1;
+    slot_offset  = changer->conf[confnum].start;
+    drive_num    = changer->conf[confnum].drivenum;
+    need_eject   = changer->eject;
+    need_sleep   = changer->sleep;
+    clean_file   = stralloc(changer->conf[confnum].cleanfile);
+    clean_slot   = changer->conf[confnum].cleanslot;
+    maxclean     = changer->cleanmax;
+    if (NULL != changer->conf[confnum].timefile)
+      time_file = stralloc(changer->conf[confnum].timefile);
+    if (NULL != changer->conf[confnum].slotfile)
+      changer_file = stralloc(changer->conf[confnum].slotfile);
     else
       changer_file = NULL;
-    if (NULL != chg.conf[confnum].device)
-      tape_device  = stralloc(chg.conf[confnum].device);
-    if (NULL != chg.device)
-      changer_dev  = stralloc(chg.device); 
-    if (NULL != chg.conf[confnum].scsitapedev)
-      scsitapedevice = stralloc(chg.conf[confnum].scsitapedev);
-    if (NULL != chg.conf[confnum].tapestatfile)
-      tapestatfile = stralloc(chg.conf[confnum].tapestatfile);
-    dump_changer_struct(chg);
+    if (NULL != changer->conf[confnum].device)
+      tape_device  = stralloc(changer->conf[confnum].device);
+    if (NULL != changer->device)
+      changer_dev  = stralloc(changer->device); 
+    if (NULL != changer->conf[confnum].scsitapedev)
+      scsitapedevice = stralloc(changer->conf[confnum].scsitapedev);
+    if (NULL != changer->conf[confnum].tapestatfile)
+      tapestatfile = stralloc(changer->conf[confnum].tapestatfile);
+    dump_changer_struct(changer);
     /* get info about the changer */
-    if (-1 == (fd = OpenDevice(changer_dev, "changer_dev"))) {
+    fd = OpenDevice(INDEX_CHANGER , changer_dev,
+                       "changer_dev", changer->conf[confnum].changerident);
+    if (fd == -1) {
       int localerr = errno;
-      fprintf(stderr, "%s: open: %s: %s\n", get_pname(), 
+      g_fprintf(stderr, _("%s: open: %s: %s\n"), get_pname(), 
               changer_dev, strerror(localerr));
-      printf("%s open: %s: %s\n", "<none>", changer_dev, strerror(localerr));
-      dbprintf(("%s: open: %s: %s\n", get_pname(),
-                changer_dev, strerror(localerr)));
+      g_printf(_("%s open: %s: %s\n"), "<none>", changer_dev, strerror(localerr));
+      dbprintf(_("open: %s: %s\n"), changer_dev, strerror(localerr));
       return 2;
     }
 
@@ -697,21 +815,23 @@ int main(int argc, char *argv[])
          scsitapedevice = stralloc(tape_device);
       }
 
-    if ((chg.conf[confnum].end == -1) || (chg.conf[confnum].start == -1)){
+    if ((changer->conf[confnum].end == -1) || (changer->conf[confnum].start == -1)){
       slotcnt = get_slot_count(fd);
       use_slots    = slotcnt;
       slot_offset  = 0;
     }
-    free_changer_struct(&chg);
+    free_changer_struct(&changer);
   } else {
     /* get info about the changer */
-    if (-1 == (fd = OpenDevice(changer_dev))) {
+    confnum = 0;
+    fd = OpenDevice(INDEX_CHANGER , changer_dev,
+                       "changer_dev", changer->conf[confnum].changerident);
+    if (fd == -1) {
       int localerr = errno;
-      fprintf(stderr, "%s: open: %s: %s\n", get_pname(), 
+      g_fprintf(stderr, _("%s: open: %s: %s\n"), get_pname(), 
               changer_dev, strerror(localerr));
-      printf("%s open: %s: %s\n", "<none>", changer_dev, strerror(localerr));
-      dbprintf(("%s: open: %s: %s\n", get_pname(),
-                changer_dev, strerror(localerr)));
+      g_printf(_("%s open: %s: %s\n"), _("<none>"), changer_dev, strerror(localerr));
+      dbprintf(_("open: %s: %s\n"), changer_dev, strerror(localerr));
       return 2;
     }
     slotcnt = get_slot_count(fd);
@@ -725,14 +845,13 @@ int main(int argc, char *argv[])
   drivecnt = get_drive_count(fd);
 
   if (drive_num > drivecnt) {
-    printf("%s drive number error (%d > %d)\n", "<none>"
+    g_printf(_("%s drive number error (%d > %d)\n"), _("<none>")
            drive_num, drivecnt);
-    fprintf(stderr, "%s: requested drive number (%d) greater than "
-            "number of supported drives (%d)\n", get_pname(), 
+    g_fprintf(stderr, _("%s: requested drive number (%d) greater than "
+            "number of supported drives (%d)\n"), get_pname(), 
             drive_num, drivecnt);
-    dbprintf(("%s: requested drive number (%d) greater than "
-              "number of supported drives (%d)\n", get_pname(), 
-              drive_num, drivecnt));
+    dbprintf(_("requested drive number (%d) greater than "
+              "number of supported drives (%d)\n"), drive_num, drivecnt);
     CloseDevice("", fd);
     return 2;
   }
@@ -743,7 +862,7 @@ int main(int argc, char *argv[])
   case COM_SLOT:  /* slot changing command */
     if (is_positive_number(com.parameter)) {
       if ((target = atoi(com.parameter))>=use_slots) {
-        printf("<none> no slot `%d'\n",target);
+        g_printf(_("<none> no slot `%d'\n"),target);
         close(fd);
         endstatus = 2;
         break;
@@ -777,7 +896,7 @@ int main(int argc, char *argv[])
       put_current_slot(changer_file, target);
     }
     if (!loaded && isempty(fd, target)) {
-      printf("%d slot %d is empty\n",target-slot_offset,
+      g_printf(_("%d slot %d is empty\n"),target-slot_offset,
              target-slot_offset);
       close(fd);
       endstatus = 1;
@@ -785,25 +904,25 @@ int main(int argc, char *argv[])
     }
     if (!loaded)
       if (load(fd, drive_num, target) != 0) {
-        printf("%d slot %d move failed\n",target-slot_offset,
+        g_printf(_("%d slot %d move failed\n"),target-slot_offset,
                target-slot_offset);  
         close(fd);
         endstatus = 2;
         break;
       }
     if (need_sleep)
-      Tape_Ready(scsitapedevice, need_sleep);
-    printf("%d %s\n", target-slot_offset, tape_device);
+      Tape_Ready1(scsitapedevice, need_sleep);
+    g_printf(_("%d %s\n"), target-slot_offset, tape_device);
     break;
 
   case COM_INFO:
     if (changer_file != NULL)
       {
-        printf("%d ", get_current_slot(changer_file)-slot_offset);
+        g_printf("%d ", get_current_slot(changer_file)-slot_offset);
       } else {
-        printf("%d ", GetCurrentSlot(fd, drive_num)-slot_offset);
+        g_printf("%d ", GetCurrentSlot(fd, drive_num)-slot_offset);
       }
-    printf("%d 1\n", use_slots);
+    g_printf("%d 1\n", use_slots);
     break;
 
   case COM_RESET:
@@ -825,14 +944,14 @@ int main(int argc, char *argv[])
     }
 
     if (isempty(fd, slot_offset)) {
-      printf("0 slot 0 is empty\n");
+      g_printf(_("0 slot 0 is empty\n"));
       close(fd);
       endstatus = 1;
       break;
     }
 
     if (load(fd, drive_num, slot_offset) != 0) {
-      printf("%d slot %d move failed\n",slot_offset,
+      g_printf(_("%d slot %d move failed\n"),slot_offset,
              slot_offset);  
       close(fd);
       endstatus = 2;
@@ -843,12 +962,12 @@ int main(int argc, char *argv[])
       put_current_slot(changer_file, slot_offset);
     }
     if (need_sleep)
-      Tape_Ready(scsitapedevice, need_sleep);
+      Tape_Ready1(scsitapedevice, need_sleep);
     if (changer_file != NULL)
       {
-        printf("%d %s\n", get_current_slot(changer_file), tape_device);
+        g_printf("%d %s\n", get_current_slot(changer_file), tape_device);
       } else {
-        printf("%d %s\n", GetCurrentSlot(fd, drive_num), tape_device);
+        g_printf("%d %s\n", GetCurrentSlot(fd, drive_num), tape_device);
       }
     break;
 
@@ -866,9 +985,9 @@ int main(int argc, char *argv[])
       if (ask_clean(scsitapedevice))
         clean_tape(fd,tape_device,clean_file,drive_num,clean_slot,
                    maxclean,time_file);
-      printf("%d %s\n", target, tape_device);
+      g_printf("%d %s\n", target, tape_device);
     } else {
-      printf("%d %s\n", target, "drive was not loaded");
+      g_printf(_("%d drive was not loaded\n"), target);
       endstatus = 1;
     }
     break;
@@ -886,7 +1005,7 @@ int main(int argc, char *argv[])
     } 
     clean_tape(fd,tape_device,clean_file,drive_num,clean_slot,
                maxclean,time_file);
-    printf("%s cleaned\n", tape_device);
+    g_printf(_("%s cleaned\n"), tape_device);
     break;
   };