Example #1
0
void JCR::set_killable(bool killable)
{
   JCR *jcr = this;
   jcr->lock();
   jcr->my_thread_killable = killable;
   jcr->unlock();
}
Example #2
0
/* Return Job variables */
PyObject *job_getattr(PyObject *self, char *attrname)
{
   JCR *jcr;
   bool found = false;
   int i;
   char buf[10];
   char errmsg[200];
   
   Dmsg1(100, "In job_getattr=%s\n", attrname);
   jcr = get_jcr_from_PyObject(self);
   if (!jcr) {
      bstrncpy(errmsg, _("Job pointer not found."), sizeof(errmsg));
      goto bail_out;
   }

   for (i=0; getvars[i].name; i++) {
      if (strcmp(getvars[i].name, attrname) == 0) {
         found = true;
         break;
      }
   }
   if (!found) {
      /* Try our methods */
      return Py_FindMethod(JobMethods, self, attrname);
   }  
   switch (i) {
   case 0:                            /* Job */
      return Py_BuildValue((char *)getvars[i].fmt, jcr->job_name);    /* Non-unique name */
   case 1:                            /* SD's name */
      return Py_BuildValue((char *)getvars[i].fmt, my_name);
   case 2:                            /* level */
      return Py_BuildValue((char *)getvars[i].fmt, job_level_to_str(jcr->get_JobLevel()));
   case 3:                            /* type */
      return Py_BuildValue((char *)getvars[i].fmt, job_type_to_str(jcr->get_JobType()));
   case 4:                            /* JobId */
      return Py_BuildValue((char *)getvars[i].fmt, jcr->JobId);
   case 5:                            /* Client */
      return Py_BuildValue((char *)getvars[i].fmt, jcr->client_name);
   case 6:                            /* Pool */
      return Py_BuildValue((char *)getvars[i].fmt, jcr->dcr->pool_name);
   case 7:                            /* MediaType */
      return Py_BuildValue((char *)getvars[i].fmt, jcr->dcr->media_type);
   case 8:                            /* JobName */
      return Py_BuildValue((char *)getvars[i].fmt, jcr->Job);
   case 9:                            /* JobStatus */
      buf[1] = 0;
      buf[0] = jcr->JobStatus;
      return Py_BuildValue((char *)getvars[i].fmt, buf);
   case 10:
      return Py_BuildValue((char *)getvars[i].fmt, jcr->dcr->VolumeName);
   case 11:
      return Py_BuildValue((char *)getvars[i].fmt, jcr->dcr->dev_name);
   }
   bsnprintf(errmsg, sizeof(errmsg), _("Attribute %s not found."), attrname);
bail_out:
   PyErr_SetString(PyExc_AttributeError, errmsg);
   return NULL;
}
Example #3
0
static void jcr_timeout_check(watchdog_t *self)
{
    JCR *jcr;
    BSOCK *bs;
    time_t timer_start;

    Dmsg0(dbglvl, "Start JCR timeout checks\n");

    /* Walk through all JCRs checking if any one is
     * blocked for more than specified max time.
     */
    foreach_jcr(jcr) {
        Dmsg2(dbglvl, "jcr_timeout_check JobId=%u jcr=0x%x\n", jcr->JobId, jcr);
        if (jcr->JobId == 0) {
            continue;
        }
        bs = jcr->store_bsock;
        if (bs) {
            timer_start = bs->timer_start;
            if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
                bs->timer_start = 0;      /* turn off timer */
                bs->set_timed_out();
                Qmsg(jcr, M_ERROR, 0, _(
                         "Watchdog sending kill after %d secs to thread stalled reading Storage daemon.\n"),
                     watchdog_time - timer_start);
                jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
            }
        }
        bs = jcr->file_bsock;
        if (bs) {
            timer_start = bs->timer_start;
            if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
                bs->timer_start = 0;      /* turn off timer */
                bs->set_timed_out();
                Qmsg(jcr, M_ERROR, 0, _(
                         "Watchdog sending kill after %d secs to thread stalled reading File daemon.\n"),
                     watchdog_time - timer_start);
                jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
            }
        }
        bs = jcr->dir_bsock;
        if (bs) {
            timer_start = bs->timer_start;
            if (timer_start && (watchdog_time - timer_start) > bs->timeout) {
                bs->timer_start = 0;      /* turn off timer */
                bs->set_timed_out();
                Qmsg(jcr, M_ERROR, 0, _(
                         "Watchdog sending kill after %d secs to thread stalled reading Director.\n"),
                     watchdog_time - timer_start);
                jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
            }
        }
    }
    endeach_jcr(jcr);

    Dmsg0(dbglvl, "Finished JCR timeout checks\n");
}
Example #4
0
/*
 * Create a Job Control Record and link it into JCR chain
 * Returns newly allocated JCR
 * Note, since each daemon has a different JCR, he passes
 *  us the size.
 */
JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
{
   JCR *jcr;
   MQUEUE_ITEM *item = NULL;
   struct sigaction sigtimer;
   int status;

   Dmsg0(dbglvl, "Enter new_jcr\n");
   status = pthread_once(&key_once, create_jcr_key);
   if (status != 0) {
      berrno be;
      Jmsg1(NULL, M_ABORT, 0, _("pthread_once failed. ERR=%s\n"), be.bstrerror(status));
   }
   jcr = (JCR *)malloc(size);
   memset(jcr, 0, size);
   jcr->my_thread_id = pthread_self();
   jcr->msg_queue = New(dlist(item, &item->link));
   jcr->job_end_push.init(1, false);
   jcr->sched_time = time(NULL);
   jcr->daemon_free_jcr = daemon_free_jcr;    /* plug daemon free routine */
   jcr->init_mutex();
   jcr->inc_use_count();   
   jcr->VolumeName = get_pool_memory(PM_FNAME);
   jcr->VolumeName[0] = 0;
   jcr->errmsg = get_pool_memory(PM_MESSAGE);
   jcr->errmsg[0] = 0;
   /* Setup some dummy values */
   bstrncpy(jcr->Job, "*System*", sizeof(jcr->Job));
   jcr->JobId = 0;
   jcr->set_JobType(JT_SYSTEM);          /* internal job until defined */
   jcr->set_JobLevel(L_NONE);
   set_jcr_job_status(jcr, JS_Created);       /* ready to run */
   set_jcr_in_tsd(jcr);
   sigtimer.sa_flags = 0;
   sigtimer.sa_handler = timeout_handler;
   sigfillset(&sigtimer.sa_mask);
   sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);

   /*
    * Locking jobs is a global lock that is needed
    * so that the Director can stop new jobs from being
    * added to the jcr chain while it processes a new
    * conf file and does the job_end_push().
    */
   lock_jobs();
   lock_jcr_chain();
   if (!jcrs) {
      jcrs = New(dlist(jcr, &jcr->link));
   }
   jcrs->append(jcr);
   unlock_jcr_chain();
   unlock_jobs();

   return jcr;
}
Example #5
0
/*
 * Set and send Job status to Director
 */
bool JCR::sendJobStatus(int newJobStatus)
{
    JCR *jcr = this;
    if (!jcr->is_JobStatus(newJobStatus)) {
        setJobStatus(newJobStatus);
        if (jcr->dir_bsock) {
            return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
        }
    }
    return true;
}
Example #6
0
/*
 * Create session label
 *  The pool memory must be released by the calling program
 */
void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
{
   JCR *jcr = dcr->jcr;
   ser_declare;

   rec->VolSessionId   = jcr->VolSessionId;
   rec->VolSessionTime = jcr->VolSessionTime;
   rec->Stream         = jcr->JobId;
   rec->maskedStream   = jcr->JobId;

   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
   ser_begin(rec->data, SER_LENGTH_Session_Label);
   if (me->compatible) {
      ser_string(OldBaculaId);
      ser_uint32(OldCompatibleBareosTapeVersion1);
   } else {
      ser_string(BareosId);
      ser_uint32(BareosTapeVersion);
   }

   ser_uint32(jcr->JobId);

   /* Changed in VerNum 11 */
   ser_btime(get_current_btime());
   ser_float64(0);

   ser_string(dcr->pool_name);
   ser_string(dcr->pool_type);
   ser_string(jcr->job_name);         /* base Job name */
   ser_string(jcr->client_name);

   /* Added in VerNum 10 */
   ser_string(jcr->Job);              /* Unique name of this Job */
   ser_string(jcr->fileset_name);
   ser_uint32(jcr->getJobType());
   ser_uint32(jcr->getJobLevel());
   /* Added in VerNum 11 */
   ser_string(jcr->fileset_md5);

   if (label == EOS_LABEL) {
      ser_uint32(jcr->JobFiles);
      ser_uint64(jcr->JobBytes);
      ser_uint32(dcr->StartBlock);
      ser_uint32(dcr->EndBlock);
      ser_uint32(dcr->StartFile);
      ser_uint32(dcr->EndFile);
      ser_uint32(jcr->JobErrors);

      /* Added in VerNum 11 */
      ser_uint32(jcr->JobStatus);
   }
   ser_end(rec->data, SER_LENGTH_Session_Label);
   rec->data_len = ser_length(rec->data);
}
Example #7
0
void JCR::set_killable(bool killable)
{
    JCR *jcr = this;
    jcr->lock();
    jcr->my_thread_killable = killable;
    if (killable) {
        jcr->my_thread_id = pthread_self();
    } else {
        memset(&jcr->my_thread_id, 0, sizeof(jcr->my_thread_id));
    }
    jcr->unlock();
}
Example #8
0
/*
 * After receiving a connection (in dircmd.c) if it is
 * from the Storage daemon, this routine is called.
 */
void *handle_stored_connection(BSOCK *sd, char *job_name)
{
   JCR *jcr;

/*
 * With the following bmicrosleep on, running the
 * SD under the debugger fails.
 */
// bmicrosleep(0, 50000);             /* wait 50 millisecs */
   if (!(jcr = get_jcr_by_full_name(job_name))) {
      Jmsg1(NULL, M_FATAL, 0, _("SD connect failed: Job name not found: %s\n"), job_name);
      Dmsg1(3, "**** Job \"%s\" not found.\n", job_name);
      sd->close();
      delete sd;
      return NULL;
   }

   Dmsg1(50, "Found Job %s\n", job_name);

   if (jcr->authenticated) {
      Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
         (uint32_t)jcr->JobId, jcr->Job);
      Dmsg2(50, "Hey!!!! JobId %u Job %s already authenticated.\n",
         (uint32_t)jcr->JobId, jcr->Job);
      sd->close();
      delete sd;
      free_jcr(jcr);
      return NULL;
   }

   jcr->store_bsock = sd;
   jcr->store_bsock->set_jcr(jcr);

   /*
    * Authenticate the Storage daemon
    */
   if (jcr->authenticated || !authenticate_storagedaemon(jcr)) {
      Dmsg1(50, "Authentication failed Job %s\n", jcr->Job);
      Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate Storage daemon\n"));
   } else {
      jcr->authenticated = true;
      Dmsg2(50, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
   }

   if (!jcr->authenticated) {
      jcr->setJobStatus(JS_ErrorTerminated);
   }

   pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
   free_jcr(jcr);

   return NULL;
}
Example #9
0
/*
 * After receiving a connection (in dircmd.c) if it is
 *   from the File daemon, this routine is called.
 */
void handle_filed_connection(BSOCK *fd, char *job_name, int fd_version,
        int sd_version)
{
   JCR *jcr;

   if (!(jcr=get_jcr_by_full_name(job_name))) {
      Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
      Dmsg1(3, "**** Job \"%s\" not found.\n", job_name);
      fd->destroy();
      return;
   }

   Dmsg1(100, "Found Filed Job %s\n", job_name);

   if (jcr->authenticated) {
      Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
         (uint32_t)jcr->JobId, jcr->Job);
      Dmsg2(050, "Hey!!!! JobId %u Job %s already authenticated.\n",
         (uint32_t)jcr->JobId, jcr->Job);
      fd->destroy();
      free_jcr(jcr);
      return;
   }

   jcr->file_bsock = fd;
   jcr->file_bsock->set_jcr(jcr);
   jcr->FDVersion = fd_version;
   jcr->SDVersion = sd_version;
   Dmsg2(050, "fd_version=%d sd_version=%d\n", fd_version, sd_version);

   /*
    * Authenticate the File daemon
    */
   if (jcr->authenticated || !authenticate_filed(jcr)) {
      Dmsg1(50, "Authentication failed Job %s\n", jcr->Job);
      Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
   } else {
      jcr->authenticated = true;
      Dmsg2(050, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
   }

   if (!jcr->authenticated) {
      jcr->setJobStatus(JS_ErrorTerminated);
   }
   Dmsg3(050, "=== Auth OK, unblock Job %s jid=%d sd_ver=%d\n", job_name, jcr->JobId, sd_version);
   if (sd_version > 0) {
      jcr->sd_client = true;
   }
   pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
   free_jcr(jcr);
   return;
}
Example #10
0
static bool write_spool_header(DCR *dcr)
{
    spool_hdr hdr;
    ssize_t status;
    DEV_BLOCK *block = dcr->block;
    JCR *jcr = dcr->jcr;

    hdr.FirstIndex = block->FirstIndex;
    hdr.LastIndex = block->LastIndex;
    hdr.len = block->binbuf;

    /* Write header */
    for (int retry = 0; retry <= 1; retry++) {
        status = write(dcr->spool_fd, (char*)&hdr, sizeof(hdr));
        if (status == -1) {
            berrno be;

            Jmsg(jcr, M_FATAL, 0, _("Error writing header to spool file. ERR=%s\n"), be.bstrerror());
            jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        }
        if (status != (ssize_t)sizeof(hdr)) {
            Jmsg(jcr, M_ERROR, 0, _("Error writing header to spool file."
                                    " Disk probably full. Attempting recovery. Wanted to write=%d got=%d\n"),
                 (int)status, (int)sizeof(hdr));
            /* If we wrote something, truncate it, then despool */
            if (status != -1) {
#if defined(HAVE_WIN32)
                boffset_t   pos = _lseeki64(dcr->spool_fd, (__int64)0, SEEK_CUR);
#else
                boffset_t   pos = lseek(dcr->spool_fd, 0, SEEK_CUR);
#endif
                if (ftruncate(dcr->spool_fd, pos - status) != 0) {
                    berrno be;

                    Jmsg(dcr->jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), be.bstrerror());
                    /* Note, try continuing despite ftruncate problem */
                }
            }
            if (!despool_data(dcr, false)) {
                Jmsg(jcr, M_FATAL, 0, _("Fatal despooling error."));
                jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
                return false;
            }
            continue;                    /* try again */
        }
        return true;
    }
    Jmsg(jcr, M_FATAL, 0, _("Retrying after header spooling error failed.\n"));
    jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
    return false;
}
Example #11
0
File: askdir.c Project: AlD/bareos
/**
 * After writing a Volume, create the JobMedia record.
 */
bool dir_create_jobmedia_record(DCR *dcr, bool zero)
{
   JCR *jcr = dcr->jcr;
   BSOCK *dir = jcr->dir_bsock;
   char ed1[50];

   /* If system job, do not update catalog */
   if (jcr->is_JobType(JT_SYSTEM)) {
      return true;
   }

   /* Throw out records where FI is zero -- i.e. nothing done */
   if (!zero && dcr->VolFirstIndex == 0 &&
        (dcr->StartBlock != 0 || dcr->EndBlock != 0)) {
      Dmsg0(dbglvl, "JobMedia FI=0 StartBlock!=0 record suppressed\n");
      return true;
   }

   if (!dcr->WroteVol) {
      return true;                    /* nothing written to tape */
   }

   dcr->WroteVol = false;
   if (zero) {
      /* Send dummy place holder to avoid purging */
      dir->fsend(Create_job_media, jcr->Job,
         0 , 0, 0, 0, 0, 0, 0, 0, edit_uint64(dcr->VolMediaId, ed1));
   } else {
      dir->fsend(Create_job_media, jcr->Job,
         dcr->VolFirstIndex, dcr->VolLastIndex,
         dcr->StartFile, dcr->EndFile,
         dcr->StartBlock, dcr->EndBlock,
         dcr->Copy, dcr->Stripe,
         edit_uint64(dcr->VolMediaId, ed1));
   }
   Dmsg1(dbglvl, ">dird %s", dir->msg);
   if (dir->recv() <= 0) {
      Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n");
      Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
           dir->bstrerror());
      return false;
   }
   Dmsg1(dbglvl, "<dird %s", dir->msg);
   if (!bstrcmp(dir->msg, OK_create)) {
      Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg);
      Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
      return false;
   }
   return true;
}
Example #12
0
/*
 * Read a block from the spool file
 *
 *  Returns RB_OK on success
 *          RB_EOT when file done
 *          RB_ERROR on error
 */
static int read_block_from_spool_file(DCR *dcr)
{
    uint32_t rlen;
    ssize_t status;
    spool_hdr hdr;
    DEV_BLOCK *block = dcr->block;
    JCR *jcr = dcr->jcr;

    rlen = sizeof(hdr);
    status = read(dcr->spool_fd, (char *)&hdr, (size_t)rlen);
    if (status == 0) {
        Dmsg0(100, "EOT on spool read.\n");
        return RB_EOT;
    } else if (status != (ssize_t)rlen) {
        if (status == -1) {
            berrno be;

            Jmsg(dcr->jcr, M_FATAL, 0, _("Spool header read error. ERR=%s\n"), be.bstrerror());
        } else {
            Pmsg2(000, _("Spool read error. Wanted %u bytes, got %d\n"), rlen, status);
            Jmsg2(jcr, M_FATAL, 0, _("Spool header read error. Wanted %u bytes, got %d\n"), rlen, status);
        }
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        return RB_ERROR;
    }
    rlen = hdr.len;
    if (rlen > block->buf_len) {
        Pmsg2(000, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
        Jmsg2(jcr, M_FATAL, 0, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        return RB_ERROR;
    }
    status = read(dcr->spool_fd, (char *)block->buf, (size_t)rlen);
    if (status != (ssize_t)rlen) {
        Pmsg2(000, _("Spool data read error. Wanted %u bytes, got %d\n"), rlen, status);
        Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool data read error. Wanted %u bytes, got %d\n"), rlen, status);
        jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        return RB_ERROR;
    }
    /* Setup write pointers */
    block->binbuf = rlen;
    block->bufp = block->buf + block->binbuf;
    block->FirstIndex = hdr.FirstIndex;
    block->LastIndex = hdr.LastIndex;
    block->VolSessionId = dcr->jcr->VolSessionId;
    block->VolSessionTime = dcr->jcr->VolSessionTime;
    Dmsg2(800, "Read block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex);
    return RB_OK;
}
Example #13
0
/*
 * We are called here for each record that matches the above
 *  SQL query -- that is for each file contained in the Catalog
 *  that was not marked earlier. This means that the file in
 *  question is a missing file (in the Catalog but not on Disk).
 */
static int missing_handler(void *ctx, int num_fields, char **row)
{
   JCR *jcr = (JCR *)ctx;

   if (job_canceled(jcr)) {
      return 1;
   }
   if (!jcr->fn_printed) {
      Qmsg(jcr, M_WARNING, 0, _("The following files are in the Catalog but not on %s:\n"),
          jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG ? "the Volume(s)" : "disk");
      jcr->fn_printed = true;
   }
   Qmsg(jcr, M_INFO, 0, "      %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
   return 0;
}
Example #14
0
/*
 * Given a JobId, find the JCR
 *
 * Returns: jcr on success
 *          NULL on failure
 */
JCR *get_jcr_by_id(uint32_t JobId)
{
    JCR *jcr;

    foreach_jcr(jcr) {
        if (jcr->JobId == JobId) {
            jcr->inc_use_count();
            Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n",
                  jcr->JobId, jcr->use_count(), jcr->Job);
            break;
        }
    }
    endeach_jcr(jcr);
    return jcr;
}
Example #15
0
/*
 * Start walk of jcr chain
 * The proper way to walk the jcr chain is:
 *    JCR *jcr;
 *    foreach_jcr(jcr) {
 *      ...
 *    }
 *    endeach_jcr(jcr);
 *
 * It is possible to leave out the endeach_jcr(jcr), but
 * in that case, the last jcr referenced must be explicitly
 * released with:
 *
 * free_jcr(jcr);
 */
JCR *jcr_walk_start()
{
    JCR *jcr;
    lock_jcr_chain();
    jcr = (JCR *)jcrs->first();
    if (jcr) {
        jcr->inc_use_count();
        if (jcr->JobId > 0) {
            Dmsg3(dbglvl, "Inc walk_start jid=%u use_count=%d Job=%s\n",
                  jcr->JobId, jcr->use_count(), jcr->Job);
        }
    }
    unlock_jcr_chain();
    return jcr;
}
Example #16
0
static bool write_spool_data(DCR *dcr)
{
    ssize_t status;
    DEV_BLOCK *block = dcr->block;
    JCR *jcr = dcr->jcr;

    /* Write data */
    for (int retry = 0; retry <= 1; retry++) {
        status = write(dcr->spool_fd, block->buf, (size_t)block->binbuf);
        if (status == -1) {
            berrno be;

            Jmsg(jcr, M_FATAL, 0, _("Error writing data to spool file. ERR=%s\n"), be.bstrerror());
            jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
        }
        if (status != (ssize_t)block->binbuf) {
            /*
             * If we wrote something, truncate it and the header, then despool
             */
            if (status != -1) {
#if defined(HAVE_WIN32)
                boffset_t   pos = _lseeki64(dcr->spool_fd, (__int64)0, SEEK_CUR);
#else
                boffset_t   pos = lseek(dcr->spool_fd, 0, SEEK_CUR);
#endif
                if (ftruncate(dcr->spool_fd, pos - status - sizeof(spool_hdr)) != 0) {
                    berrno be;

                    Jmsg(dcr->jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), be.bstrerror());
                    /* Note, try continuing despite ftruncate problem */
                }
            }
            if (!despool_data(dcr, false)) {
                Jmsg(jcr, M_FATAL, 0, _("Fatal despooling error."));
                jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
                return false;
            }
            if (!write_spool_header(dcr)) {
                return false;
            }
            continue;                    /* try again */
        }
        return true;
    }
    Jmsg(jcr, M_FATAL, 0, _("Retrying after data spooling error failed.\n"));
    jcr->forceJobStatus(JS_FatalError);  /* override any Incomplete */
    return false;
}
Example #17
0
void DEVICE::attach_dcr_to_dev(DCR *dcr)
{
   JCR *jcr = dcr->jcr;

   Lock_dcrs();
   jcr = dcr->jcr;
   if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
   /* ***FIXME*** return error if dev not initiated */
   if (!dcr->attached_to_dev && initiated && jcr && jcr->getJobType() != JT_SYSTEM) {
      Dmsg4(200, "Attach Jid=%d dcr=%p size=%d dev=%s\n", (uint32_t)jcr->JobId,
         dcr, attached_dcrs->size(), print_name());
      attached_dcrs->append(dcr);  /* attach dcr to device */
      dcr->attached_to_dev = true;
   }
   Unlock_dcrs();
}
Example #18
0
/*
 * Given a SessionId and SessionTime, find the JCR
 *
 * Returns: jcr on success
 *          NULL on failure
 */
JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime)
{
    JCR *jcr;

    foreach_jcr(jcr) {
        if (jcr->VolSessionId == SessionId &&
                jcr->VolSessionTime == SessionTime) {
            jcr->inc_use_count();
            Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n",
                  jcr->JobId, jcr->use_count(), jcr->Job);
            break;
        }
    }
    endeach_jcr(jcr);
    return jcr;
}
Example #19
0
/*
 * Given a Job, find the JCR requires an exact match of names.
 *
 * Returns: jcr on success
 *          NULL on failure
 */
JCR *get_jcr_by_full_name(char *Job)
{
    JCR *jcr;

    if (!Job) {
        return NULL;
    }
    foreach_jcr(jcr) {
        if (bstrcmp(jcr->Job, Job)) {
            jcr->inc_use_count();
            Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n",
                  jcr->JobId, jcr->use_count(), jcr->Job);
            break;
        }
    }
    endeach_jcr(jcr);
    return jcr;
}
Example #20
0
/*
 * Get next jcr from chain, and release current one
 */
JCR *jcr_walk_next(JCR *prev_jcr)
{
    JCR *jcr;

    lock_jcr_chain();
    jcr = (JCR *)jcrs->next(prev_jcr);
    if (jcr) {
        jcr->inc_use_count();
        if (jcr->JobId > 0) {
            Dmsg3(dbglvl, "Inc walk_next jid=%u use_count=%d Job=%s\n",
                  jcr->JobId, jcr->use_count(), jcr->Job);
        }
    }
    unlock_jcr_chain();
    if (prev_jcr) {
        free_jcr(prev_jcr);
    }
    return jcr;
}
Example #21
0
/*
 * Setup a "daemon" JCR for the various standalone
 *  tools (e.g. bls, bextract, bscan, ...)
 */
JCR *setup_jcr(const char *name, char *dev_name,
               BSR *bsr, DIRRES *director,
               const char *VolumeName, int mode)
{
   DCR *dcr;
   JCR *jcr = new_jcr(sizeof(JCR), my_free_jcr);
   jcr->bsr = bsr;
   jcr->director = director;
   jcr->VolSessionId = 1;
   jcr->VolSessionTime = (uint32_t)time(NULL);
   jcr->NumReadVolumes = 0;
   jcr->NumWriteVolumes = 0;
   jcr->JobId = 0;
   jcr->setJobType(JT_CONSOLE);
   jcr->setJobLevel(L_FULL);
   jcr->JobStatus = JS_Terminated;
   jcr->where = bstrdup("");
   jcr->job_name = get_pool_memory(PM_FNAME);
   pm_strcpy(jcr->job_name, "Dummy.Job.Name");
   jcr->client_name = get_pool_memory(PM_FNAME);
   pm_strcpy(jcr->client_name, "Dummy.Client.Name");
   bstrncpy(jcr->Job, name, sizeof(jcr->Job));
   jcr->fileset_name = get_pool_memory(PM_FNAME);
   pm_strcpy(jcr->fileset_name, "Dummy.fileset.name");
   jcr->fileset_md5 = get_pool_memory(PM_FNAME);
   pm_strcpy(jcr->fileset_md5, "Dummy.fileset.md5");

   new_plugins(jcr);  /* instantiate plugins */

   init_autochangers();
   create_volume_lists();

   dcr = setup_to_access_device(jcr, dev_name, VolumeName, mode);
   if (!dcr) {
      return NULL;
   }
   if (!bsr && VolumeName) {
      bstrncpy(dcr->VolumeName, VolumeName, sizeof(dcr->VolumeName));
   }
   bstrncpy(dcr->pool_name, "Default", sizeof(dcr->pool_name));
   bstrncpy(dcr->pool_type, "Backup", sizeof(dcr->pool_type));
   return jcr;
}
Example #22
0
/*
 * Given a Job, find the JCR compares on the number of
 * characters in Job thus allowing partial matches.
 *
 * Returns: jcr on success
 *          NULL on failure
 */
JCR *get_jcr_by_partial_name(char *Job)
{
    JCR *jcr;
    int len;

    if (!Job) {
        return NULL;
    }
    len = strlen(Job);
    foreach_jcr(jcr) {
        if (bstrncmp(Job, jcr->Job, len)) {
            jcr->inc_use_count();
            Dmsg3(dbglvl, "Inc get_jcr jid=%u use_count=%d Job=%s\n",
                  jcr->JobId, jcr->use_count(), jcr->Job);
            break;
        }
    }
    endeach_jcr(jcr);
    return jcr;
}
Example #23
0
static void attach_dcr_to_dev(DCR *dcr)
{
   DEVICE *dev;
   JCR *jcr;

   P(dcr->m_mutex);
   dev = dcr->dev;
   jcr = dcr->jcr;
   if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
   /* ***FIXME*** return error if dev not initiated */
   if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->getJobType() != JT_SYSTEM) {
      dev->Lock();
      Dmsg4(200, "Attach Jid=%d dcr=%p size=%d dev=%s\n", (uint32_t)jcr->JobId,
         dcr, dev->attached_dcrs->size(), dev->print_name());
      dev->attached_dcrs->append(dcr);  /* attach dcr to device */
      dev->Unlock();
      dcr->attached_to_dev = true;
   }
   V(dcr->m_mutex);
}
Example #24
0
/*
 * !!! WARNING !!! 
 *
 * This function should be used ONLY after a fatal signal. We walk through the
 * JCR chain without doing any lock, bacula should not be running.
 */
void _dbg_print_jcr(FILE *fp)
{
   char buf1[128], buf2[128], buf3[128], buf4[128];
   if (!jcrs) {
      return;
   }

   fprintf(fp, "Attempt to dump current JCRs\n");

   for (JCR *jcr = (JCR *)jcrs->first(); jcr ; jcr = (JCR *)jcrs->next(jcr)) {
      if (!jcr) {               /* protect us against something ? */
         continue;
      }
      
      fprintf(fp, "JCR=%p JobId=%i name=%s JobStatus=%c\n", 
              jcr, jcr->JobId, jcr->Job, jcr->JobStatus);
#ifdef HAVE_WIN32
      fprintf(fp, "\tuse_count=%i\n",
              jcr->use_count());
#else
      fprintf(fp, "\tuse_count=%i threadid=0x%x\n",
              jcr->use_count(), (int)jcr->my_thread_id);
#endif
      fprintf(fp, "\tJobType=%c JobLevel=%c\n",
              jcr->get_JobType(), jcr->get_JobLevel());
      bstrftime(buf1, sizeof(buf1), jcr->sched_time);
      bstrftime(buf2, sizeof(buf2), jcr->start_time);
      bstrftime(buf3, sizeof(buf3), jcr->end_time);
      bstrftime(buf4, sizeof(buf4), jcr->wait_time);
      fprintf(fp, "\tsched_time=%s start_time=%s\n\tend_time=%s wait_time=%s\n",
              buf1, buf2, buf3, buf4);
      fprintf(fp, "\tdequeing=%i\n", jcr->dequeuing);
      fprintf(fp, "\tdb=%p db_batch=%p batch_started=%i\n", 
              jcr->db, jcr->db_batch, jcr->batch_started);
      
      for(int i=0; i < dbg_jcr_handler_count; i++) {
         dbg_jcr_hook_t *fct = dbg_jcr_hooks[i];
         fct(jcr, fp);
      }
   }
}
Example #25
0
/*
 * Create a Job Control Record for a control "job",
 *   filling in all the appropriate fields.
 */
JCR *new_control_jcr(const char *base_name, int job_type)
{
   JCR *jcr;
   jcr = new_jcr(sizeof(JCR), dird_free_jcr);
   /*
    * The job and defaults are not really used, but
    *  we set them up to ensure that everything is correctly
    *  initialized.
    */
   LockRes();
   jcr->job = (JOB *)GetNextRes(R_JOB, NULL);
   set_jcr_defaults(jcr, jcr->job);
   UnlockRes();
   jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */
   create_unique_job_name(jcr, base_name);
   jcr->sched_time = jcr->start_time;
   jcr->setJobType(job_type);
   jcr->setJobLevel(L_NONE);
   jcr->setJobStatus(JS_Running);
   jcr->JobId = 0;
   return jcr;
}
Example #26
0
/*
 * !!! WARNING !!!
 *
 * This function should be used ONLY after a fatal signal. We walk through the
 * JCR chain without doing any lock, Bacula should not be running.
 */
void dbg_print_jcr(FILE *fp)
{
   char buf1[128], buf2[128], buf3[128], buf4[128];
   if (!jcrs) {
      return;
   }

   fprintf(fp, "Attempt to dump current JCRs. njcrs=%d\n", jcrs->size());

   for (JCR *jcr = (JCR *)jcrs->first(); jcr ; jcr = (JCR *)jcrs->next(jcr)) {
      fprintf(fp, "threadid=%p JobId=%d JobStatus=%c jcr=%p name=%s\n",
              get_threadid(jcr->my_thread_id), (int)jcr->JobId, jcr->JobStatus, jcr, jcr->Job);
      fprintf(fp, "threadid=%p killable=%d JobId=%d JobStatus=%c "
                  "jcr=%p name=%s\n",
              get_threadid(jcr->my_thread_id), jcr->is_killable(),
              (int)jcr->JobId, jcr->JobStatus, jcr, jcr->Job);
      fprintf(fp, "\tuse_count=%i\n", jcr->use_count());
      fprintf(fp, "\tJobType=%c JobLevel=%c\n",
              jcr->getJobType(), jcr->getJobLevel());
      bstrftime(buf1, sizeof(buf1), jcr->sched_time);
      bstrftime(buf2, sizeof(buf2), jcr->start_time);
      bstrftime(buf3, sizeof(buf3), jcr->end_time);
      bstrftime(buf4, sizeof(buf4), jcr->wait_time);
      fprintf(fp, "\tsched_time=%s start_time=%s\n\tend_time=%s wait_time=%s\n",
              buf1, buf2, buf3, buf4);
      fprintf(fp, "\tdb=%p db_batch=%p batch_started=%i\n",
              jcr->db, jcr->db_batch, jcr->batch_started);

      /*
       * Call all the jcr debug hooks
       */
      for(int i=0; i < dbg_jcr_handler_count; i++) {
         dbg_jcr_hook_t *hook = dbg_jcr_hooks[i];
         hook(jcr, fp);
      }
   }
}
Example #27
0
File: stored.c Project: AlD/bareos
void *device_initialization(void *arg)
{
   DEVRES *device;
   DCR *dcr;
   JCR *jcr;
   DEVICE *dev;
   int errstat;

   LockRes();

   pthread_detach(pthread_self());
   jcr = new_jcr(sizeof(JCR), stored_free_jcr);
   new_plugins(jcr);  /* instantiate plugins */
   jcr->setJobType(JT_SYSTEM);

   /*
    * Initialize job start condition variable
    */
   errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
   if (errstat != 0) {
      berrno be;
      Jmsg1(jcr, M_ABORT, 0, _("Unable to init job start cond variable: ERR=%s\n"), be.bstrerror(errstat));
   }

   /*
    * Initialize job end condition variable
    */
   errstat = pthread_cond_init(&jcr->job_end_wait, NULL);
   if (errstat != 0) {
      berrno be;
      Jmsg1(jcr, M_ABORT, 0, _("Unable to init job endstart cond variable: ERR=%s\n"), be.bstrerror(errstat));
   }

   foreach_res(device, R_DEVICE) {
      Dmsg1(90, "calling init_dev %s\n", device->device_name);
      dev = init_dev(NULL, device);
      Dmsg1(10, "SD init done %s\n", device->device_name);
      if (!dev) {
         Jmsg1(NULL, M_ERROR, 0, _("Could not initialize %s\n"), device->device_name);
         continue;
      }

      jcr->dcr = dcr = new_dcr(jcr, NULL, dev, NULL);
      generate_plugin_event(jcr, bsdEventDeviceInit, dcr);
      if (dev->is_autochanger()) {
         /* If autochanger set slot in dev structure */
         get_autochanger_loaded_slot(dcr);
      }

      if (device->cap_bits & CAP_ALWAYSOPEN) {
         Dmsg1(20, "calling first_open_device %s\n", dev->print_name());
         if (!first_open_device(dcr)) {
            Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), dev->print_name());
            Dmsg1(20, "Could not open device %s\n", dev->print_name());
            free_dcr(dcr);
            jcr->dcr = NULL;
            continue;
         }
      }

      if (device->cap_bits & CAP_AUTOMOUNT && dev->is_open()) {
         switch (read_dev_volume_label(dcr)) {
         case VOL_OK:
            memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
            volume_unused(dcr);             /* mark volume "released" */
            break;
         default:
            Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"), dev->print_name());
            break;
         }
      }
      free_dcr(dcr);
      jcr->dcr = NULL;
   }
Example #28
0
int main (int argc, char *argv[])
{
   int ch;
#if defined(HAVE_DYNAMIC_CATS_BACKENDS)
   alist *backend_directories = NULL;
#endif
   char *jobids = (char *)"1";
   char *path=NULL, *client=NULL;
   uint64_t limit=0;
   bool clean=false;
   setlocale(LC_ALL, "");
   bindtextdomain("bareos", LOCALEDIR);
   textdomain("bareos");
   init_stack_dump();

   Dmsg0(0, "Starting bvfs_test tool\n");

   my_name_is(argc, argv, "bvfs_test");
   init_msg(NULL, NULL);

   OSDependentInit();

   while ((ch = getopt(argc, argv, "h:c:l:d:D:n:P:Su:vf:w:?j:p:f:T")) != -1) {
      switch (ch) {
      case 'd':                    /* debug level */
         if (*optarg == 't') {
            dbg_timestamp = true;
         } else {
            debug_level = atoi(optarg);
            if (debug_level <= 0) {
               debug_level = 1;
            }
         }
         break;

      case 'D':
         db_driver = optarg;
         break;

      case 'l':
         limit = str_to_int64(optarg);
         break;

      case 'c':
         client = optarg;
         break;

      case 'h':
         db_host = optarg;
         break;

      case 'n':
         db_name = optarg;
         break;

      case 'w':
         working_directory = optarg;
         break;

      case 'u':
         db_user = optarg;
         break;

      case 'P':
         db_password = optarg;
         break;

      case 'v':
         verbose++;
         break;

      case 'p':
         path = optarg;
         break;

      case 'f':
         file = optarg;
         break;

      case 'j':
         jobids = optarg;
         break;

      case 'T':
         clean = true;
         break;

      case '?':
      default:
         usage();

      }
   }
   argc -= optind;
   argv += optind;

   if (argc != 0) {
      Pmsg0(0, _("Wrong number of arguments: \n"));
      usage();
   }
   JCR *bjcr = new_jcr(sizeof(JCR), NULL);
   bjcr->JobId = getpid();
   bjcr->setJobType(JT_CONSOLE);
   bjcr->setJobLevel(L_FULL);
   bjcr->JobStatus = JS_Running;
   bjcr->client_name = get_pool_memory(PM_FNAME);
   pm_strcpy(bjcr->client_name, "Dummy.Client.Name");
   bstrncpy(bjcr->Job, "bvfs_test", sizeof(bjcr->Job));

#if defined(HAVE_DYNAMIC_CATS_BACKENDS)
   backend_directories = New(alist(10, owned_by_alist));
   backend_directories->append((char *)backend_directory);

   db_set_backend_dirs(backend_directories);
#endif

   if ((db = db_init_database(NULL, NULL, db_name, db_user, db_password, db_host, 0, NULL)) == NULL) {
      Emsg0(M_ERROR_TERM, 0, _("Could not init Bareos database\n"));
   }
   Dmsg1(0, "db_type=%s\n", db_get_type(db));

   if (!db_open_database(NULL, db)) {
      Emsg0(M_ERROR_TERM, 0, db_strerror(db));
   }
   Dmsg0(200, "Database opened\n");
   if (verbose) {
      Pmsg2(000, _("Using Database: %s, User: %s\n"), db_name, db_user);
   }

   bjcr->db = db;

   if (clean) {
      Pmsg0(0, "Clean old table\n");
      db_sql_query(db, "DELETE FROM PathHierarchy", NULL, NULL);
      db_sql_query(db, "UPDATE Job SET HasCache=0", NULL, NULL);
      db_sql_query(db, "DELETE FROM PathVisibility", NULL, NULL);
      bvfs_update_cache(bjcr, db);
   }

   Bvfs fs(bjcr, db);
   fs.set_handler(result_handler, &fs);

   fs.set_jobids(jobids);
   fs.update_cache();
   if (limit)
      fs.set_limit(limit);

   if (path) {
      fs.ch_dir(path);
      fs.ls_special_dirs();
      fs.ls_dirs();
      while (fs.ls_files()) {
         fs.next_offset();
      }

      if (fnid && client) {
         Pmsg0(0, "---------------------------------------------\n");
         Pmsg1(0, "Getting file version for %s\n", file);
         fs.get_all_file_versions(fs.get_pwd(), fnid, client);
      }

      exit (0);
   }


   Pmsg0(0, "list /\n");
   fs.ch_dir("/");
   fs.ls_special_dirs();
   fs.ls_dirs();
   fs.ls_files();

   Pmsg0(0, "list /tmp/\n");
   fs.ch_dir("/tmp/");
   fs.ls_special_dirs();
   fs.ls_dirs();
   fs.ls_files();

   Pmsg0(0, "list /tmp/regress/\n");
   fs.ch_dir("/tmp/regress/");
   fs.ls_special_dirs();
   fs.ls_files();
   fs.ls_dirs();

   Pmsg0(0, "list /tmp/regress/build/\n");
   fs.ch_dir("/tmp/regress/build/");
   fs.ls_special_dirs();
   fs.ls_dirs();
   fs.ls_files();

   fs.get_all_file_versions(1, 347, "zog4-fd");

   char p[200];
   strcpy(p, "/tmp/toto/rep/");
   bvfs_parent_dir(p);
   if(!bstrcmp(p, "/tmp/toto/")) {
      Pmsg0(000, "Error in bvfs_parent_dir\n");
   }
   bvfs_parent_dir(p);
   if(!bstrcmp(p, "/tmp/")) {
      Pmsg0(000, "Error in bvfs_parent_dir\n");
   }
   bvfs_parent_dir(p);
   if(!bstrcmp(p, "/")) {
      Pmsg0(000, "Error in bvfs_parent_dir\n");
   }
   bvfs_parent_dir(p);
   if(!bstrcmp(p, "")) {
      Pmsg0(000, "Error in bvfs_parent_dir\n");
   }
   bvfs_parent_dir(p);
   if(!bstrcmp(p, "")) {
      Pmsg0(000, "Error in bvfs_parent_dir\n");
   }

   return 0;
}
Example #29
0
File: askdir.c Project: AlD/bareos
/**
 *   Request to mount specific Volume
 *
 *   Entered with device blocked and dcr->VolumeName is desired
 *      volume.
 *   Leaves with device blocked.
 *
 *   Returns: true  on success (operator issues a mount command)
 *            false on failure
 *                  Note, must create dev->errmsg on error return.
 *
 */
bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode)
{
   int status = W_TIMEOUT;
   DEVICE *dev = dcr->dev;
   JCR *jcr = dcr->jcr;

   Dmsg0(dbglvl, "enter dir_ask_sysop_to_mount_volume\n");
   if (!dcr->VolumeName[0]) {
      Mmsg0(dev->errmsg, _("Cannot request another volume: no volume name given.\n"));
      return false;
   }
   ASSERT(dev->blocked());
   for ( ;; ) {
      if (job_canceled(jcr)) {
         Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device %s.\n"),
              jcr->Job, dev->print_name());
         return false;
      }

      /*
       * If we are not polling, and the wait timeout or the
       *   user explicitly did a mount, send him the message.
       *   Otherwise skip it.
       */
      if (!dev->poll && (status == W_TIMEOUT || status == W_MOUNT)) {
         const char *msg;

         if (mode == ST_APPENDREADY) {
            msg = _("Please mount append Volume \"%s\" or label a new one for:\n"
                    "    Job:          %s\n"
                    "    Storage:      %s\n"
                    "    Pool:         %s\n"
                    "    Media type:   %s\n");
         } else {
            msg = _("Please mount read Volume \"%s\" for:\n"
                    "    Job:          %s\n"
                    "    Storage:      %s\n"
                    "    Pool:         %s\n"
                    "    Media type:   %s\n");
         }
         Jmsg(jcr, M_MOUNT, 0, msg, dcr->VolumeName, jcr->Job,
              dev->print_name(), dcr->pool_name, dcr->media_type);
         Dmsg3(dbglvl, "Mount \"%s\" on device \"%s\" for Job %s\n",
               dcr->VolumeName, dev->print_name(), jcr->Job);
      }

      jcr->sendJobStatus(JS_WaitMount);

      status = wait_for_sysop(dcr);          /* wait on device */
      Dmsg1(dbglvl, "Back from wait_for_sysop status=%d\n", status);
      if (dev->poll) {
         Dmsg1(dbglvl, "Poll timeout in mount vol on device %s\n", dev->print_name());
         Dmsg1(dbglvl, "Blocked=%s\n", dev->print_blocked());
         goto get_out;
      }

      if (status == W_TIMEOUT) {
         if (!double_dev_wait_time(dev)) {
            Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
               dev->print_name(), jcr->Job);
            Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
            Dmsg1(dbglvl, "Gave up waiting on device %s\n", dev->print_name());
            return false;             /* exceeded maximum waits */
         }
         continue;
      }
      if (status == W_ERROR) {
         berrno be;
         Mmsg(dev->errmsg, _("pthread error in mount_volume\n"));
         Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
         return false;
      }
      Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
      break;
   }

get_out:
   jcr->sendJobStatus(JS_Running);
   Dmsg0(dbglvl, "leave dir_ask_sysop_to_mount_volume\n");
   return true;
}
Example #30
0
File: askdir.c Project: AlD/bareos
/**
 *   Request the sysop to create an appendable volume
 *
 *   Entered with device blocked.
 *   Leaves with device blocked.
 *
 *   Returns: true  on success (operator issues a mount command)
 *            false on failure
 *              Note, must create dev->errmsg on error return.
 *
 *    On success, dcr->VolumeName and dcr->VolCatInfo contain
 *      information on suggested volume, but this may not be the
 *      same as what is actually mounted.
 *
 *    When we return with success, the correct tape may or may not
 *      actually be mounted. The calling routine must read it and
 *      verify the label.
 */
bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
{
   int status = W_TIMEOUT;
   DEVICE *dev = dcr->dev;
   JCR *jcr = dcr->jcr;
   bool got_vol = false;

   if (job_canceled(jcr)) {
      return false;
   }
   Dmsg0(dbglvl, "enter dir_ask_sysop_to_create_appendable_volume\n");
   ASSERT(dev->blocked());
   for ( ;; ) {
      if (job_canceled(jcr)) {
         Mmsg(dev->errmsg,
              _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"),
              jcr->Job, dev->print_name());
         Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
         return false;
      }
      got_vol = dir_find_next_appendable_volume(dcr);   /* get suggested volume */
      if (got_vol) {
         goto get_out;
      } else {
         if (status == W_TIMEOUT || status == W_MOUNT) {
            Mmsg(dev->errmsg, _(
"Job %s is waiting. Cannot find any appendable volumes.\n"
"Please use the \"label\" command to create a new Volume for:\n"
"    Storage:      %s\n"
"    Pool:         %s\n"
"    Media type:   %s\n"),
               jcr->Job,
               dev->print_name(),
               dcr->pool_name,
               dcr->media_type);
            Jmsg(jcr, M_MOUNT, 0, "%s", dev->errmsg);
            Dmsg1(dbglvl, "%s", dev->errmsg);
         }
      }

      jcr->sendJobStatus(JS_WaitMedia);

      status = wait_for_sysop(dcr);
      Dmsg1(dbglvl, "Back from wait_for_sysop status=%d\n", status);
      if (dev->poll) {
         Dmsg1(dbglvl, "Poll timeout in create append vol on device %s\n", dev->print_name());
         continue;
      }

      if (status == W_TIMEOUT) {
         if (!double_dev_wait_time(dev)) {
            Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device %s for Job %s\n"),
               dev->print_name(), jcr->Job);
            Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
            Dmsg1(dbglvl, "Gave up waiting on device %s\n", dev->print_name());
            return false;             /* exceeded maximum waits */
         }
         continue;
      }
      if (status == W_ERROR) {
         berrno be;
         Mmsg0(dev->errmsg, _("pthread error in mount_next_volume.\n"));
         Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg);
         return false;
      }
      Dmsg1(dbglvl, "Someone woke me for device %s\n", dev->print_name());
   }

get_out:
   jcr->sendJobStatus(JS_Running);
   Dmsg0(dbglvl, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
   return true;
}