Beispiel #1
0
/*
 * Wake watchdog timer thread so that it walks the
 *  queue and adjusts its wait time (or exits).
 */
static void ping_watchdog()
{
   P(timer_mutex);
   pthread_cond_signal(&timer);
   V(timer_mutex);
   bmicrosleep(0, 100);
}
Beispiel #2
0
/* Respond to challenge from other end */
bool cram_md5_respond(BSOCK *bs, const char *password, int *tls_remote_need, bool *compatible)
{
   char chal[MAXSTRING];
   uint8_t hmac[20];

   *compatible = false;
   if (bs->recv() <= 0) {
      bmicrosleep(5, 0);
      return false;
   }
   if (bs->msglen >= MAXSTRING) {
      Dmsg1(dbglvl, "Msg too long wanted auth cram... Got: %s", bs->msg);
      bmicrosleep(5, 0);
      return false;
   }
   Dmsg1(100, "cram-get received: %s", bs->msg);
   if (sscanf(bs->msg, "auth cram-md5c %s ssl=%d", chal, tls_remote_need) == 2) {
      *compatible = true;
   } else if (sscanf(bs->msg, "auth cram-md5 %s ssl=%d", chal, tls_remote_need) != 2) {
      if (sscanf(bs->msg, "auth cram-md5 %s\n", chal) != 1) {
         Dmsg1(dbglvl, "Cannot scan challenge: %s", bs->msg);
         bs->fsend(_("1999 Authorization failed.\n"));
         bmicrosleep(5, 0);
         return false;
      }
   }

   hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
   bs->msglen = bin_to_base64(bs->msg, 50, (char *)hmac, 16, *compatible) + 1;
// Dmsg3(100, "get_auth: chal=%s pw=%s hmac=%s\n", chal, password, bs->msg);
   if (!bs->send()) {
      Dmsg1(dbglvl, "Send challenge failed. ERR=%s\n", bs->bstrerror());
      return false;
   }
   Dmsg1(99, "sending resp to challenge: %s\n", bs->msg);
   if (bs->wait_data(180) <= 0 || bs->recv() <= 0) {
      Dmsg1(dbglvl, "Receive chanllenge response failed. ERR=%s\n", bs->bstrerror());
      bmicrosleep(5, 0);
      return false;
   }
   if (bstrcmp(bs->msg, "1000 OK auth\n")) {
      return true;
   }
   Dmsg1(dbglvl, "Received bad response: %s\n", bs->msg);
   bmicrosleep(5, 0);
   return false;
}
Beispiel #3
0
/*
 * Connection request. We accept connections either from the
 * Director, Storage Daemon or a Client (File daemon).
 *
 * Note, we are running as a seperate thread of the Storage daemon.
 *
 * Basic tasks done here:
 *  - If it was a connection from the FD, call handle_filed_connection()
 *  - If it was a connection from another SD, call handle_stored_connection()
 *  - Otherwise it was a connection from the DIR, call handle_director_connection()
 */
static void *handle_connection_request(void *arg)
{
   BSOCK *bs = (BSOCK *)arg;
   char name[MAX_NAME_LENGTH];
   char tbuf[MAX_TIME_LENGTH];

   if (bs->recv() <= 0) {
      Emsg1(M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who());
      bmicrosleep(5, 0);   /* make user wait 5 seconds */
      bs->close();
      return NULL;
   }

   /*
    * Do a sanity check on the message received
    */
   if (bs->msglen < MIN_MSG_LEN || bs->msglen > MAX_MSG_LEN) {
      Dmsg1(000, "<filed: %s", bs->msg);
      Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), bs->who(), bs->msglen);
      bmicrosleep(5, 0);   /* make user wait 5 seconds */
      bs->close();
      return NULL;
   }

   Dmsg1(110, "Conn: %s", bs->msg);

   /*
    * See if this is a File daemon connection. If so call FD handler.
    */
   if (sscanf(bs->msg, "Hello Start Job %127s", name) == 1) {
      Dmsg1(110, "Got a FD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
      return handle_filed_connection(bs, name);
   }

   /*
    * See if this is a Storage daemon connection. If so call SD handler.
    */
   if (sscanf(bs->msg, "Hello Start Storage Job %127s", name) == 1) {
      Dmsg1(110, "Got a SD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));
      return handle_stored_connection(bs, name);
   }

   Dmsg1(110, "Got a DIR connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), (utime_t)time(NULL)));

   return handle_director_connection(bs);
}
Beispiel #4
0
int32_t read_nbytes(BSOCK * bsock, char *ptr, int32_t nbytes)
{
   int32_t nleft, nread;

#ifdef HAVE_TLS
   if (bsock->tls) {
      /* TLS enabled */
      return (tls_bsock_readn(bsock, ptr, nbytes));
   }
#endif /* HAVE_TLS */

   nleft = nbytes;
   while (nleft > 0) {
      errno = 0;
      nread = socketRead(bsock->m_fd, ptr, nleft);
      if (bsock->is_timed_out() || bsock->is_terminated()) {
         return -1;
      }

#ifdef HAVE_WIN32
      /*
       * For Windows, we must simulate Unix errno on a socket
       *  error in order to handle errors correctly.
       */
      if (nread == SOCKET_ERROR) {
        DWORD err = WSAGetLastError();
        nread = -1;
        if (err == WSAEINTR) {
           errno = EINTR;
        } else if (err == WSAEWOULDBLOCK) {
           errno = EAGAIN;
        } else {
           errno = EIO;            /* some other error */
        }
     }
#endif

      if (nread == -1) {
         if (errno == EINTR) {
            continue;
         }
         if (errno == EAGAIN) {
            bmicrosleep(0, 20000);  /* try again in 20ms */
            continue;
         }
      }
      if (nread <= 0) {
         return -1;                /* error, or EOF */
      }
      nleft -= nread;
      ptr += nread;
      if (bsock->use_bwlimit()) {
         bsock->control_bwlimit(nread);
      }
   }
   return nbytes - nleft;          /* return >= 0 */
}
Beispiel #5
0
/*
 * Inititiate the message channel with the Director.
 * He has made a connection to our server.
 *
 * Basic tasks done here:
 *   Assume the Hello message is already in the input
 *     buffer.  We then authenticate him.
 *   Get device, media, and pool information from Director
 *
 *   This is the channel across which we will send error
 *     messages and job status information.
 */
int authenticate_director(JCR *jcr)
{
   BSOCK *dir = jcr->dir_bsock;

   if (!authenticate(R_DIRECTOR, dir, jcr)) {
      dir->fsend("%s", Dir_sorry);
      Dmsg1(dbglvl, "Unable to authenticate Director at %s.\n", dir->who());
      Jmsg1(jcr, M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who());
      bmicrosleep(5, 0);
      return 0;
   }
   return dir->fsend("%s", OK_hello);
}
Beispiel #6
0
/*
 * Try to connect to host for max_retry_time at retry_time intervals.
 *   Note, you must have called the constructor prior to calling
 *   this routine.
 */
bool BSOCK::connect(JCR * jcr, int retry_interval, utime_t max_retry_time,
                    utime_t heart_beat,
                    const char *name, char *host, char *service, int port,
                    int verbose)
{
   bool ok = false;
   int i;
   int fatal = 0;
   time_t begin_time = time(NULL);
   time_t now;
   btimer_t *tid = NULL;

   /* Try to trap out of OS call when time expires */
   if (max_retry_time) {
      tid = start_thread_timer(jcr, pthread_self(), (uint32_t)max_retry_time);
   }
   
   for (i = 0; !open(jcr, name, host, service, port, heart_beat, &fatal);
        i -= retry_interval) {
      berrno be;
      if (fatal || (jcr && job_canceled(jcr))) {
         goto bail_out;
      }
      Dmsg4(100, "Unable to connect to %s on %s:%d. ERR=%s\n",
            name, host, port, be.bstrerror());
      if (i < 0) {
         i = 60 * 5;               /* complain again in 5 minutes */
         if (verbose)
            Qmsg4(jcr, M_WARNING, 0, _(
               "Could not connect to %s on %s:%d. ERR=%s\n"
               "Retrying ...\n"), name, host, port, be.bstrerror());
      }
      bmicrosleep(retry_interval, 0);
      now = time(NULL);
      if (begin_time + max_retry_time <= now) {
         Qmsg4(jcr, M_FATAL, 0, _("Unable to connect to %s on %s:%d. ERR=%s\n"),
               name, host, port, be.bstrerror());
         goto bail_out;
      }
   }
   ok = true;

bail_out:
   if (tid) {
      stop_thread_timer(tid);
   }
   return ok;
}
Beispiel #7
0
/*
 * Takes base_name and appends (unique) current
 *   date and time to form unique job name.
 *
 *  Note, the seconds are actually a sequence number. This
 *   permits us to start a maximum fo 59 unique jobs a second, which
 *   should be sufficient.
 *
 *  Returns: unique job name in jcr->Job
 *    date/time in jcr->start_time
 */
void create_unique_job_name(JCR *jcr, const char *base_name)
{
   /* Job start mutex */
   static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
   static time_t last_start_time = 0;
   static int seq = 0;
   time_t now = time(NULL);
   struct tm tm;
   char dt[MAX_TIME_LENGTH];
   char name[MAX_NAME_LENGTH];
   char *p;
   int len;

   /* Guarantee unique start time -- maximum one per second, and
    * thus unique Job Name
    */
   P(mutex);                          /* lock creation of jobs */
   seq++;
   if (seq > 59) {                    /* wrap as if it is seconds */
      seq = 0;
      while (now == last_start_time) {
         bmicrosleep(0, 500000);
         now = time(NULL);
      }
   }
   last_start_time = now;
   V(mutex);                          /* allow creation of jobs */
   jcr->start_time = now;
   /* Form Unique JobName */
   (void)localtime_r(&now, &tm);
   /* Use only characters that are permitted in Windows filenames */
   strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
   len = strlen(dt) + 5;   /* dt + .%02d EOS */
   bstrncpy(name, base_name, sizeof(name));
   name[sizeof(name)-len] = 0;          /* truncate if too long */
   bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
   /* Convert spaces into underscores */
   for (p=jcr->Job; *p; p++) {
      if (*p == ' ') {
         *p = '_';
      }
   }
   Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
}
Beispiel #8
0
/*********************************************************************
 *
 *         Main Bareos Scheduler
 *
 */
JCR *wait_for_next_job(char *one_shot_job_to_run)
{
   JCR *jcr;
   JOBRES *job;
   RUNRES *run;
   time_t now, prev;
   static bool first = true;
   job_item *next_job = NULL;

   Dmsg0(dbglvl, "Enter wait_for_next_job\n");
   if (first) {
      first = false;
      /* Create scheduled jobs list */
      jobs_to_run = New(dlist(next_job, &next_job->link));
      if (one_shot_job_to_run) {            /* one shot */
         job = (JOBRES *)GetResWithName(R_JOB, one_shot_job_to_run);
         if (!job) {
            Emsg1(M_ABORT, 0, _("Job %s not found\n"), one_shot_job_to_run);
         }
         Dmsg1(5, "Found one_shot_job_to_run %s\n", one_shot_job_to_run);
         jcr = new_jcr(sizeof(JCR), dird_free_jcr);
         set_jcr_defaults(jcr, job);
         return jcr;
      }
   }

   /* Wait until we have something in the
    * next hour or so.
    */
again:
   while (jobs_to_run->empty()) {
      find_runs();
      if (!jobs_to_run->empty()) {
         break;
      }
      bmicrosleep(next_check_secs, 0); /* recheck once per minute */
   }

#ifdef  list_chain
   job_item *je;
   foreach_dlist(je, jobs_to_run) {
      dump_job(je, _("Walk queue"));
   }
Beispiel #9
0
Datei: dird.c Projekt: AlD/bareos
/* Cleanup and then exit */
void terminate_dird(int sig)
{
   static bool already_here = false;

   if (already_here) {                /* avoid recursive temination problems */
      bmicrosleep(2, 0);              /* yield */
      exit(1);
   }
   already_here = true;
   debug_level = 0;                   /* turn off debug */
   stop_watchdog();
   db_sql_pool_destroy();
   db_flush_backends();
   unload_dir_plugins();
   write_state_file(me->working_directory, "bareos-dir", get_first_port_host_order(me->DIRaddrs));
   delete_pid_file(me->pid_directory, "bareos-dir", get_first_port_host_order(me->DIRaddrs));
   term_scheduler();
   term_job_server();
   if (runjob) {
      free(runjob);
   }
   if (configfile != NULL) {
      free(configfile);
   }
   if (debug_level > 5) {
      print_memory_pool_stats();
   }
   if (my_config) {
      my_config->free_resources();
      free(my_config);
      my_config = NULL;
   }
   stop_UA_server();
   term_msg();                        /* terminate message handler */
   cleanup_crypto();
   close_memory_pool();               /* release free memory in pool */
   lmgr_cleanup_main();
   sm_dump(false);
   exit(sig);
}
Beispiel #10
0
/*
 * First prove our identity to the Storage daemon, then
 * make him prove his identity.
 */
int authenticate_storagedaemon(JCR *jcr)
{
   BSOCK *sd = jcr->store_bsock;
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   int compatible = true;
   bool auth_success = false;

   btimer_t *tid = start_bsock_timer(sd, AUTH_TIMEOUT);

   /* TLS Requirement */
   if (have_tls && me->tls_enable) {
      if (me->tls_require) {
         tls_local_need = BNET_TLS_REQUIRED;
      } else {
         tls_local_need = BNET_TLS_OK;
      }
   }

   if (me->tls_authenticate) {
      tls_local_need = BNET_TLS_REQUIRED;
   }

   if (job_canceled(jcr)) {
      auth_success = false;     /* force quick exit */
      goto auth_fatal;
   }

   /* Respond to SD challenge */
   auth_success = cram_md5_respond(sd, jcr->sd_auth_key, &tls_remote_need, &compatible);
   if (job_canceled(jcr)) {
      auth_success = false;     /* force quick exit */
      goto auth_fatal;
   }
   if (!auth_success) {
      Dmsg1(dbglvl, "cram_respond failed for %s\n", sd->who());
   } else {
      /* Now challenge him */
      auth_success = cram_md5_challenge(sd, jcr->sd_auth_key, tls_local_need, compatible);
      if (!auth_success) {
         Dmsg1(dbglvl, "cram_challenge failed for %s\n", sd->who());
      }
   }

   if (!auth_success) {
      Jmsg(jcr, M_FATAL, 0, _("Authorization key rejected by Storage daemon.\n"
       "Please see " MANUAL_AUTH_URL " for help.\n"));
      goto auth_fatal;
   }

   /* Verify that the remote host is willing to meet our TLS requirements */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
           " advertize required TLS support.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   /* Verify that we are willing to meet the remote host's requirements */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      /* Engage TLS! Full Speed Ahead! */
      if (!bnet_tls_client(me->tls_ctx, sd, NULL)) {
         Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
         auth_success = false;
         goto auth_fatal;
      }
      if (me->tls_authenticate) {           /* tls authentication only? */
         sd->free_tls();                    /* yes, shutdown tls */
      }
   }

auth_fatal:
   /* Destroy session key */
   memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
   stop_bsock_timer(tid);
   /* Single thread all failures to avoid DOS */
   if (!auth_success) {
      P(mutex);
      bmicrosleep(6, 0);
      V(mutex);
   }
   return auth_success;
}
Beispiel #11
0
/* Update the free space on the device */
bool DEVICE::update_freespace() 
{
   POOL_MEM ocmd(PM_FNAME);
   POOLMEM* results;
   char* icmd;
   int timeout;
   uint64_t free;
   char ed1[50];
   bool ok = false;
   int status;

   if (!is_dvd() || is_freespace_ok()) {
      return true;
   }
   
   /* The device must be mounted in order to dvd-freespace to work */
   mount(1);
   
   Dsm_check(400);
   icmd = device->free_space_command;
   
   if (!icmd) {
      free_space = 0;
      free_space_errno = 0;
      clear_freespace_ok();              /* No valid freespace */
      clear_media();
      Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
            edit_uint64(free_space, ed1), free_space_errno);
      Mmsg(errmsg, _("No FreeSpace command defined.\n"));
      return false;
   }
   
   edit_mount_codes(ocmd, icmd);
   
   Dmsg1(29, "update_freespace: cmd=%s\n", ocmd.c_str());

   results = get_pool_memory(PM_MESSAGE);
   
   /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
   timeout = 3;
   
   while (1) {
      berrno be;
      Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
      status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results);
      Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
      if (status == 0) {
         free = str_to_int64(results);
         Dmsg1(400, "Free space program run: Freespace=%s\n", results);
         if (free >= 0) {
            free_space = free;
            free_space_errno = 0;
            set_freespace_ok();     /* have valid freespace */
            set_media();
            Mmsg(errmsg, "");
            ok = true;
            break;
         }
      }
      free_space = 0;
      free_space_errno = EPIPE;
      clear_freespace_ok();         /* no valid freespace */
      Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), 
            results, be.bstrerror(status));
      
      if (--timeout > 0) {
         Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
            "free_space_errno=%d ERR=%s\n", print_name(), 
               edit_uint64(free_space, ed1), free_space_errno, 
               errmsg);
         bmicrosleep(1, 0);
         continue;
      }

      dev_errno = free_space_errno;
      Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
         "free_space_errno=%d ERR=%s\n",
            print_name(), edit_uint64(free_space, ed1),
            free_space_errno, errmsg);
      break;
   }
   
   free_pool_memory(results);
   Dmsg4(29, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
      edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media());
   Dsm_check(400);
   return ok;
}
Beispiel #12
0
/*
 * Close both pipes and free resources
 *
 *  Returns: 0 on success
 *           berrno on failure
 */
int close_bpipe(BPIPE *bpipe)
{
   int chldstatus = 0;
   int stat = 0;
   int wait_option;
   int remaining_wait;
   pid_t wpid = 0;


   /* Close pipes */
   if (bpipe->rfd) {
      fclose(bpipe->rfd);
      bpipe->rfd = NULL;
   }
   if (bpipe->wfd) {
      fclose(bpipe->wfd);
      bpipe->wfd = NULL;
   }

   if (bpipe->wait == 0) {
      wait_option = 0;                /* wait indefinitely */
   } else {
      wait_option = WNOHANG;          /* don't hang */
   }
   remaining_wait = bpipe->wait;

   /* wait for worker child to exit */
   for ( ;; ) {
      Dmsg2(800, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
      do {
         wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
      } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
      if (wpid == bpipe->worker_pid || wpid == -1) {
         berrno be;
         stat = errno;
         Dmsg3(800, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
            wpid==-1?be.bstrerror():"none");
         break;
      }
      Dmsg3(800, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
            wpid==-1?strerror(errno):"none");
      if (remaining_wait > 0) {
         bmicrosleep(1, 0);           /* wait one second */
         remaining_wait--;
      } else {
         stat = ETIME;                /* set error status */
         wpid = -1;
         break;                       /* don't wait any longer */
      }
   }
   if (wpid > 0) {
      if (WIFEXITED(chldstatus)) {    /* process exit()ed */
         stat = WEXITSTATUS(chldstatus);
         if (stat != 0) {
            Dmsg1(800, "Non-zero status %d returned from child.\n", stat);
            stat |= b_errno_exit;        /* exit status returned */
         }
         Dmsg1(800, "child status=%d\n", stat & ~b_errno_exit);
      } else if (WIFSIGNALED(chldstatus)) {  /* process died */
#ifndef HAVE_WIN32
         stat = WTERMSIG(chldstatus);
#else
         stat = 1;                    /* fake child status */
#endif
         Dmsg1(800, "Child died from signal %d\n", stat);
         stat |= b_errno_signal;      /* exit signal returned */
      }
   }
   if (bpipe->timer_id) {
      stop_child_timer(bpipe->timer_id);
   }
   free(bpipe);
   Dmsg2(800, "returning stat=%d,%d\n", stat & ~(b_errno_exit|b_errno_signal), stat);
   return stat;
}
Beispiel #13
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:
      bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN\n");
      if (io->flags & (O_CREAT | O_WRONLY)) {
         char *writer_codes = apply_rp_codes(p_ctx);

         p_ctx->fd = popen(writer_codes, "w");
         bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%d writer=%s\n",
             p_ctx->fd, writer_codes);
         if (!p_ctx->fd) {
            io->io_errno = errno;
            bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
               "Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(errno));
            if (writer_codes) {
               free(writer_codes);
            }
            return bRC_Error;
         }
         if (writer_codes) {
            free(writer_codes);
         }
      } else {
         p_ctx->fd = popen(p_ctx->reader, "r");
         bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n",
            p_ctx->fd, p_ctx->reader);
         if (!p_ctx->fd) {
            io->io_errno = errno;
            bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
               "Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
            return bRC_Error;
         }
      }
      bmicrosleep(1,0);         /* let pipe connect */
      break;

   case IO_READ:
      if (!p_ctx->fd) {
         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD\n");
         return bRC_Error;
      }
      io->status = fread(io->buf, 1, io->count, p_ctx->fd);
//    bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
      if (io->status == 0 && ferror(p_ctx->fd)) {
         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
            "Pipe read error: ERR=%s\n", strerror(errno));
         bfuncs->DebugMessage(ctx, fi, li, dbglvl,
            "Pipe read error: ERR=%s\n", strerror(errno));
         return bRC_Error;
      }
      break;

   case IO_WRITE:
      if (!p_ctx->fd) {
         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD\n");
         return bRC_Error;
      }
//    printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d\n", p_ctx->fd, io->buf, io->count);
      io->status = fwrite(io->buf, 1, io->count, p_ctx->fd);
//    printf("bpipe-fd: IO_WRITE buf=%p len=%d\n", io->buf, io->status);
      if (io->status == 0 && ferror(p_ctx->fd)) {
         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
            "Pipe write error\n");
         bfuncs->DebugMessage(ctx, fi, li, dbglvl,
            "Pipe read error: ERR=%s\n", strerror(errno));
         return bRC_Error;
      }
      break;

   case IO_CLOSE:
      if (!p_ctx->fd) {
         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close\n");
         return bRC_Error;
      }
      io->status = pclose(p_ctx->fd);
      break;

   case IO_SEEK:
      io->offset = p_ctx->offset;
      break;
   }
   return bRC_OK;
}
Beispiel #14
0
void *handle_stored_connection(BSOCK *sd)
{
   JCR *jcr;
   char job_name[MAX_NAME_LENGTH];

   /*
    * Do a sanity check on the message received
    */
   if (sd->msglen < 25 || sd->msglen > 256) {
      Dmsg1(000, "<filed: %s", sd->msg);
      Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), sd->who(), sd->msglen);
      bmicrosleep(5, 0);   /* make user wait 5 seconds */
      sd->close();
      return NULL;
   }

   if (sscanf(sd->msg, "Hello Storage calling Start Job %127s", job_name) != 1) {
      char addr[64];
      char *who = bnet_get_peer(sd, addr, sizeof(addr)) ? sd->who() : addr;

      sd->msg[100] = 0;
      Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n", sd->who(), sd->msg);
      Jmsg2(NULL, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"), who, sd->msg);
      sd->close();
      return NULL;
   }

   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();
      return NULL;
   }

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

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

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

   if (!jcr->max_bandwidth) {
      if (jcr->director->max_bandwidth_per_job) {
         jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
      } else if (me->max_bandwidth_per_job) {
         jcr->max_bandwidth = me->max_bandwidth_per_job;
      }
   }

   sd->set_bwlimit(jcr->max_bandwidth);
   if (me->allow_bw_bursting) {
      sd->set_bwlimit_bursting();
   }

   free_jcr(jcr);

   return NULL;
}
/*
 * Rewind the device.
 *
 * Returns: true  on success
 *          false on failure
 */
bool generic_tape_device::rewind(DCR *dcr)
{
   struct mtop mt_com;
   unsigned int i;
   bool first = true;

   Dmsg3(400, "rewind res=%d fd=%d %s\n", num_reserved(), m_fd, prt_name);
   state &= ~(ST_EOT | ST_EOF | ST_WEOT); /* Remove EOF/EOT flags */
   block_num = file = 0;
   file_size = 0;
   file_addr = 0;
   if (m_fd < 0) {
      return false;
   }

   mt_com.mt_op = MTREW;
   mt_com.mt_count = 1;

   /*
    * If we get an I/O error on rewind, it is probably because
    * the drive is actually busy. We loop for (about 5 minutes)
    * retrying every 5 seconds.
    */
   for (i = max_rewind_wait; ; i -= 5) {
      if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) {
         berrno be;

         clrerror(mt_com.mt_op);
         if (i == max_rewind_wait) {
            Dmsg1(200, "Rewind error, %s. retrying ...\n", be.bstrerror());
         }
         /*
          * This is a gross hack, because if the user has the
          * device mounted (i.e. open), then uses mtx to load
          * a tape, the current open file descriptor is invalid.
          * So, we close the drive and re-open it.
          */
         if (first && dcr) {
            int oo_mode = open_mode;
            d_close(m_fd);
            clear_opened();
            open(dcr, oo_mode);
            if (m_fd < 0) {
               return false;
            }
            first = false;
            continue;
         }
#ifdef HAVE_SUN_OS
         if (dev_errno == EIO) {
            Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), prt_name);
            return false;
         }
#else
         if (dev_errno == EIO && i > 0) {
            Dmsg0(200, "Sleeping 5 seconds.\n");
            bmicrosleep(5, 0);
            continue;
         }
#endif
         Mmsg2(errmsg, _("Rewind error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
         return false;
      }
      break;
   }

   return true;
}
Beispiel #16
0
bool run_cmd(JCR *jcr)
{
   struct timeval tv;
   struct timezone tz;
   struct timespec timeout;
   int errstat = 0;
   BSOCK *cl;
   int fd_version = 0;
   int sd_version = 0;
   char job_name[500];
   int i;
   int stat;

   Dsm_check(200);
   Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg);

   /* If we do not need the FD, we are doing a virtual backup. */
   if (jcr->no_client_used()) {
      do_vbackup(jcr);
      return false;
   }

   jcr->sendJobStatus(JS_WaitFD);          /* wait for FD to connect */

   Dmsg2(050, "sd_calls_client=%d sd_client=%d\n", jcr->sd_calls_client, jcr->sd_client);
   if (jcr->sd_calls_client) {
      /* We connected to Client, so finish work */
      cl = jcr->file_bsock;
      if (!cl) {
         Jmsg0(jcr, M_FATAL, 0, _("Client socket not open. Could not connect to Client.\n"));
         Dmsg0(050, "Client socket not open. Could not connect to Client.\n");
         return false;
      }
      /* Get response to Hello command sent earlier */
      Dmsg0(050, "Read Hello command from Client\n");
      for (i=0; i<60; i++) {
         stat = cl->recv();
         if (stat <= 0) {
            bmicrosleep(1, 0);
         } else {
            break;
         }
      }
      if (stat <= 0) {
         berrno be;
         Jmsg1(jcr, M_FATAL, 0, _("Recv request to Client failed. ERR=%s\n"),
            be.bstrerror());
         Dmsg1(050, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror());
         return false;
      }
      Dmsg1(050, "Got from FD: %s\n", cl->msg);
      if (sscanf(cl->msg, "Hello Bacula SD: Start Job %127s %d %d", job_name, &fd_version, &sd_version) != 3) {
         Jmsg1(jcr, M_FATAL, 0, _("Bad Hello from Client: %s.\n"), cl->msg);
         Dmsg1(050, _("Bad Hello from Client: %s.\n"), cl->msg);
         return false;
      }
      unbash_spaces(job_name);
      jcr->FDVersion = fd_version;
      jcr->SDVersion = sd_version;
      Dmsg1(050, "FDVersion=%d\n", fd_version);

      /*
       * Authenticate the File daemon
       */
      Dmsg0(050, "=== Authenticate FD\n");
      if (jcr->authenticated || !authenticate_filed(jcr)) {
         Dmsg1(050, "Authentication failed Job %s\n", jcr->Job);
         Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
      } else {
         jcr->authenticated = true;
      }
   } else if (!jcr->sd_client) {
      /* We wait to receive connection from Client */
      gettimeofday(&tv, &tz);
      timeout.tv_nsec = tv.tv_usec * 1000;
      timeout.tv_sec = tv.tv_sec + me->client_wait;

      Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n",
            jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key);

      Dmsg3(800, "=== Block Job=%s jid=%d %p\n", jcr->Job, jcr->JobId, jcr);

      /*
       * Wait for the File daemon to contact us to start the Job,
       *  when he does, we will be released, unless the 30 minutes
       *  expires.
       */
      P(mutex);
      while ( !jcr->authenticated && !job_canceled(jcr) ) {
         errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
         if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
            break;
         }
         Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
      }
      Dmsg4(050, "=== Auth=%d jid=%d canceled=%d errstat=%d\n",
         jcr->JobId, jcr->authenticated, job_canceled(jcr), errstat);
      V(mutex);
      Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
   }

   memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));

   if (jcr->authenticated && !job_canceled(jcr)) {
      Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr);
      run_job(jcr);                   /* Run the job */
   }
   Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr);
   return false;
}
Beispiel #17
0
/*
 * See who is connecting and lookup the authentication information.
 * First make him prove his identity and then prove our identity to the Remote daemon.
 */
static inline bool two_way_authenticate(int rcode, BSOCK *bs, JCR* jcr)
{
   POOLMEM *dirname = get_pool_memory(PM_MESSAGE);
   DIRRES *director = NULL;
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   bool compatible = true;                /* Want md5 compatible DIR */
   bool auth_success = false;
   alist *verify_list = NULL;
   btimer_t *tid = NULL;

   if (rcode != R_DIRECTOR) {
      Dmsg1(dbglvl, "I only authenticate directors, not %d\n", rcode);
      Jmsg1(jcr, M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode);
      goto auth_fatal;
   }

   if (bs->msglen < 25 || bs->msglen > 500) {
      Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
            bs->who(), bs->msglen);
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
             who, bs->msglen);
      goto auth_fatal;
   }
   dirname = check_pool_memory_size(dirname, bs->msglen);

   if (sscanf(bs->msg, "Hello Director %s calling", dirname) != 1) {
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      bs->msg[100] = 0;
      Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
            bs->who(), bs->msg);
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
            who, bs->msg);
      goto auth_fatal;
   }
   unbash_spaces(dirname);
   foreach_res(director, R_DIRECTOR) {
      if (bstrcmp(director->hdr.name, dirname))
         break;
   }
   if (!director) {
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"),
            dirname, who);
      goto auth_fatal;
   }

   if (have_tls) {
      /*
       * TLS Requirement
       */
      if (director->tls_enable) {
         if (director->tls_require) {
            tls_local_need = BNET_TLS_REQUIRED;
         } else {
            tls_local_need = BNET_TLS_OK;
         }
      }

      if (director->tls_authenticate) {
         tls_local_need = BNET_TLS_REQUIRED;
      }

      if (director->tls_verify_peer) {
         verify_list = director->tls_allowed_cns;
      }
   }

   /*
    * Timeout Hello after 10 min
    */
   tid = start_bsock_timer(bs, AUTH_TIMEOUT);

   /*
    * Sanity check.
    */
   ASSERT(director->password.encoding == p_encoding_md5);

   /*
    * Challenge the director
    */
   auth_success = cram_md5_challenge(bs, director->password.value, tls_local_need, compatible);
   if (job_canceled(jcr)) {
      auth_success = false;
      goto auth_fatal;                   /* quick exit */
   }

   if (auth_success) {
      auth_success = cram_md5_respond(bs, director->password.value, &tls_remote_need, &compatible);
      if (!auth_success) {
          char addr[64];
          char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
          Dmsg1(dbglvl, "cram_get_auth failed for %s\n", who);
      }
   } else {
       char addr[64];
       char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
       Dmsg1(dbglvl, "cram_auth failed for %s\n", who);
   }

   if (!auth_success) {
       Emsg1(M_FATAL, 0, _("Incorrect password given by Director at %s.\n"),
             bs->who());
       goto auth_fatal;
   }

   /*
    * Verify that the remote host is willing to meet our TLS requirements
    */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
           " advertize required TLS support.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   /*
    * Verify that we are willing to meet the remote host's requirements
    */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      /*
       * Engage TLS! Full Speed Ahead!
       */
      if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
         Jmsg0(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
         auth_success = false;
         goto auth_fatal;
      }
      if (director->tls_authenticate) {         /* authentication only? */
         bs->free_tls();                        /* shutodown tls */
      }
   }

auth_fatal:
   if (tid) {
      stop_bsock_timer(tid);
      tid = NULL;
   }
   free_pool_memory(dirname);
   jcr->director = director;

   /*
    * Single thread all failures to avoid DOS
    */
   if (!auth_success) {
      P(mutex);
      bmicrosleep(6, 0);
      V(mutex);
   }

   return auth_success;
}
Beispiel #18
0
/*
 * Open a fifo device
 */
void win32_fifo_device::open_device(DCR *dcr, int omode)
{
   file_size = 0;
   int timeout = max_open_wait;
   utime_t start_time = time(NULL);

   mount(dcr, 1);                     /* do mount if required */

   Dmsg0(100, "Open dev: device is fifo\n");

   get_autochanger_loaded_slot(dcr);

   open_mode = omode;
   set_mode(omode);

   if (timeout < 1) {
      timeout = 1;
   }
   errno = 0;

   if (timeout) {
      /*
       * Set open timer
       */
      tid = start_thread_timer(dcr->jcr, pthread_self(), timeout);
   }

   Dmsg2(100, "Try open %s mode=%s\n", prt_name, mode_to_str(omode));

   /*
    * If busy retry each second for max_open_wait seconds
    */
   for ( ;; ) {
      /*
       * Try non-blocking open
       */
      m_fd = d_open(dev_name, oflags | O_NONBLOCK, 0);
      if (m_fd < 0) {
         berrno be;
         dev_errno = errno;
         Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n",
               prt_name, omode, oflags, errno, be.bstrerror());
      } else {
         d_close(m_fd);
         m_fd = d_open(dev_name, oflags, 0); /* open normally */
         if (m_fd < 0) {
            berrno be;
            dev_errno = errno;
            Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n",
                  prt_name, omode, oflags, errno, be.bstrerror());
            break;
         }
         dev_errno = 0;
         lock_door();
         break;                               /* Successfully opened and rewound */
      }
      bmicrosleep(5, 0);

      /*
       * Exceed wait time ?
       */
      if (time(NULL) - start_time >= max_open_wait) {
         break;                       /* yes, get out */
      }
   }

   if (!is_open()) {
      berrno be;
      Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"),
            prt_name, be.bstrerror(dev_errno));
      Dmsg1(100, "%s", errmsg);
   }

   /*
    * Stop any open() timer we started
    */
   if (tid) {
      stop_thread_timer(tid);
      tid = 0;
   }

   Dmsg1(100, "open dev: fifo %d opened\n", m_fd);
}
Beispiel #19
0
/*
 * Check for duplicate jobs.
 *  Returns: true  if current job should continue
 *           false if current job should terminate
 */
bool allow_duplicate_job(JCR *jcr)
{
   JCR *djcr;                /* possible duplicate job */
   JOBRES *job = jcr->res.job;
   bool cancel_dup = false;
   bool cancel_me = false;

   /*
    * See if AllowDuplicateJobs is set or
    * if duplicate checking is disabled for this job.
    */
   if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
      return true;
   }

   Dmsg0(800, "Enter allow_duplicate_job\n");

   /*
    * After this point, we do not want to allow any duplicate
    * job to run.
    */

   foreach_jcr(djcr) {
      if (jcr == djcr || djcr->JobId == 0) {
         continue;                   /* do not cancel this job or consoles */
      }

      /*
       * See if this Job has the IgnoreDuplicateJobChecking flag set, ignore it
       * for any checking against other jobs.
       */
      if (djcr->IgnoreDuplicateJobChecking) {
         continue;
      }

      if (bstrcmp(job->name(), djcr->res.job->name())) {
         if (job->DuplicateJobProximity > 0) {
            utime_t now = (utime_t)time(NULL);
            if ((now - djcr->start_time) > job->DuplicateJobProximity) {
               continue;               /* not really a duplicate */
            }
         }
         if (job->CancelLowerLevelDuplicates &&
             djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
            switch (jcr->getJobLevel()) {
            case L_FULL:
               if (djcr->getJobLevel() == L_DIFFERENTIAL ||
                   djcr->getJobLevel() == L_INCREMENTAL) {
                  cancel_dup = true;
               }
               break;
            case L_DIFFERENTIAL:
               if (djcr->getJobLevel() == L_INCREMENTAL) {
                  cancel_dup = true;
               }
               if (djcr->getJobLevel() == L_FULL) {
                  cancel_me = true;
               }
               break;
            case L_INCREMENTAL:
               if (djcr->getJobLevel() == L_FULL ||
                   djcr->getJobLevel() == L_DIFFERENTIAL) {
                  cancel_me = true;
               }
            }
            /*
             * cancel_dup will be done below
             */
            if (cancel_me) {
              /* Zap current job */
              jcr->setJobStatus(JS_Canceled);
              Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
                 djcr->JobId);
              break;     /* get out of foreach_jcr */
            }
         }

         /*
          * Cancel one of the two jobs (me or dup)
          * If CancelQueuedDuplicates is set do so only if job is queued.
          */
         if (job->CancelQueuedDuplicates) {
             switch (djcr->JobStatus) {
             case JS_Created:
             case JS_WaitJobRes:
             case JS_WaitClientRes:
             case JS_WaitStoreRes:
             case JS_WaitPriority:
             case JS_WaitMaxJobs:
             case JS_WaitStartTime:
                cancel_dup = true;  /* cancel queued duplicate */
                break;
             default:
                break;
             }
         }

         if (cancel_dup || job->CancelRunningDuplicates) {
            /*
             * Zap the duplicated job djcr
             */
            UAContext *ua = new_ua_context(jcr);
            Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
            cancel_job(ua, djcr);
            bmicrosleep(0, 500000);
            djcr->setJobStatus(JS_Canceled);
            cancel_job(ua, djcr);
            free_ua_context(ua);
            Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
         } else {
            /*
             * Zap current job
             */
            jcr->setJobStatus(JS_Canceled);
            Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
               djcr->JobId);
            Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
         }
         Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
               jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
         break;                 /* did our work, get out of foreach loop */
      }
   }
   endeach_jcr(djcr);

   return true;
}
Beispiel #20
0
/*
 * Handle signals here
 */
extern "C" void signal_handler(int sig)
{
   static int already_dead = 0;
   int chld_status=-1;
   utime_t now;

   /* If we come back more than once, get out fast! */
   if (already_dead) {
      exit(1);
   }
   Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]);
   /* Ignore certain signals -- SIGUSR2 used to interrupt threads */
   if (sig == SIGCHLD || sig == SIGUSR2) {
      return;
   }
   /* FreeBSD seems to generate a signal of 0, which is of course undefined */
   if (sig == 0) {
      return;
   }
   already_dead++;
   /* Don't use Emsg here as it may lock and thus block us */
   if (sig == SIGTERM || sig == SIGINT) {
       syslog(LOG_DAEMON|LOG_ERR, "Shutting down Bacula service: %s ...\n", my_name);
   } else {
      fprintf(stderr, _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
      syslog(LOG_DAEMON|LOG_ERR,
         _("Bacula interrupted by signal %d: %s\n"), sig, get_signal_name(sig));
      /* Edit current time for showing in the dump */
      now = time(NULL);
      bstrftimes(fail_time, 30, now);
   }

#ifdef TRACEBACK
   if (sig != SIGTERM && sig != SIGINT) {
      struct sigaction sigdefault;
      static char *argv[5];
      static char pid_buf[20];
      static char btpath[400];
      char buf[400];
      pid_t pid;
      int exelen = strlen(exepath);

      fprintf(stderr, _("Kaboom! %s, %s got signal %d - %s at %s. Attempting traceback.\n"),
              exename, my_name, sig, get_signal_name(sig), fail_time);
      fprintf(stderr, _("Kaboom! exepath=%s\n"), exepath);

      if (exelen + 12 > (int)sizeof(btpath)) {
         bstrncpy(btpath, "btraceback", sizeof(btpath));
      } else {
         bstrncpy(btpath, exepath, sizeof(btpath));
         if (IsPathSeparator(btpath[exelen-1])) {
            btpath[exelen-1] = 0;
         }
         bstrncat(btpath, "/btraceback", sizeof(btpath));
      }
      if (!IsPathSeparator(exepath[exelen - 1])) {
         strcat(exepath, "/");
      }
      strcat(exepath, exename);
      if (!working_directory) {
         working_directory = buf;
         *buf = 0;
      }
      if (*working_directory == 0) {
         strcpy((char *)working_directory, "/tmp/");
      }
      if (chdir(working_directory) != 0) {  /* dump in working directory */
         berrno be;
         Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory,  be.bstrerror());
         strcpy((char *)working_directory, "/tmp/");
      }
      unlink("./core");               /* get rid of any old core file */

#ifdef DEVELOPER /* When DEVELOPER not set, this is done below */
      /* print information about the current state into working/<file>.lockdump */
      dbg_print_bacula();
#endif


      sprintf(pid_buf, "%d", (int)main_pid);
      Dmsg1(300, "Working=%s\n", working_directory);
      Dmsg1(300, "btpath=%s\n", btpath);
      Dmsg1(300, "exepath=%s\n", exepath);
      switch (pid = fork()) {
      case -1:                        /* error */
         fprintf(stderr, _("Fork error: ERR=%s\n"), strerror(errno));
         break;
      case 0:                         /* child */
         argv[0] = btpath;            /* path to btraceback */
         argv[1] = exepath;           /* path to exe */
         argv[2] = pid_buf;
         argv[3] = (char *)working_directory;
         argv[4] = (char *)NULL;
         fprintf(stderr, _("Calling: %s %s %s %s\n"), btpath, exepath, pid_buf,
            working_directory);
         if (execv(btpath, argv) != 0) {
            berrno be;
            printf(_("execv: %s failed: ERR=%s\n"), btpath, be.bstrerror());
         }
         exit(-1);
      default:                        /* parent */
         break;
      }

      /* Parent continue here, waiting for child */
      sigdefault.sa_flags = 0;
      sigdefault.sa_handler = SIG_DFL;
      sigfillset(&sigdefault.sa_mask);

      sigaction(sig,  &sigdefault, NULL);
      if (pid > 0) {
         Dmsg0(500, "Doing waitpid\n");
         waitpid(pid, &chld_status, 0);   /* wait for child to produce dump */
         Dmsg0(500, "Done waitpid\n");
      } else {
         Dmsg0(500, "Doing sleep\n");
         bmicrosleep(30, 0);
      }
      if (WEXITSTATUS(chld_status) == 0) {
         fprintf(stderr, _("It looks like the traceback worked...\n"));
      } else {
         fprintf(stderr, _("The btraceback call returned %d\n"),
                           WEXITSTATUS(chld_status));
      }
      /* If we want it printed, do so */
#ifdef direct_print
      if (prt_kaboom) {
         FILE *fd;
         snprintf(buf, sizeof(buf), "%s/%s.%s.traceback", working_directory, my_name, pid_buf);
         fd = fopen(buf, "r");
         if (fd != NULL) {
            printf("\n\n ==== Traceback output ====\n\n");
            while (fgets(buf, (int)sizeof(buf), fd) != NULL) {
               printf("%s", buf);
            }
            fclose(fd);
            printf(" ==== End traceback output ====\n\n");
         }
      }
#else
      if (prt_kaboom) {
         snprintf(buf, sizeof(buf), "/bin/cat %s/%s.%s.traceback", working_directory, my_name, pid_buf);
         fprintf(stderr, "\n\n ==== Traceback output ====\n\n");
         system(buf);
         fprintf(stderr, " ==== End traceback output ====\n\n");
      }
#endif

#ifndef DEVELOPER /* When DEVELOPER set, this is done above */
      /* print information about the current state into working/<file>.lockdump */
      dbg_print_bacula();
#endif

   }
#endif
   exit_handler(sig);
   Dmsg0(500, "Done exit_handler\n");
}
/*
 * Open a tape device
 */
void generic_tape_device::open_device(DCR *dcr, int omode)
{
   file_size = 0;
   int timeout = max_open_wait;
#if !defined(HAVE_WIN32)
   struct mtop mt_com;
   utime_t start_time = time(NULL);
#endif

   mount(dcr, 1);                     /* do mount if required */

   Dmsg0(100, "Open dev: device is tape\n");

   get_autochanger_loaded_slot(dcr);

   open_mode = omode;
   set_mode(omode);

   if (timeout < 1) {
      timeout = 1;
   }
   errno = 0;
   Dmsg2(100, "Try open %s mode=%s\n", prt_name, mode_to_str(omode));
#if defined(HAVE_WIN32)
   /*
    * Windows Code
    */
   if ((m_fd = d_open(dev_name, oflags, 0)) < 0) {
      dev_errno = errno;
   }
#else
   /*
    * UNIX Code
    *
    * If busy retry each second for max_open_wait seconds
    */
   for ( ;; ) {
      /*
       * Try non-blocking open
       */
      m_fd = d_open(dev_name, oflags | O_NONBLOCK, 0);
      if (m_fd < 0) {
         berrno be;
         dev_errno = errno;
         Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n",
               prt_name, omode, oflags, errno, be.bstrerror());
      } else {
         /*
          * Tape open, now rewind it
          */
         Dmsg0(100, "Rewind after open\n");
         mt_com.mt_op = MTREW;
         mt_com.mt_count = 1;

         /*
          * Rewind only if dev is a tape
          */
         if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) {
            berrno be;
            dev_errno = errno;           /* set error status from rewind */
            d_close(m_fd);
            clear_opened();
            Dmsg2(100, "Rewind error on %s close: ERR=%s\n", prt_name, be.bstrerror(dev_errno));
            /*
             * If we get busy, device is probably rewinding, try again
             */
            if (dev_errno != EBUSY) {
               break;                    /* error -- no medium */
            }
         } else {
            /*
             * Got fd and rewind worked, so we must have medium in drive
             */
            d_close(m_fd);
            m_fd = d_open(dev_name, oflags, 0); /* open normally */
            if (m_fd < 0) {
               berrno be;
               dev_errno = errno;
               Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n",
                     prt_name, omode, oflags, errno, be.bstrerror());
               break;
            }
            dev_errno = 0;
            lock_door();
            set_os_device_parameters(dcr);       /* do system dependent stuff */
            break;                               /* Successfully opened and rewound */
         }
      }
      bmicrosleep(5, 0);

      /*
       * Exceed wait time ?
       */
      if (time(NULL) - start_time >= max_open_wait) {
         break;                       /* yes, get out */
      }
   }
#endif

   if (!is_open()) {
      berrno be;
      Mmsg2(errmsg, _("Unable to open device %s: ERR=%s\n"),
            prt_name, be.bstrerror(dev_errno));
      Dmsg1(100, "%s", errmsg);
   }

   Dmsg1(100, "open dev: tape %d opened\n", m_fd);
}
Beispiel #22
0
/* Authorize other end
 * Codes that tls_local_need and tls_remote_need can take:
 *
 *   BNET_TLS_NONE     I cannot do tls
 *   BNET_TLS_OK       I can do tls, but it is not required on my end
 *   BNET_TLS_REQUIRED  tls is required on my end
 *
 *   Returns: false if authentication failed
 *            true if OK
 */
bool cram_md5_challenge(BSOCK *bs, const char *password, int tls_local_need, bool compatible)
{
   struct timeval t1;
   struct timeval t2;
   struct timezone tz;
   int i;
   bool ok;
   char chal[MAXSTRING];
   char host[MAXSTRING];
   uint8_t hmac[20];

   gettimeofday(&t1, &tz);
   for (i=0; i<4; i++) {
      gettimeofday(&t2, &tz);
   }
   srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff));
   if (!gethostname(host, sizeof(host))) {
      bstrncpy(host, my_name, sizeof(host));
   }
   /* Send challenge -- no hashing yet */
   bsnprintf(chal, sizeof(chal), "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host);
   if (compatible) {
      Dmsg2(dbglvl, "send: auth cram-md5 %s ssl=%d\n", chal, tls_local_need);
      if (!bs->fsend("auth cram-md5 %s ssl=%d\n", chal, tls_local_need)) {
         Dmsg1(dbglvl, "Bnet send challenge comm error. ERR=%s\n", bs->bstrerror());
         return false;
      }
   } else {
      /* Old non-compatible system */
      Dmsg2(dbglvl, "send: auth cram-md5 %s ssl=%d\n", chal, tls_local_need);
      if (!bs->fsend("auth cram-md5 %s ssl=%d\n", chal, tls_local_need)) {
         Dmsg1(dbglvl, "Bnet send challenge comm error. ERR=%s\n", bs->bstrerror());
         return false;
      }
   }

   /* Read hashed response to challenge */
   if (bs->wait_data(180) <= 0 || bs->recv() <= 0) {
      Dmsg1(dbglvl, "Bnet receive challenge response comm error. ERR=%s\n", bs->bstrerror());
      bmicrosleep(5, 0);
      return false;
   }

   /* Attempt to duplicate hash with our password */
   hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
   bin_to_base64(host, sizeof(host), (char *)hmac, 16, compatible);
   ok = bstrcmp(bs->msg, host);
   if (ok) {
      Dmsg1(dbglvl, "Authenticate OK %s\n", host);
   } else {
      bin_to_base64(host, sizeof(host), (char *)hmac, 16, false);
      ok = bstrcmp(bs->msg, host);
      if (!ok) {
         Dmsg2(dbglvl, "Authenticate NOT OK: wanted %s, got %s\n", host, bs->msg);
      }
   }
   if (ok) {
      bs->fsend("1000 OK auth\n");
   } else {
      bs->fsend(_("1999 Authorization failed.\n"));
      bmicrosleep(5, 0);
   }
   return ok;
}
/*
 * (Un)mount the device (For a FILE device)
 */
static bool do_mount(DCR *dcr, bool mount, int dotimeout)
{
   DEVRES *device = dcr->dev->device;
   POOL_MEM ocmd(PM_FNAME);
   POOLMEM *results;
   DIR* dp;
   char *icmd;
   struct dirent *entry, *result;
   int status, tries, name_max, count;
   berrno be;

   Dsm_check(200);
   if (mount) {
      icmd = device->mount_command;
   } else {
      icmd = device->unmount_command;
   }

   dcr->dev->edit_mount_codes(ocmd, icmd);

   Dmsg2(100, "do_mount: cmd=%s mounted=%d\n", ocmd.c_str(), dcr->dev->is_mounted());

   if (dotimeout) {
      /* Try at most 10 times to (un)mount the device. This should perhaps be configurable. */
      tries = 10;
   } else {
      tries = 1;
   }
   results = get_memory(4000);

   /* If busy retry each second */
   Dmsg1(100, "do_mount run_prog=%s\n", ocmd.c_str());
   while ((status = run_program_full_output(ocmd.c_str(), dcr->dev->max_open_wait / 2, results)) != 0) {
      /* Doesn't work with internationalization (This is not a problem) */
      if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
         break;
      }
      if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
         break;
      }
      if (tries-- > 0) {
         /* Sometimes the device cannot be mounted because it is already mounted.
          * Try to unmount it, then remount it */
         if (mount) {
            Dmsg1(400, "Trying to unmount the device %s...\n", dcr->dev->print_name());
            do_mount(dcr, 0, 0);
         }
         bmicrosleep(1, 0);
         continue;
      }
      Dmsg5(100, "Device %s cannot be %smounted. status=%d result=%s ERR=%s\n", dcr->dev->print_name(),
           (mount ? "" : "un"), status, results, be.bstrerror(status));
      Mmsg(dcr->dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
           dcr->dev->print_name(), (mount ? "" : "un"), be.bstrerror(status));

      /*
       * Now, just to be sure it is not mounted, try to read the filesystem.
       */
      name_max = pathconf(".", _PC_NAME_MAX);
      if (name_max < 1024) {
         name_max = 1024;
      }

      if (!(dp = opendir(device->mount_point))) {
         berrno be;
         dcr->dev->dev_errno = errno;
         Dmsg3(100, "do_mount: failed to open dir %s (dev=%s), ERR=%s\n",
               device->mount_point, dcr->dev->print_name(), be.bstrerror());
         goto get_out;
      }

      entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
      count = 0;
      while (1) {
         if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
            dcr->dev->dev_errno = EIO;
            Dmsg2(129, "do_mount: failed to find suitable file in dir %s (dev=%s)\n",
                  device->mount_point, dcr->dev->print_name());
            break;
         }
         if (!bstrcmp(result->d_name, ".") && !bstrcmp(result->d_name, "..") && !bstrcmp(result->d_name, ".keep")) {
            count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
            break;
         } else {
            Dmsg2(129, "do_mount: ignoring %s in %s\n", result->d_name, device->mount_point);
         }
      }
      free(entry);
      closedir(dp);

      Dmsg1(100, "do_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count);

      if (count > 0) {
         /* If we got more than ., .. and .keep */
         /*   there must be something mounted */
         if (mount) {
            Dmsg1(100, "Did Mount by count=%d\n", count);
            break;
         } else {
            /* An unmount request. We failed to unmount - report an error */
            free_pool_memory(results);
            Dmsg0(200, "== error mount=1 wanted unmount\n");
            return false;
         }
      }
get_out:
      free_pool_memory(results);
      Dmsg0(200, "============ mount=0\n");
      Dsm_check(200);
      return false;
   }

   free_pool_memory(results);
   Dmsg1(200, "============ mount=%d\n", mount);
   return true;
}
Beispiel #24
0
/*
 * First prove our identity to the Remote daemon and then make him prove his identity.
 */
static inline bool two_way_authenticate(BSOCK *bs, JCR *jcr, bool initiate, const char *what)
{
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   bool compatible = true;
   bool auth_success = false;
   alist *verify_list = NULL;
   btimer_t *tid = NULL;

   /*
    * TLS Requirement
    */
   if (have_tls && me->tls_enable) {
      if (me->tls_require) {
         tls_local_need = BNET_TLS_REQUIRED;
      } else {
         tls_local_need = BNET_TLS_OK;
      }
   }

   if (me->tls_authenticate) {
      tls_local_need = BNET_TLS_REQUIRED;
   }

   if (job_canceled(jcr)) {
      auth_success = false;     /* force quick exit */
      goto auth_fatal;
   }

   /*
    * Timeout Hello after 10 min
    */
   tid = start_bsock_timer(bs, AUTH_TIMEOUT);

   /*
    * See if we initiate the challenge or respond to a challenge.
    */
   if (initiate) {
      /*
       * Challenge SD
       */
      auth_success = cram_md5_challenge(bs, jcr->sd_auth_key, tls_local_need, compatible);
      if (auth_success) {
          /*
           * Respond to his challenge
           */
          auth_success = cram_md5_respond(bs, jcr->sd_auth_key, &tls_remote_need, &compatible);
          if (!auth_success) {
             Dmsg1(dbglvl, "Respond cram-get-auth failed with %s\n", bs->who());
          }
      } else {
         Dmsg1(dbglvl, "Challenge cram-auth failed with %s\n", bs->who());
      }
   } else {
      /*
       * Respond to challenge
       */
      auth_success = cram_md5_respond(bs, jcr->sd_auth_key, &tls_remote_need, &compatible);
      if (job_canceled(jcr)) {
         auth_success = false;     /* force quick exit */
         goto auth_fatal;
      }
      if (!auth_success) {
         Dmsg1(dbglvl, "cram_respond failed for %s\n", bs->who());
      } else {
         /*
          * Challenge SD.
          */
         auth_success = cram_md5_challenge(bs, jcr->sd_auth_key, tls_local_need, compatible);
         if (!auth_success) {
            Dmsg1(dbglvl, "cram_challenge failed for %s\n", bs->who());
         }
      }
   }

   if (!auth_success) {
      Jmsg(jcr, M_FATAL, 0, _("Authorization key rejected by %s daemon.\n"
                              "Please see %s for help.\n"), what, MANUAL_AUTH_URL);
      goto auth_fatal;
   }

   /*
    * Verify that the remote host is willing to meet our TLS requirements
    */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
                              " advertize required TLS support.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   /*
    * Verify that we are willing to meet the remote host's requirements
    */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      /*
       * See if we are handshaking a passive client connection.
       */
      if (initiate) {
         verify_list = me->tls_allowed_cns;
      }

      /*
       * Engage TLS! Full Speed Ahead!
       */
      if (!bnet_tls_client(me->tls_ctx, bs, verify_list)) {
         Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
         auth_success = false;
         goto auth_fatal;
      }
      if (me->tls_authenticate) {           /* tls authentication only? */
         bs->free_tls();                    /* yes, shutdown tls */
      }
   }

auth_fatal:
   /*
    * Destroy session key
    */
   memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
   stop_bsock_timer(tid);

   /*
    * Single thread all failures to avoid DOS
    */
   if (!auth_success) {
      P(mutex);
      bmicrosleep(6, 0);
      V(mutex);
   }

   return auth_success;
}
Beispiel #25
0
int main (int argc, char *argv[])
{
   int ch;
   bool disable_batch = false;
   char *restore_list=NULL;
   setlocale(LC_ALL, "");
   bindtextdomain("bareos", LOCALEDIR);
   textdomain("bareos");
   init_stack_dump();
   lmgr_init_thread();

   char **files = (char **) malloc (10 * sizeof(char *));
   int i;
   my_name_is(argc, argv, "bbatch");
   init_msg(NULL, NULL);

   OSDependentInit();

   while ((ch = getopt(argc, argv, "bBh:c:d:D:n:P:Su:vf:w:r:?")) != -1) {
      switch (ch) {
      case 'r':
         restore_list=bstrdup(optarg);
         break;

      case 'B':
         disable_batch = true;
         break;

      case 'b':
         disable_batch = false;
         break;

      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 '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 'f':
         if (nb < 10 ) {
            files[nb++] = optarg;
         }
         break;

      case '?':
      default:
         usage();

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

   if (argc != 0) {
      Pmsg0(0, _("Wrong number of arguments: \n"));
      usage();
   }

   if (restore_list) {
      uint64_t nb_file=0;
      btime_t start, end;
      /* To use the -r option, the catalog should already contains records */

      if ((db = db_init_database(NULL, db_driver, db_name, db_user, db_password,
                                 db_host, 0, NULL, false, disable_batch)) == NULL) {
         Emsg0(M_ERROR_TERM, 0, _("Could not init Bareos database\n"));
      }
      if (!db_open_database(NULL, db)) {
         Emsg0(M_ERROR_TERM, 0, db_strerror(db));
      }

      start = get_current_btime();
      db_get_file_list(NULL, db, restore_list, false, false, list_handler, &nb_file);
      end = get_current_btime();

      Pmsg3(0, _("Computing file list for jobid=%s files=%lld secs=%d\n"),
            restore_list, nb_file, (uint32_t)btime_to_unix(end-start));

      free(restore_list);
      return 0;
   }

   if (disable_batch) {
      printf("Without new Batch mode\n");
   } else {
      printf("With new Batch mode\n");
   }

   i = nb;
   while (--i >= 0) {
      pthread_t thid;
      JCR *bjcr = new_jcr(sizeof(JCR), NULL);
      bjcr->bsr = NULL;
      bjcr->VolSessionId = 1;
      bjcr->VolSessionTime = (uint32_t)time(NULL);
      bjcr->NumReadVolumes = 0;
      bjcr->NumWriteVolumes = 0;
      bjcr->JobId = getpid();
      bjcr->setJobType(JT_CONSOLE);
      bjcr->setJobLevel(L_FULL);
      bjcr->JobStatus = JS_Running;
      bjcr->where = bstrdup(files[i]);
      bjcr->job_name = get_pool_memory(PM_FNAME);
      pm_strcpy(bjcr->job_name, "Dummy.Job.Name");
      bjcr->client_name = get_pool_memory(PM_FNAME);
      pm_strcpy(bjcr->client_name, "Dummy.Client.Name");
      bstrncpy(bjcr->Job, "bbatch", sizeof(bjcr->Job));
      bjcr->fileset_name = get_pool_memory(PM_FNAME);
      pm_strcpy(bjcr->fileset_name, "Dummy.fileset.name");
      bjcr->fileset_md5 = get_pool_memory(PM_FNAME);
      pm_strcpy(bjcr->fileset_md5, "Dummy.fileset.md5");

      if ((db = db_init_database(NULL, db_driver, db_name, db_user, db_password,
                                 db_host, 0, NULL, false, false)) == NULL) {
         Emsg0(M_ERROR_TERM, 0, _("Could not init Bareos database\n"));
      }
      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;

      pthread_create(&thid, NULL, do_batch, bjcr);
   }

   while (nb > 0) {
      bmicrosleep(1,0);
   }

   return 0;
}
Beispiel #26
0
/*
 * Become Threaded Network Server
 *
 * This function is able to handle multiple server ips in
 * ipv4 and ipv6 style. The Addresse are give in a comma
 * seperated string in bind_addr
 *
 * At the moment it is impossible to bind to different ports.
 */
void bnet_thread_server(dlist *addr_list, int max_clients, alist *sockfds,
                        workq_t *client_wq, void *handle_client_request(void *bsock))
{
   int newsockfd, status;
   socklen_t clilen;
   struct sockaddr cli_addr;       /* client's address */
   int tlog, tmax;
   int turnon = 1;
#ifdef HAVE_LIBWRAP
   struct request_info request;
#endif
   IPADDR *ipaddr, *next;
   s_sockfd *fd_ptr = NULL;
   char buf[128];
#ifdef HAVE_POLL
   nfds_t nfds;
   struct pollfd *pfds;
#endif

   char allbuf[256 * 10];

   /*
    * Remove any duplicate addresses.
    */
   for (ipaddr = (IPADDR *)addr_list->first(); ipaddr;
        ipaddr = (IPADDR *)addr_list->next(ipaddr)) {
      for (next = (IPADDR *)addr_list->next(ipaddr); next;
           next = (IPADDR *)addr_list->next(next)) {
         if (ipaddr->get_sockaddr_len() == next->get_sockaddr_len() &&
             memcmp(ipaddr->get_sockaddr(), next->get_sockaddr(),
                    ipaddr->get_sockaddr_len()) == 0) {
            addr_list->remove(next);
         }
      }
   }

   Dmsg1(100, "Addresses %s\n", build_addresses_str(addr_list, allbuf, sizeof(allbuf)));

#ifdef HAVE_POLL
   nfds = 0;
#endif
   foreach_dlist(ipaddr, addr_list) {
      /*
       * Allocate on stack from -- no need to free
       */
      fd_ptr = (s_sockfd *)alloca(sizeof(s_sockfd));
      fd_ptr->port = ipaddr->get_port_net_order();

      /*
       * Open a TCP socket
       */
      for (tlog= 60; (fd_ptr->fd=socket(ipaddr->get_family(), SOCK_STREAM, 0)) < 0; tlog -= 10) {
         if (tlog <= 0) {
            berrno be;
            char curbuf[256];
            Emsg3(M_ABORT, 0, _("Cannot open stream socket. ERR=%s. Current %s All %s\n"),
                       be.bstrerror(),
                       ipaddr->build_address_str(curbuf, sizeof(curbuf)),
                       build_addresses_str(addr_list, allbuf, sizeof(allbuf)));
         }
         bmicrosleep(10, 0);
      }

      /*
       * Reuse old sockets
       */
      if (setsockopt(fd_ptr->fd, SOL_SOCKET, SO_REUSEADDR, (sockopt_val_t)&turnon,
           sizeof(turnon)) < 0) {
         berrno be;
         Emsg1(M_WARNING, 0, _("Cannot set SO_REUSEADDR on socket: %s\n"),
               be.bstrerror());
      }

      tmax = 30 * (60 / 5);        /* wait 30 minutes max */
      for (tlog = 0; bind(fd_ptr->fd, ipaddr->get_sockaddr(), ipaddr->get_sockaddr_len()) < 0; tlog -= 5) {
         berrno be;
         if (tlog <= 0) {
            tlog = 2 * 60;         /* Complain every 2 minutes */
            Emsg2(M_WARNING, 0, _("Cannot bind port %d: ERR=%s: Retrying ...\n"),
                  ntohs(fd_ptr->port), be.bstrerror());
         }
         bmicrosleep(5, 0);
         if (--tmax <= 0) {
            Emsg2(M_ABORT, 0, _("Cannot bind port %d: ERR=%s.\n"), ntohs(fd_ptr->port),
                  be.bstrerror());
         }
      }

      listen(fd_ptr->fd, 50);      /* tell system we are ready */
      sockfds->append(fd_ptr);

#ifdef HAVE_POLL
      nfds++;
#endif
   }
Beispiel #27
0
/*
 * Try to limit the bandwidth of a network connection
 */
void BSOCK::control_bwlimit(int bytes)
{
   btime_t now, temp;
   int64_t usec_sleep;

   /*
    * If nothing written or read nothing todo.
    */
   if (bytes == 0) {
      return;
   }

   /*
    * See if this is the first time we enter here.
    */
   now = get_current_btime();
   if (m_last_tick == 0) {
      m_nb_bytes = bytes;
      m_last_tick = now;
      return;
   }

   /*
    * Calculate the number of microseconds since the last check.
    */
   temp = now - m_last_tick;

   /*
    * Less than 0.1ms since the last call, see the next time
    */
   if (temp < 100) {
      m_nb_bytes += bytes;
      return;
   }

   /*
    * Keep track of how many bytes are written in this timeslice.
    */
   m_nb_bytes += bytes;
   m_last_tick = now;
   if (debug_level >= 400) {
      Dmsg3(400, "control_bwlimit: now = %lld, since = %lld, nb_bytes = %d\n", now, temp, m_nb_bytes);
   }

   /*
    * Take care of clock problems (>10s)
    */
   if (temp > 10000000) {
      return;
   }

   /*
    * Remove what was authorised to be written in temp usecs.
    */
   m_nb_bytes -= (int64_t)(temp * ((double)m_bwlimit / 1000000.0));
   if (m_nb_bytes < 0) {
      /*
       * If more was authorized then used but bursting is not enabled
       * reset the counter as these bytes cannot be used later on when
       * we are exceeding our bandwidth.
       */
      if (!m_use_bursting) {
         m_nb_bytes = 0;
      }
      return;
   }

   /*
    * What exceed should be converted in sleep time
    */
   usec_sleep = (int64_t)(m_nb_bytes /((double)m_bwlimit / 1000000.0));
   if (usec_sleep > 100) {
      if (debug_level >= 400) {
         Dmsg1(400, "control_bwlimit: sleeping for %lld usecs\n", usec_sleep);
      }

      /*
       * Sleep the right number of usecs.
       */
      while (1) {
         bmicrosleep(0, usec_sleep);
         now = get_current_btime();

         /*
          * See if we slept enough or that bmicrosleep() returned early.
          */
         if ((now - m_last_tick) < usec_sleep) {
            usec_sleep -= (now - m_last_tick);
            continue;
         } else {
            m_last_tick = now;
            break;
         }
      }

      /*
       * Subtract the number of bytes we could have sent during the sleep
       * time given the bandwidth limit set. We only do this when we are
       * allowed to burst e.g. use unused bytes from previous timeslices
       * to get an overall bandwidth limiting which may sometimes be below
       * the bandwidth and sometimes above it but the average will be near
       * the set bandwidth.
       */
      if (m_use_bursting) {
         m_nb_bytes -= (int64_t)(usec_sleep * ((double)m_bwlimit / 1000000.0));
      } else {
         m_nb_bytes = 0;
      }
   }
}