Example #1
0
bool RUNSCRIPT::run(JCR *jcr, const char *name)
{
   Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type);
   POOLMEM *ecmd = get_pool_memory(PM_FNAME);
   int status;
   BPIPE *bpipe;
   POOL_MEM line(PM_NAME);

   ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback);
   Dmsg1(100, "runscript: running '%s'...\n", ecmd);
   Jmsg(jcr, M_INFO, 0, _("%s: run %s \"%s\"\n"),
        cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd);

   switch (cmd_type) {
   case SHELL_CMD:
      bpipe = open_bpipe(ecmd, 0, "r");
      free_pool_memory(ecmd);

      if (bpipe == NULL) {
         berrno be;
         Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
            be.bstrerror());
         goto bail_out;
      }

      while (fgets(line.c_str(), line.size(), bpipe->rfd)) {
         strip_trailing_junk(line.c_str());
         Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line.c_str());
      }

      status = close_bpipe(bpipe);

      if (status != 0) {
         berrno be;
         Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
            be.code(status), be.bstrerror(status));
         goto bail_out;
      }

      Dmsg0(100, "runscript OK\n");
      break;
   case CONSOLE_CMD:
      if (console_command) {                 /* can we run console command? */
         if (!console_command(jcr, ecmd)) {  /* yes, do so */
            goto bail_out;
         }
      }
      break;
   }
   return true;

bail_out:
   /* cancel running job properly */
   if (fail_on_error) {
      jcr->setJobStatus(JS_ErrorTerminated);
   }
   Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
   return false;
}
Example #2
0
int do_shell_expansion(char *name, int name_len)
{
   static char meta[] = "~\\$[]*?`'<>\"";
   bool found = false;
   int len, i, status;
   POOLMEM *cmd;
   BPIPE *bpipe;
   char line[MAXSTRING];
   const char *shellcmd;

   /* Check if any meta characters are present */
   len = strlen(meta);
   for (i = 0; i < len; i++) {
      if (strchr(name, meta[i])) {
         found = true;
         break;
      }
   }
   if (found) {
      cmd =  get_pool_memory(PM_FNAME);
      /* look for shell */
      if ((shellcmd = getenv("SHELL")) == NULL) {
         shellcmd = "/bin/sh";
      }
      pm_strcpy(&cmd, shellcmd);
      pm_strcat(&cmd, " -c \"echo ");
      pm_strcat(&cmd, name);
      pm_strcat(&cmd, "\"");
      Dmsg1(400, "Send: %s\n", cmd);
      if ((bpipe = open_bpipe(cmd, 0, "r"))) {
         *line = 0;
         fgets(line, sizeof(line), bpipe->rfd);
         strip_trailing_junk(line);
         status = close_bpipe(bpipe);
         Dmsg2(400, "status=%d got: %s\n", status, line);
      } else {
         status = 1;                    /* error */
      }
      free_pool_memory(cmd);
      if (status == 0) {
         bstrncpy(name, line, name_len);
      }
   }
   return 1;
}
Example #3
0
/*
 * Run an external program. Optionally wait a specified number
 *   of seconds. Program killed if wait exceeded. Optionally
 *   return the output from the program (normally a single line).
 *
 *   If the watchdog kills the program, fgets returns, and ferror is set
 *   to 1 (=>SUCCESS), so we check if the watchdog killed the program.
 *
 * Contrary to my normal calling conventions, this program
 *
 *  Returns: 0 on success
 *           non-zero on error == berrno status
 */
int run_program(char *prog, int wait, POOLMEM *&results)
{
   BPIPE *bpipe;
   int stat1, stat2;
   char *mode;

   mode = (char *)"r";
   bpipe = open_bpipe(prog, wait, mode);
   if (!bpipe) {
      return ENOENT;
   }
   results[0] = 0;
   int len = sizeof_pool_memory(results) - 1;
   fgets(results, len, bpipe->rfd);
   results[len] = 0;
   if (feof(bpipe->rfd)) {
      stat1 = 0;
   } else {
      stat1 = ferror(bpipe->rfd);
   }
   if (stat1 < 0) {
      berrno be;
      Dmsg2(150, "Run program fgets stat=%d ERR=%s\n", stat1, be.bstrerror(errno));
   } else if (stat1 != 0) {
      Dmsg1(150, "Run program fgets stat=%d\n", stat1);
      if (bpipe->timer_id) {
         Dmsg1(150, "Run program fgets killed=%d\n", bpipe->timer_id->killed);
         /* NB: I'm not sure it is really useful for run_program. Without the
          * following lines run_program would not detect if the program was killed
          * by the watchdog. */
         if (bpipe->timer_id->killed) {
            stat1 = ETIME;
            pm_strcpy(results, _("Program killed by Bacula (timeout)\n"));
         }
      }
   }
   stat2 = close_bpipe(bpipe);
   stat1 = stat2 != 0 ? stat2 : stat1;
   Dmsg1(150, "Run program returning %d\n", stat1);
   return stat1;
}
Example #4
0
/*
 * This job is done, so release the device. From a Unix standpoint,
 *  the device remains open.
 *
 * Note, if we were spooling, we may enter with the device blocked.
 *   We unblock at the end, only if it was us who blocked the
 *   device.
 *
 */
bool release_device(DCR *dcr)
{
   utime_t now;
   JCR *jcr = dcr->jcr;
   DEVICE *dev = dcr->dev;
   bool ok = true;
   char tbuf[100];
   int was_blocked = BST_NOT_BLOCKED;

   /*
    * Capture job statistics now that we are done using this device.
    */
   now = (utime_t)time(NULL);
   update_job_statistics(jcr, now);

   dev->Lock();
   if (!dev->is_blocked()) {
      block_device(dev, BST_RELEASING);
   } else {
      was_blocked = dev->blocked();
      dev->set_blocked(BST_RELEASING);
   }
   lock_volumes();
   Dmsg2(100, "release_device device %s is %s\n", dev->print_name(), dev->is_tape() ? "tape" : "disk");

   /*
    * If device is reserved, job never started, so release the reserve here
    */
   dcr->clear_reserved();

   if (dev->can_read()) {
      VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
      dev->clear_read();              /* clear read bit */
      Dmsg2(150, "dir_update_vol_info. label=%d Vol=%s\n",
         dev->is_labeled(), vol->VolCatName);
      if (dev->is_labeled() && vol->VolCatName[0] != 0) {
         dcr->dir_update_volume_info(false, false); /* send Volume info to Director */
         remove_read_volume(jcr, dcr->VolumeName);
         volume_unused(dcr);
      }
   } else if (dev->num_writers > 0) {
      /*
       * Note if WEOT is set, we are at the end of the tape and may not be positioned correctly,
       * so the job_media_record and update_vol_info have already been done,
       * which means we skip them here.
       */
      dev->num_writers--;
      Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers);
      if (dev->is_labeled()) {
         Dmsg2(200, "dir_create_jobmedia. Release vol=%s dev=%s\n",
               dev->getVolCatName(), dev->print_name());
         if (!dev->at_weot() && !dcr->dir_create_jobmedia_record(false)) {
            Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
               dcr->getVolCatName(), jcr->Job);
         }

         /*
          * If no more writers, and no errors, and wrote something, write an EOF
          */
         if (!dev->num_writers && dev->can_write() && dev->block_num > 0) {
            dev->weof(1);
            write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName);
         }
         if (!dev->at_weot()) {
            dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */

            /*
             * Note! do volume update before close, which zaps VolCatInfo
             */
            dcr->dir_update_volume_info(false, false); /* send Volume info to Director */
            Dmsg2(200, "dir_update_vol_info. Release vol=%s dev=%s\n",
                  dev->getVolCatName(), dev->print_name());
         }
         if (dev->num_writers == 0) {         /* if not being used */
            volume_unused(dcr);               /*  we obviously are not using the volume */
         }
      }

   } else {
      /*
       * If we reach here, it is most likely because the job has failed,
       * since the device is not in read mode and there are no writers.
       * It was probably reserved.
       */
      volume_unused(dcr);
   }

   Dmsg3(100, "%d writers, %d reserve, dev=%s\n", dev->num_writers, dev->num_reserved(), dev->print_name());

   /*
    * If no writers, close if file or !CAP_ALWAYS_OPEN
    */
   if (dev->num_writers == 0 && (!dev->is_tape() || !dev->has_cap(CAP_ALWAYSOPEN))) {
      dev->close(dcr);
      free_volume(dev);
   }

   unlock_volumes();

   /*
    * Fire off Alert command and include any output
    */
   if (!job_canceled(jcr)) {
      if (!dcr->device->drive_tapealert_enabled && dcr->device->alert_command) {
         int status = 1;
         POOLMEM *alert, *line;
         BPIPE *bpipe;

         alert = get_pool_memory(PM_FNAME);
         line = get_pool_memory(PM_FNAME);

         alert = edit_device_codes(dcr, alert, dcr->device->alert_command, "");

         /*
          * Wait maximum 5 minutes
          */
         bpipe = open_bpipe(alert, 60 * 5, "r");
         if (bpipe) {
            while (bfgets(line, bpipe->rfd)) {
               Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line);
            }
            status = close_bpipe(bpipe);
         } else {
            status = errno;
         }
         if (status != 0) {
            berrno be;
            Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"), alert, be.bstrerror(status));
         }

         Dmsg1(400, "alert status=%d\n", status);
         free_pool_memory(alert);
         free_pool_memory(line);
      } else {
         /*
          * If all reservations are cleared for this device raise an event that SD plugins can register to.
          */
         if (dev->num_reserved() == 0) {
            generate_plugin_event(jcr, bsdEventDeviceReleased, dcr);
         }
      }
   }

   pthread_cond_broadcast(&dev->wait_next_vol);
   Dmsg2(100, "JobId=%u broadcast wait_device_release at %s\n",
         (uint32_t)jcr->JobId, bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
   release_device_cond();

   /*
    * If we are the thread that blocked the device, then unblock it
    */
   if (pthread_equal(dev->no_wait_id, pthread_self())) {
      dev->dunblock(true);
   } else {
      /*
       * Otherwise, reset the prior block status and unlock
       */
      dev->set_blocked(was_blocked);
      dev->Unlock();
   }

   if (dcr->keep_dcr) {
      detach_dcr_from_dev(dcr);
   } else {
      free_dcr(dcr);
   }

   Dmsg2(100, "Device %s released by JobId=%u\n", dev->print_name(), (uint32_t)jcr->JobId);

   return ok;
}
Example #5
0
/*
 * Open a new configuration file. We push the
 * state of the current file (lf) so that we
 * can do includes.  This is a bit of a hammer.
 * Instead of passing back the pointer to the
 * new packet, I simply replace the contents
 * of the caller's packet with the new packet,
 * and link the contents of the old packet into
 * the next field.
 */
LEX *lex_open_file(LEX *lf,
                   const char *filename,
                   LEX_ERROR_HANDLER *scan_error,
                   LEX_WARNING_HANDLER *scan_warning)
{
   FILE *fd;
   BPIPE *bpipe = NULL;
   char *bpipe_filename = NULL;

   if (filename[0] == '|') {
      bpipe_filename = bstrdup(filename);
      if ((bpipe = open_bpipe(bpipe_filename + 1, 0, "rb")) == NULL) {
         free(bpipe_filename);
         return NULL;
      }
      free(bpipe_filename);
      fd = bpipe->rfd;
      return lex_add(lf, filename, fd, bpipe, scan_error, scan_warning);
   } else {
#ifdef HAVE_GLOB
      int globrc;
      glob_t fileglob;
      char *filename_expanded = NULL;

      /*
       * Flag GLOB_NOMAGIC is a GNU extension, therefore manually check if string is a wildcard string.
       */

      /*
       * Clear fileglob at least required for mingw version of glob()
       */
      memset(&fileglob, 0, sizeof(fileglob));
      globrc = glob(filename, 0, NULL, &fileglob);

      if ((globrc == GLOB_NOMATCH) && (is_wildcard_string(filename))) {
         /*
          * fname is a wildcard string, but no matching files have been found.
          * Ignore this include statement and continue.
          */
         return lf;
      } else if (globrc != 0) {
         /*
          * glob() error has occurred. Giving up.
          */
         return NULL;
      }

      Dmsg2(100, "glob %s: %i files\n", filename, fileglob.gl_pathc);
      for (size_t i = 0; i < fileglob.gl_pathc; i++) {
         filename_expanded = fileglob.gl_pathv[i];
         if ((fd = fopen(filename_expanded, "rb")) == NULL) {
            globfree(&fileglob);
            return NULL;
         }
         lf = lex_add(lf, filename_expanded, fd, bpipe, scan_error, scan_warning);
      }
      globfree(&fileglob);
#else
      if ((fd = fopen(filename, "rb")) == NULL) {
         return NULL;
      }
      lf = lex_add(lf, filename, fd, bpipe, scan_error, scan_warning);
#endif
      return lf;
   }
}
Example #6
0
void update_bootstrap_file(JCR *jcr)
{
   /* Now update the bootstrap file if any */
   if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes &&
       jcr->job->WriteBootstrap) {
      FILE *fd;
      BPIPE *bpipe = NULL;
      int got_pipe = 0;
      POOLMEM *fname = get_pool_memory(PM_FNAME);
      fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "");

      VOL_PARAMS *VolParams = NULL;
      int VolCount;
      char edt[50], ed1[50], ed2[50];

      if (*fname == '|') {
         got_pipe = 1;
         bpipe = open_bpipe(fname+1, 0, "w"); /* skip first char "|" */
         fd = bpipe ? bpipe->wfd : NULL;
      } else {
         /* ***FIXME*** handle BASE */
         fd = fopen(fname, jcr->get_JobLevel()==L_FULL?"w+b":"a+b");
      }
      if (fd) {
         VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,
                    &VolParams);
         if (VolCount == 0) {
            Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters to "
                 "update Bootstrap file. ERR=%s\n"), db_strerror(jcr->db));
             if (jcr->SDJobFiles != 0) {
                set_jcr_job_status(jcr, JS_ErrorTerminated);
             }

         }
         /* Start output with when and who wrote it */
         bstrftimes(edt, sizeof(edt), time(NULL));
         fprintf(fd, "# %s - %s - %s%s\n", edt, jcr->jr.Job,
                 level_to_str(jcr->get_JobLevel()), jcr->since);
         for (int i=0; i < VolCount; i++) {
            /* Write the record */
            fprintf(fd, "Volume=\"%s\"\n", VolParams[i].VolumeName);
            fprintf(fd, "MediaType=\"%s\"\n", VolParams[i].MediaType);
            if (VolParams[i].Slot > 0) {
               fprintf(fd, "Slot=%d\n", VolParams[i].Slot);
            }
            fprintf(fd, "VolSessionId=%u\n", jcr->VolSessionId);
            fprintf(fd, "VolSessionTime=%u\n", jcr->VolSessionTime);
            fprintf(fd, "VolAddr=%s-%s\n", 
                    edit_uint64(VolParams[i].StartAddr, ed1),
                    edit_uint64(VolParams[i].EndAddr, ed2));
            fprintf(fd, "FileIndex=%d-%d\n", VolParams[i].FirstIndex,
                         VolParams[i].LastIndex);
         }
         if (VolParams) {
            free(VolParams);
         }
         if (got_pipe) {
            close_bpipe(bpipe);
         } else {
            fclose(fd);
         }
      } else {
         berrno be;
         Jmsg(jcr, M_ERROR, 0, _("Could not open WriteBootstrap file:\n"
              "%s: ERR=%s\n"), fname, be.bstrerror());
         set_jcr_job_status(jcr, JS_ErrorTerminated);
      }
      free_pool_memory(fname);
   }
}
Example #7
0
/*
 * Run an external program. Optionally wait a specified number
 *   of seconds. Program killed if wait exceeded (it is done by the
 *   watchdog, as fgets is a blocking function).
 *
 *   If the watchdog kills the program, fgets returns, and ferror is set
 *   to 1 (=>SUCCESS), so we check if the watchdog killed the program.
 *
 *   Return the full output from the program (not only the first line).
 *
 * Contrary to my normal calling conventions, this program
 *
 *  Returns: 0 on success
 *           non-zero on error == berrno status
 *
 */
int run_program_full_output(char *prog, int wait, POOLMEM *&results)
{
   BPIPE *bpipe;
   int stat1, stat2;
   char *mode;
   POOLMEM* tmp;
   char *buf;
   const int bufsize = 32000;


   Dsm_check(200);

   tmp = get_pool_memory(PM_MESSAGE);
   buf = (char *)malloc(bufsize+1);

   results[0] = 0;
   mode = (char *)"r";
   bpipe = open_bpipe(prog, wait, mode);
   if (!bpipe) {
      stat1 = ENOENT;
      goto bail_out;
   }

   Dsm_check(200);
   tmp[0] = 0;
   while (1) {
      buf[0] = 0;
      fgets(buf, bufsize, bpipe->rfd);
      buf[bufsize] = 0;
      pm_strcat(tmp, buf);
      if (feof(bpipe->rfd)) {
         stat1 = 0;
         Dmsg1(900, "Run program fgets stat=%d\n", stat1);
         break;
      } else {
         stat1 = ferror(bpipe->rfd);
      }
      if (stat1 < 0) {
         berrno be;
         Dmsg2(200, "Run program fgets stat=%d ERR=%s\n", stat1, be.bstrerror());
         break;
      } else if (stat1 != 0) {
         Dmsg1(900, "Run program fgets stat=%d\n", stat1);
         if (bpipe->timer_id && bpipe->timer_id->killed) {
            Dmsg1(250, "Run program saw fgets killed=%d\n", bpipe->timer_id->killed);
            break;
         }
      }
   }
   /*
    * We always check whether the timer killed the program. We would see
    * an eof even when it does so we just have to trust the killed flag
    * and set the timer values to avoid edge cases where the program ends
    * just as the timer kills it.
    */
   if (bpipe->timer_id && bpipe->timer_id->killed) {
      Dmsg1(150, "Run program fgets killed=%d\n", bpipe->timer_id->killed);
      pm_strcpy(tmp, _("Program killed by Bacula (timeout)\n"));
      stat1 = ETIME;
   }
   pm_strcpy(results, tmp);
   Dmsg3(1900, "resadr=0x%x reslen=%d res=%s\n", results, strlen(results), results);
   stat2 = close_bpipe(bpipe);
   stat1 = stat2 != 0 ? stat2 : stat1;

   Dmsg1(900, "Run program returning %d\n", stat1);
bail_out:
   free_pool_memory(tmp);
   free(buf);
   return stat1;
}
Example #8
0
/*
 * Bareos is calling us to do the actual I/O
 */
static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
{
   struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
   if (!p_ctx) {
      return bRC_Error;
   }

   io->status = 0;
   io->io_errno = 0;
   switch(io->func) {
   case IO_OPEN:
      Dmsg(ctx, dbglvl, "bpipe-fd: IO_OPEN\n");
      if (io->flags & (O_CREAT | O_WRONLY)) {
         char *writer_codes = apply_rp_codes(ctx);

         p_ctx->pfd = open_bpipe(writer_codes, 0, "w");
         Dmsg(ctx, dbglvl, "bpipe-fd: IO_OPEN fd=%p writer=%s\n", p_ctx->pfd, writer_codes);
         if (!p_ctx->pfd) {
            io->io_errno = errno;
            Jmsg(ctx, M_FATAL, "bpipe-fd: Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(io->io_errno));
            Dmsg(ctx, dbglvl, "bpipe-fd: Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(io->io_errno));
            if (writer_codes) {
               free(writer_codes);
            }
            return bRC_Error;
         }
         if (writer_codes) {
            free(writer_codes);
         }
      } else {
         p_ctx->pfd = open_bpipe(p_ctx->reader, 0, "r", false);
         Dmsg(ctx, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n", p_ctx->pfd, p_ctx->reader);
         if (!p_ctx->pfd) {
            io->io_errno = errno;
            Jmsg(ctx, M_FATAL, "bpipe-fd: Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(io->io_errno));
            Dmsg(ctx, dbglvl, "bpipe-fd: Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(io->io_errno));
            return bRC_Error;
         }
      }
      sleep(1);                 /* let pipe connect */
      break;
   case IO_READ:
      if (!p_ctx->pfd) {
         Jmsg(ctx, M_FATAL, "bpipe-fd: Logic error: NULL read FD\n");
         Dmsg(ctx, dbglvl, "bpipe-fd: Logic error: NULL read FD\n");
         return bRC_Error;
      }
      io->status = fread(io->buf, 1, io->count, p_ctx->pfd->rfd);
      if (io->status == 0 && ferror(p_ctx->pfd->rfd)) {
         io->io_errno = errno;
         Jmsg(ctx, M_FATAL, "bpipe-fd: Pipe read error: ERR=%s\n", strerror(io->io_errno));
         Dmsg(ctx, dbglvl, "bpipe-fd: Pipe read error: ERR=%s\n", strerror(io->io_errno));
         return bRC_Error;
      }
      break;
   case IO_WRITE:
      if (!p_ctx->pfd) {
         Jmsg(ctx, M_FATAL, "bpipe-fd: Logic error: NULL write FD\n");
         Dmsg(ctx, dbglvl, "bpipe-fd: Logic error: NULL write FD\n");
         return bRC_Error;
      }
      io->status = fwrite(io->buf, 1, io->count, p_ctx->pfd->wfd);
      if (io->status == 0 && ferror(p_ctx->pfd->wfd)) {
         io->io_errno = errno;
         Jmsg(ctx, M_FATAL, "bpipe-fd: Pipe write error: ERR=%s\n", strerror(io->io_errno));
         Dmsg(ctx, dbglvl, "bpipe-fd: Pipe write error: ERR=%s\n", strerror(io->io_errno));
         return bRC_Error;
      }
      break;
   case IO_CLOSE:
      if (!p_ctx->pfd) {
         Jmsg(ctx, M_FATAL, "bpipe-fd: Logic error: NULL FD on bpipe close\n");
         Dmsg(ctx, dbglvl, "bpipe-fd: Logic error: NULL FD on bpipe close\n");
         return bRC_Error;
      }
      io->status = close_bpipe(p_ctx->pfd);
      if (io->status) {
         Jmsg(ctx, M_FATAL, "bpipe-fd: Error closing stream for pseudo file %s: %d\n", p_ctx->fname, io->status);
         Dmsg(ctx, dbglvl, "bpipe-fd: Error closing stream for pseudo file %s: %d\n", p_ctx->fname, io->status);
      }
      break;
   case IO_SEEK:
      io->offset = p_ctx->offset;
      break;
   }

   return bRC_OK;
}