/* * Start watchdog thread * * Returns: 0 on success * errno on failure */ int start_watchdog(void) { int stat; watchdog_t *dummy = NULL; int errstat; if (wd_is_init) { return 0; } Dmsg0(800, "Initialising NicB-hacked watchdog thread\n"); watchdog_time = time(NULL); if ((errstat=rwl_init(&lock)) != 0) { berrno be; Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize watchdog lock. ERR=%s\n"), be.bstrerror(errstat)); } wd_queue = New(dlist(dummy, &dummy->link)); wd_inactive = New(dlist(dummy, &dummy->link)); wd_is_init = true; if ((stat = pthread_create(&wd_tid, NULL, watchdog_thread, NULL)) != 0) { return stat; } return 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; }
void init_last_jobs_list() { JCR *jcr = NULL; struct s_last_job *job_entry = NULL; if (!last_jobs) { last_jobs = New(dlist(job_entry, &job_entry->link)); } if (!jcrs) { jcrs = New(dlist(jcr, &jcr->link)); } }
/* * Find the first selectable line greater than or equal to line. That is, * the first line the cursor is allowed to start on. * (If there are none >= line, it will find the highest one.) * * Returns the line number of the found line or NO_LINE if there isn't one. */ long first_selectable_line(long int line) { long lineno; register PerAddrBook *pab; int i; /* skip past non-selectable lines */ for(lineno=line; !line_is_selectable(lineno) && dlist(lineno)->type != End; lineno++) ;/* do nothing */ if(line_is_selectable(lineno)) return(lineno); /* * There were no selectable lines from lineno on down. Trying looking * back up the list. */ for(lineno=line-1; !line_is_selectable(lineno) && dlist(lineno)->type != Beginning; lineno--) ;/* do nothing */ if(line_is_selectable(lineno)) return(lineno); /* * No selectable lines at all. * If some of the addrbooks are still not displayed, it is too * early to set the no_op_possbl flag. Or, if some of the addrbooks * are empty but writable, then we should not set it either. */ for(i = 0; i < as.n_addrbk; i++){ pab = &as.adrbks[i]; if(pab->ostatus != Open && pab->ostatus != HalfOpen && pab->ostatus != ThreeQuartOpen) return NO_LINE; if(pab->access == ReadWrite && adrbk_count(pab->address_book) == 0) return NO_LINE; } as.no_op_possbl++; return NO_LINE; }
/* * i host = 0 mean INADDR_ANY only ipv4 */ dlist *bnet_host2ipaddrs(const char *host, int family, const char **errstr) { struct in_addr inaddr; IPADDR *addr = 0; const char *errmsg; #ifdef HAVE_IPV6 struct in6_addr inaddr6; #endif dlist *addr_list = New(dlist(addr, &addr->link)); if (!host || host[0] == '\0') { if (family != 0) { addr_list->append(add_any(family)); } else { addr_list->append(add_any(AF_INET)); #ifdef HAVE_IPV6 addr_list->append(add_any(AF_INET6)); #endif } } else if (inet_aton(host, &inaddr)) { /* MA Bug 4 */ addr = New(IPADDR(AF_INET)); addr->set_type(IPADDR::R_MULTIPLE); addr->set_addr4(&inaddr); addr_list->append(addr); #ifdef HAVE_IPV6 } else if (inet_pton(AF_INET6, host, &inaddr6) == 1) { addr = New(IPADDR(AF_INET6)); addr->set_type(IPADDR::R_MULTIPLE); addr->set_addr6(&inaddr6); addr_list->append(addr); #endif } else { if (family != 0) { errmsg = resolv_host(family, host, addr_list); if (errmsg) { *errstr = errmsg; free_addresses(addr_list); return 0; } } else { #ifdef HAVE_IPV6 /* We try to resolv host for ipv6 and ipv4, the connection procedure * will try to reach the host for each protocols. We report only "Host * not found" ipv4 message (no need to have ipv6 and ipv4 messages). */ resolv_host(AF_INET6, host, addr_list); #endif errmsg = resolv_host(AF_INET, host, addr_list); if (addr_list->size() == 0) { *errstr = errmsg; free_addresses(addr_list); return 0; } } } return addr_list; }
/** * Initialize the cache for use. * This function should be called with a write lock on the mntent_cache. */ static inline void initialize_mntent_cache(void) { mntent_cache_entry_t *mce = NULL; mntent_cache_entries = New(dlist(mce, &mce->link)); /** * Refresh the cache. */ refresh_mount_cache(add_mntent_mapping); }
/* * Returns 1 if this line is of a type that can have a cursor on it. */ int line_is_selectable(long int lineno) { register AddrScrn_Disp *dl; if((dl = dlist(lineno)) && (dl->type == Text || dl->type == ListEmpty || dl->type == TitleCmb || dl->type == Beginning || dl->type == End)){ return 0; } return 1; }
/********************************************************************* * * 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")); }
/* * We get the slot list from the Storage daemon. * If listall is set we run an 'autochanger listall' cmd * otherwise an 'autochanger list' cmd * If scan is set and listall is not, we return all slots found, * otherwise, we return only slots with valid barcodes (Volume names) * * Input (output of mxt-changer list): * * 0:vol2 Slot num:Volume Name * * Input (output of mxt-changer listall): * * Drive content: D:Drive num:F:Slot loaded:Volume Name * D:0:F:2:vol2 or D:Drive num:E * D:1:F:42:vol42 * D:3:E * * Slot content: * S:1:F:vol1 S:Slot num:F:Volume Name * S:2:E or S:Slot num:E * S:3:F:vol4 * * Import/Export tray slots: * I:10:F:vol10 I:Slot num:F:Volume Name * I:11:E or I:Slot num:E * I:12:F:vol40 * * If a drive is loaded, the slot *should* be empty */ dlist *get_vol_list_from_SD(UAContext *ua, STORERES *store, bool listall, bool scan) { int nr_fields; char *bp; char dev_name[MAX_NAME_LENGTH]; char *field1, *field2, *field3, *field4, *field5; vol_list_t *vl = NULL; dlist *vol_list; BSOCK *sd = NULL; if (!(sd = open_sd_bsock(ua))) { return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask for autochanger list of volumes */ if (listall) { sd->fsend(changerlistallcmd , dev_name); } else { sd->fsend(changerlistcmd, dev_name); } vol_list = New(dlist(vl, &vl->link)); /* * Read and organize list of Volumes */ while (bnet_recv(sd) >= 0) { strip_trailing_junk(sd->msg); /* * Check for returned SD messages */ if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) && B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) && sd->msg[4] == ' ') { ua->send_msg("%s\n", sd->msg); /* pass them on to user */ continue; } /* * Parse the message. list gives max 2 fields listall max 5. * We always make sure all fields are initialized to either * a value or NULL. * * For autochanger list the following mapping is used: * - field1 == slotnr * - field2 == volumename * * For autochanger listall the following mapping is used: * - field1 == type * - field2 == slotnr * - field3 == content (E for Empty, F for Full) * - field4 == loaded (loaded slot if type == D) * - field4 == volumename (if type == S or I) * - field5 == volumename (if type == D) */ field1 = sd->msg; field2 = strchr(sd->msg, ':'); if (field2) { *field2++ = '\0'; if (listall) { field3 = strchr(field2, ':'); if (field3) { *field3++ = '\0'; field4 = strchr(field3, ':'); if (field4) { *field4++ = '\0'; field5 = strchr(field4, ':'); if (field5) { *field5++ = '\0'; nr_fields = 5; } else { nr_fields = 4; } } else { nr_fields = 3; field5 = NULL; } } else { nr_fields = 2; field4 = NULL; field5 = NULL; } } else { nr_fields = 2; field3 = NULL; field4 = NULL; field5 = NULL; } } else { nr_fields = 1; field3 = NULL; field4 = NULL; field5 = NULL; } /* * See if this is a parsable string from either list or listall * e.g. at least f1:f2 */ if (!field1 && !field2) { goto parse_error; } vl = (vol_list_t *)malloc(sizeof(vol_list_t)); memset(vl, 0, sizeof(vol_list_t)); if (scan && !listall) { /* * Scanning -- require only valid slot */ vl->Slot = atoi(field1); if (vl->Slot <= 0) { ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg); free(vl); continue; } vl->Type = slot_type_normal; if (strlen(field2) > 0) { vl->Content = slot_content_full; vl->VolName = bstrdup(field2); } else { vl->Content = slot_content_empty; } vl->Index = INDEX_SLOT_OFFSET + vl->Slot; } else if (!listall) { /* * Not scanning and not listall. */ if (strlen(field2) == 0) { free(vl); continue; } if (!is_an_integer(field1) || (vl->Slot = atoi(field1)) <= 0) { ua->error_msg(_("Invalid Slot number: %s\n"), field1); free(vl); continue; } if (!is_volume_name_legal(ua, field2)) { ua->error_msg(_("Invalid Volume name: %s\n"), field2); free(vl); continue; } vl->Type = slot_type_normal; vl->Content = slot_content_full; vl->VolName = bstrdup(field2); vl->Index = INDEX_SLOT_OFFSET + vl->Slot; } else { /* * Listall. */ if (!field3) { goto parse_error; } switch (*field1) { case 'D': vl->Type = slot_type_drive; break; case 'S': vl->Type = slot_type_normal; break; case 'I': vl->Type = slot_type_import; break; default: vl->Type = slot_type_unknown; break; } /* * For drives the Slot is the actual drive number. * For any other type its the actual slot number. */ switch (vl->Type) { case slot_type_drive: if (!is_an_integer(field2) || (vl->Slot = atoi(field2)) < 0) { ua->error_msg(_("Invalid Drive number: %s\n"), field2); free(vl); continue; } vl->Index = INDEX_DRIVE_OFFSET + vl->Slot; if (vl->Index >= INDEX_MAX_DRIVES) { ua->error_msg(_("Drive number %d greater then INDEX_MAX_DRIVES(%d) please increase define\n"), vl->Slot, INDEX_MAX_DRIVES); free(vl); continue; } break; default: if (!is_an_integer(field2) || (vl->Slot = atoi(field2)) <= 0) { ua->error_msg(_("Invalid Slot number: %s\n"), field2); free(vl); continue; } vl->Index = INDEX_SLOT_OFFSET + vl->Slot; break; } switch (*field3) { case 'E': vl->Content = slot_content_empty; break; case 'F': vl->Content = slot_content_full; switch (vl->Type) { case slot_type_normal: case slot_type_import: if (field4) { vl->VolName = bstrdup(field4); } break; case slot_type_drive: if (field4) { vl->Loaded = atoi(field4); } if (field5) { vl->VolName = bstrdup(field5); } break; default: break; } break; default: vl->Content = slot_content_unknown; break; } } if (vl->VolName) { Dmsg6(100, "Add index = %d slot=%d loaded=%d type=%d content=%d Vol=%s to SD list.\n", vl->Index, vl->Slot, vl->Loaded, vl->Type, vl->Content, NPRT(vl->VolName)); } else { Dmsg5(100, "Add index = %d slot=%d loaded=%d type=%d content=%d Vol=NULL to SD list.\n", vl->Index, vl->Slot, vl->Loaded, vl->Type, vl->Content); } vol_list->binary_insert(vl, compare_vol_list_entry); continue; parse_error: /* * We encountered a parse error, see how many replacements * we done of ':' with '\0' by looking at the nr_fields * variable and undo those. Number of undo's are nr_fields - 1 */ while (nr_fields > 1 && (bp = strchr(sd->msg, '\0')) != NULL) { *bp = ':'; nr_fields--; } ua->error_msg(_("Illegal output from autochanger %s: %s\n"), (listall) ? _("listall") : _("list"), sd->msg); free(vl); continue; } close_sd_bsock(ua); if (vol_list->size() == 0) { delete vol_list; vol_list = NULL; } return vol_list; }
/* * Read the content of the crypto cache from the filesystem. */ void read_crypto_cache(const char *cache_file) { int fd, cnt; ssize_t status; bool ok = false; s_crypto_cache_hdr hdr; int hdr_size = sizeof(hdr); crypto_cache_entry_t *cce = NULL; if ((fd = open(cache_file, O_RDONLY|O_BINARY)) < 0) { berrno be; Dmsg2(010, "Could not open crypto cache file. %s ERR=%s\n", cache_file, be.bstrerror()); goto bail_out; } if ((status = read(fd, &hdr, hdr_size)) != hdr_size) { berrno be; Dmsg4(010, "Could not read crypto cache file. fd=%d status=%d size=%d: ERR=%s\n", fd, (int)status, hdr_size, be.bstrerror()); goto bail_out; } if (hdr.version != crypto_cache_hdr.version) { Dmsg2(010, "Crypto cache bad hdr version. Wanted %d got %d\n", crypto_cache_hdr.version, hdr.version); goto bail_out; } hdr.id[20] = 0; if (!bstrcmp(hdr.id, crypto_cache_hdr.id)) { Dmsg0(000, "Crypto cache file header id invalid.\n"); goto bail_out; } if (!cached_crypto_keys) { cached_crypto_keys = New(dlist(cce, &cce->link)); } /* * Read as many crypto cache entries as available. */ cnt = 0; cce = (crypto_cache_entry_t *)malloc(sizeof(crypto_cache_entry_t)); while (read(fd, cce, sizeof(crypto_cache_entry_t)) == sizeof(crypto_cache_entry_t)) { cnt++; cached_crypto_keys->append(cce); cce = (crypto_cache_entry_t *)malloc(sizeof(crypto_cache_entry_t)); } /* * We always allocate a dangling crypto_cache_entry_t structure in * the way that we malloc before the loop and in the loop. So drop * the last unused entry. */ free(cce); /* * Check if we read the number of entries the header said are in the file. */ if (cnt == hdr.nr_entries) { ok = true; Dmsg2(010, "Crypto cache read %d entries in file %s\n", cnt, cache_file); } else { Dmsg3(000, "Crypto cache read %d entries while %d entries should be in file %s\n", cnt, hdr.nr_entries, cache_file); } bail_out: if (fd >= 0) { close(fd); } if (!ok) { unlink(cache_file); if (cached_crypto_keys) { cached_crypto_keys->destroy(); delete cached_crypto_keys; cached_crypto_keys = NULL; } } }
/* * Update the internal cache with new data. When the cache gets * modified by a new entry or by expiring old data the return * value gives an indication of that. * Returns: true - cache was updated with new data. * false - cache was not updated with new data. */ bool update_crypto_cache(const char *VolumeName, const char *EncryptionKey) { time_t now; bool found; bool retval = false; crypto_cache_entry_t *cce = NULL; crypto_cache_entry_t *next_cce; /* * Lock the cache. */ P(crypto_cache_lock); /* * See if there are any cached encryption keys. */ if (!cached_crypto_keys) { cached_crypto_keys = New(dlist(cce, &cce->link)); cce = (crypto_cache_entry_t *)malloc(sizeof(crypto_cache_entry_t)); bstrncpy(cce->VolumeName, VolumeName, sizeof(cce->VolumeName)); bstrncpy(cce->EncryptionKey, EncryptionKey, sizeof(cce->EncryptionKey)); cce->added = time(NULL); cached_crypto_keys->append(cce); retval = true; } else { found = false; now = time(NULL); cce = (crypto_cache_entry_t *)cached_crypto_keys->first(); while (cce) { next_cce = (crypto_cache_entry_t *)cached_crypto_keys->next(cce); if (bstrcmp(cce->VolumeName, VolumeName)) { found = true; /* * If the key changed update the cached entry. */ if (!bstrcmp(cce->EncryptionKey, EncryptionKey)) { bstrncpy(cce->EncryptionKey, EncryptionKey, sizeof(cce->EncryptionKey)); retval = true; } cce->added = time(NULL); cce = next_cce; continue; } /* * Validate the entry. * Any entry older the CRYPTO_CACHE_MAX_AGE seconds is removed. */ if ((cce->added + CRYPTO_CACHE_MAX_AGE) < now) { cached_crypto_keys->remove(cce); retval = true; } cce = next_cce; } /* * New entry. */ if (!found) { cce = (crypto_cache_entry_t *)malloc(sizeof(crypto_cache_entry_t)); bstrncpy(cce->VolumeName, VolumeName, sizeof(cce->VolumeName)); bstrncpy(cce->EncryptionKey, EncryptionKey, sizeof(cce->EncryptionKey)); cce->added = time(NULL); cached_crypto_keys->append(cce); retval = true; } } V(crypto_cache_lock); return retval; }
printf("Re-insert 10th item\n"); jcr_chain->insert_before(jcr1, next_jcr); printf("Print remaining list.\n"); foreach_dlist(jcr, jcr_chain) { printf("Dlist item = %s\n", jcr->buf); free(jcr->buf); } jcr_chain->destroy(); free(jcr_chain); /* The following may seem a bit odd, but we create a chaing * of jcr objects. Within a jcr object, there is a buf * that points to a malloced string containing data */ jcr_chain = New(dlist(jcr, &jcr->link)); printf("append 20 items 0-19\n"); for (int i=0; i<20; i++) { sprintf(buf, "This is dlist item %d", i); jcr = (MYJCR *)malloc(sizeof(MYJCR)); jcr->buf = bstrdup(buf); jcr_chain->append(jcr); if (i == 10) { save_jcr = jcr; } } next_jcr = (MYJCR *)jcr_chain->next(save_jcr); printf("11th item=%s\n", next_jcr->buf); jcr = (MYJCR *)malloc(sizeof(MYJCR)); jcr->buf = save_jcr->buf;
DEVICE *m_init_dev(JCR *jcr, DEVRES *device) { struct stat statp; int errstat; DCR *dcr = NULL; DEVICE *dev = NULL; uint32_t max_bs; /* If no device type specified, try to guess */ if (!device->dev_type) { /* Check that device is available */ if (stat(device->device_name, &statp) < 0) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"), device->device_name, be.bstrerror()); return NULL; } if (S_ISDIR(statp.st_mode)) { device->dev_type = B_FILE_DEV; } else if (S_ISCHR(statp.st_mode)) { device->dev_type = B_TAPE_DEV; } else if (S_ISFIFO(statp.st_mode)) { device->dev_type = B_FIFO_DEV; #ifdef USE_VTAPE /* must set DeviceType = Vtape * in normal mode, autodetection is disabled */ } else if (S_ISREG(statp.st_mode)) { device->dev_type = B_VTAPE_DEV; #endif } else if (!(device->cap_bits & CAP_REQMOUNT)) { Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n" " or have RequiresMount=yes for DVD. st_mode=%x\n"), device->device_name, statp.st_mode); return NULL; } else { device->dev_type = B_DVD_DEV; } if (strcmp(device->device_name, "/dev/null") == 0) { device->dev_type = B_NULL_DEV; } } switch (device->dev_type) { case B_DVD_DEV: Jmsg0(jcr, M_FATAL, 0, _("DVD support is now deprecated.\n")); return NULL; case B_VTAPE_DEV: dev = New(vtape); break; #ifdef USE_FTP case B_FTP_DEV: dev = New(ftp_device); break; #endif case B_TAPE_DEV: dev = New(tape_dev); break; case B_FILE_DEV: case B_FIFO_DEV: case B_NULL_DEV: dev = New(file_dev); break; default: return NULL; } dev->clear_slot(); /* unknown */ /* Copy user supplied device parameters from Resource */ dev->dev_name = get_memory(strlen(device->device_name)+1); pm_strcpy(dev->dev_name, device->device_name); dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->hdr.name) + 20); /* We edit "Resource-name" (physical-name) */ Mmsg(dev->prt_name, "\"%s\" (%s)", device->hdr.name, device->device_name); Dmsg1(400, "Allocate dev=%s\n", dev->print_name()); dev->capabilities = device->cap_bits; dev->min_free_space = device->min_free_space; dev->min_block_size = device->min_block_size; dev->max_block_size = device->max_block_size; dev->max_volume_size = device->max_volume_size; dev->max_file_size = device->max_file_size; dev->max_concurrent_jobs = device->max_concurrent_jobs; dev->volume_capacity = device->volume_capacity; dev->max_rewind_wait = device->max_rewind_wait; dev->max_open_wait = device->max_open_wait; dev->vol_poll_interval = device->vol_poll_interval; dev->max_spool_size = device->max_spool_size; dev->drive_index = device->drive_index; dev->enabled = device->enabled; dev->autoselect = device->autoselect; dev->read_only = device->read_only; dev->dev_type = device->dev_type; dev->device = device; if (dev->is_tape()) { /* No parts on tapes */ dev->max_part_size = 0; } else { dev->max_part_size = device->max_part_size; } /* Sanity check */ if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { dev->vol_poll_interval = 60; } if (!device->dev) { /* The first time we create a DEVICE from the DEVRES, we keep a pointer * to the DEVICE accessible from the DEVRES. */ device->dev = dev; } if (dev->is_fifo()) { dev->capabilities |= CAP_STREAM; /* set stream device */ } /* If the device requires mount : * - Check that the mount point is available * - Check that (un)mount commands are defined */ if (dev->is_file() && dev->requires_mount()) { if (!device->mount_point || stat(device->mount_point, &statp) < 0) { berrno be; dev->dev_errno = errno; Jmsg2(jcr, M_ERROR_TERM, 0, _("Unable to stat mount point %s: ERR=%s\n"), device->mount_point, be.bstrerror()); } if (!device->mount_command || !device->unmount_command) { Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n")); } } /* Keep the device ID in the DEVICE struct to identify the hardware */ if (dev->is_file() && stat(dev->archive_name(), &statp) == 0) { dev->devno = statp.st_dev; } /* Sanity check */ if (dev->max_block_size == 0) { max_bs = DEFAULT_BLOCK_SIZE; } else { max_bs = dev->max_block_size; } if (dev->min_block_size > max_bs) { Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"), dev->print_name()); } if (dev->max_block_size > 4096000) { Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"), dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE); dev->max_block_size = 0; } if (dev->max_block_size % TAPE_BSIZE != 0) { Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"), dev->max_block_size, dev->print_name(), TAPE_BSIZE); } if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) { Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), dev->print_name()); } dev->errmsg = get_pool_memory(PM_EMSG); *dev->errmsg = 0; if ((errstat = dev->init_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = dev->init_acquire_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = dev->init_read_acquire_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init read acquire mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = dev->init_volcat_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init volcat mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = dev->init_dcrs_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init dcrs mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } dev->set_mutex_priorities(); #ifdef xxx if ((errstat = rwl_init(&dev->lock)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } #endif dev->clear_opened(); dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link)); Dmsg2(100, "init_dev: tape=%d dev_name=%s\n", dev->is_tape(), dev->dev_name); dev->initiated = true; return dev; }
static inline DEVICE *m_init_dev(JCR *jcr, DEVRES *device, bool new_init) { struct stat statp; int errstat; DCR *dcr = NULL; DEVICE *dev = NULL; uint32_t max_bs; Dmsg1(400, "max_block_size in device res is %u\n", device->max_block_size); /* * If no device type specified, try to guess */ if (!device->dev_type) { /* * Check that device is available */ if (stat(device->device_name, &statp) < 0) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"), device->device_name, be.bstrerror()); return NULL; } if (S_ISDIR(statp.st_mode)) { device->dev_type = B_FILE_DEV; } else if (S_ISCHR(statp.st_mode)) { device->dev_type = B_TAPE_DEV; } else if (S_ISFIFO(statp.st_mode)) { device->dev_type = B_FIFO_DEV; } else if (!bit_is_set(CAP_REQMOUNT, device->cap_bits)) { Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory, st_mode=%x\n"), device->device_name, statp.st_mode); return NULL; } } /* * See what type of device is wanted. */ switch (device->dev_type) { /* * When using dynamic loading use the init_backend_dev() function * for any type of device not being of the type file. */ #ifndef HAVE_DYNAMIC_SD_BACKENDS #ifdef HAVE_GFAPI case B_GFAPI_DEV: dev = New(gfapi_device); break; #endif #ifdef HAVE_OBJECTSTORE case B_OBJECT_STORE_DEV: dev = New(object_store_device); break; #endif #ifdef HAVE_RADOS case B_RADOS_DEV: dev = New(rados_device); break; #endif #ifdef HAVE_CEPHFS case B_CEPHFS_DEV: dev = New(cephfs_device); break; #endif #ifdef HAVE_ELASTO case B_ELASTO_DEV: dev = New(elasto_device); break; #endif #ifdef HAVE_WIN32 case B_TAPE_DEV: dev = New(win32_tape_device); break; case B_FIFO_DEV: dev = New(win32_fifo_device); break; #else case B_TAPE_DEV: dev = New(unix_tape_device); break; case B_FIFO_DEV: dev = New(unix_fifo_device); break; #endif #endif /* HAVE_DYNAMIC_SD_BACKENDS */ #ifdef HAVE_WIN32 case B_FILE_DEV: dev = New(win32_file_device); break; #else case B_FILE_DEV: dev = New(unix_file_device); break; #endif default: #ifdef HAVE_DYNAMIC_SD_BACKENDS dev = init_backend_dev(jcr, device->dev_type); #endif break; } if (!dev) { Jmsg2(jcr, M_ERROR, 0, _("%s has an unknown device type %d\n"), device->device_name, device->dev_type); return NULL; } dev->clear_slot(); /* unknown */ /* * Copy user supplied device parameters from Resource */ dev->dev_name = get_memory(strlen(device->device_name) + 1); pm_strcpy(dev->dev_name, device->device_name); if (device->device_options) { dev->dev_options = get_memory(strlen(device->device_options) + 1); pm_strcpy(dev->dev_options, device->device_options); } dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->name()) + 20); /* * We edit "Resource-name" (physical-name) */ Mmsg(dev->prt_name, "\"%s\" (%s)", device->name(), device->device_name); Dmsg1(400, "Allocate dev=%s\n", dev->print_name()); copy_bits(CAP_MAX, device->cap_bits, dev->capabilities); /* * current block sizes */ dev->min_block_size = device->min_block_size; dev->max_block_size = device->max_block_size; dev->max_volume_size = device->max_volume_size; dev->max_file_size = device->max_file_size; dev->max_concurrent_jobs = device->max_concurrent_jobs; dev->volume_capacity = device->volume_capacity; dev->max_rewind_wait = device->max_rewind_wait; dev->max_open_wait = device->max_open_wait; dev->max_open_vols = device->max_open_vols; dev->vol_poll_interval = device->vol_poll_interval; dev->max_spool_size = device->max_spool_size; dev->drive = device->drive; dev->drive_index = device->drive_index; dev->autoselect = device->autoselect; dev->norewindonclose = device->norewindonclose; dev->dev_type = device->dev_type; dev->device = device; /* * Sanity check */ if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { dev->vol_poll_interval = 60; } device->dev = dev; if (dev->is_fifo()) { dev->set_cap(CAP_STREAM); /* set stream device */ } /* * If the device requires mount : * - Check that the mount point is available * - Check that (un)mount commands are defined */ if (dev->is_file() && dev->requires_mount()) { if (!device->mount_point || stat(device->mount_point, &statp) < 0) { berrno be; dev->dev_errno = errno; Jmsg2(jcr, M_ERROR_TERM, 0, _("Unable to stat mount point %s: ERR=%s\n"), device->mount_point, be.bstrerror()); } if (!device->mount_command || !device->unmount_command) { Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n")); } } /* * Sanity check */ if (dev->max_block_size == 0) { max_bs = DEFAULT_BLOCK_SIZE; } else { max_bs = dev->max_block_size; } if (dev->min_block_size > max_bs) { Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"), dev->print_name()); } if (dev->max_block_size > MAX_BLOCK_LENGTH) { Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"), dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE); dev->max_block_size = 0; } if (dev->max_block_size % TAPE_BSIZE != 0) { Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"), dev->max_block_size, dev->print_name(), TAPE_BSIZE); } if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) { Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), dev->print_name()); } dev->errmsg = get_pool_memory(PM_EMSG); *dev->errmsg = 0; if ((errstat = dev->init_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = dev->init_acquire_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } if ((errstat = dev->init_read_acquire_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init read acquire mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } dev->set_mutex_priorities(); #ifdef xxx if ((errstat = rwl_init(&dev->lock)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } #endif dev->clear_opened(); dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link)); Dmsg2(100, "init_dev: tape=%d dev_name=%s\n", dev->is_tape(), dev->dev_name); dev->initiated = true; Dmsg3(100, "dev=%s dev_max_bs=%u max_bs=%u\n", dev->dev_name, dev->device->max_block_size, dev->max_block_size); return dev; }
static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1, const char *query2, const char *type) { dlist *item_chain; uitem *item = NULL; uitem *last_item = NULL; regex_t preg; char prbuf[500]; int rc; bool ok = false; POOL_MEM query(PM_MESSAGE); item_chain = New(dlist(item, &item->link)); if (!jcr->job->selection_pattern) { Jmsg(jcr, M_FATAL, 0, _("No %s %s selection pattern specified.\n"), jcr->get_OperationName(), type); goto bail_out; } Dmsg1(dbglevel, "regex-sel-pattern=%s\n", jcr->job->selection_pattern); /* Basic query for names */ Mmsg(query, query1, jcr->rpool->name()); Dmsg1(dbglevel, "get name query1=%s\n", query.c_str()); if (!db_sql_query(jcr->db, query.c_str(), unique_name_handler, (void *)item_chain)) { Jmsg(jcr, M_FATAL, 0, _("SQL to get %s failed. ERR=%s\n"), type, db_strerror(jcr->db)); goto bail_out; } Dmsg1(dbglevel, "query1 returned %d names\n", item_chain->size()); if (item_chain->size() == 0) { Jmsg(jcr, M_INFO, 0, _("Query of Pool \"%s\" returned no Jobs to %s.\n"), jcr->rpool->name(), jcr->get_ActionName(0)); ok = true; goto bail_out; /* skip regex match */ } else { /* Compile regex expression */ rc = regcomp(&preg, jcr->job->selection_pattern, REG_EXTENDED); if (rc != 0) { regerror(rc, &preg, prbuf, sizeof(prbuf)); Jmsg(jcr, M_FATAL, 0, _("Could not compile regex pattern \"%s\" ERR=%s\n"), jcr->job->selection_pattern, prbuf); goto bail_out; } /* Now apply the regex to the names and remove any item not matched */ foreach_dlist(item, item_chain) { const int nmatch = 30; regmatch_t pmatch[nmatch]; if (last_item) { Dmsg1(dbglevel, "Remove item %s\n", last_item->item); free(last_item->item); item_chain->remove(last_item); } Dmsg1(dbglevel, "get name Item=%s\n", item->item); rc = regexec(&preg, item->item, nmatch, pmatch, 0); if (rc == 0) { last_item = NULL; /* keep this one */ } else { last_item = item; } } if (last_item) { free(last_item->item); Dmsg1(dbglevel, "Remove item %s\n", last_item->item); item_chain->remove(last_item); } regfree(&preg); } if (item_chain->size() == 0) { Jmsg(jcr, M_INFO, 0, _("Regex pattern matched no Jobs to %s.\n"), jcr->get_ActionName(0)); ok = true; goto bail_out; /* skip regex match */ } /* * At this point, we have a list of items in item_chain * that have been matched by the regex, so now we need * to look up their jobids. */ ids->count = 0; foreach_dlist(item, item_chain) { Dmsg2(dbglevel, "Got %s: %s\n", type, item->item); Mmsg(query, query2, item->item, jcr->rpool->name()); Dmsg1(dbglevel, "get id from name query2=%s\n", query.c_str()); if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; } }
/* * Initialize the sql connection pool. */ bool db_sql_pool_initialize(const char *db_drivername, const char *db_name, const char *db_user, const char *db_password, const char *db_address, int db_port, const char *db_socket, bool disable_batch_insert, int min_connections, int max_connections, int increment_connections, int idle_timeout, int validate_timeout) { int cnt; B_DB *mdb; time_t now; SQL_POOL_DESCRIPTOR *spd = NULL; SQL_POOL_ENTRY *spe = NULL; bool retval = false; /* * See if pooling is runtime disabled. */ if (max_connections == 0) { Dmsg0(100, "db_sql_pool_initialize pooling disabled as max_connections == 0\n"); return true; } /* * First make sure the values make any sense. */ if (min_connections <= 0 || max_connections <= 0 || increment_connections <= 0 || min_connections > max_connections) { Jmsg(NULL, M_FATAL, 0, _("Illegal values for sql pool initialization, min_connections = %d, max_connections = %d, increment_connections = %d"), min_connections, max_connections, increment_connections); return false; } P(mutex); time(&now); if (db_pooling_descriptors == NULL) { db_pooling_descriptors = New(dlist(spd, &spd->link)); } /* * Create a new pool descriptor. */ spd = (SQL_POOL_DESCRIPTOR *)malloc(sizeof(SQL_POOL_DESCRIPTOR)); memset(spd, 0, sizeof(SQL_POOL_DESCRIPTOR)); spd->pool_entries = New(dlist(spe, &spe->link)); spd->min_connections = min_connections; spd->max_connections = max_connections; spd->increment_connections = increment_connections; spd->idle_timeout = idle_timeout; spd->validate_timeout = validate_timeout; spd->last_update = now; spd->active = true; /* * Create a number of database connections. */ for (cnt = 0; cnt < min_connections; cnt++) { mdb = db_init_database(NULL, db_drivername, db_name, db_user, db_password, db_address, db_port, db_socket, true, disable_batch_insert); if (mdb == NULL) { Jmsg(NULL, M_FATAL, 0, "%s", _("Could not init database connection")); goto bail_out; } if (!db_open_database(NULL, mdb)) { Mmsg2(mdb->errmsg, _("Could not open database \"%s\": ERR=%s\n"), db_name, db_strerror(mdb)); Jmsg(NULL, M_FATAL, 0, "%s", mdb->errmsg); db_close_database(NULL, mdb); goto bail_out; } /* * Push this new connection onto the connection pool. */ spe = (SQL_POOL_ENTRY *)malloc(sizeof(SQL_POOL_ENTRY)); memset(spe, 0, sizeof(SQL_POOL_ENTRY)); spe->id = spd->nr_connections++; spe->last_update = now; spe->db_handle = mdb; spd->pool_entries->append(spe); spe = NULL; } #if defined(HAVE_DYNAMIC_CATS_BACKENDS) Dmsg3(100, "db_sql_pool_initialize created %d connections to database %s, backend type %s\n", cnt, db_name, db_drivername); #else Dmsg2(100, "db_sql_pool_initialize created %d connections to database %s\n", cnt, db_name); #endif db_pooling_descriptors->append(spd); retval = true; goto ok_out; bail_out: if (spe) { free(spe); } if (spd) { destroy_pool_descriptor(spd, false); } ok_out: V(mutex); return retval; }