/* * Edit a utime "duration" into ASCII */ char *edit_utime(utime_t val, char *buf, int buf_len) { char mybuf[200]; static const int32_t mult[] = {60*60*24*365, 60*60*24*30, 60*60*24, 60*60, 60}; static const char *mod[] = {"year", "month", "day", "hour", "min"}; int i; uint32_t times; *buf = 0; for (i=0; i<5; i++) { times = (uint32_t)(val / mult[i]); if (times > 0) { val = val - (utime_t)times * mult[i]; bsnprintf(mybuf, sizeof(mybuf), "%d %s%s ", times, mod[i], times>1?"s":""); bstrncat(buf, mybuf, buf_len); } } if (val == 0 && strlen(buf) == 0) { bstrncat(buf, "0 secs", buf_len); } else if (val != 0) { bsnprintf(mybuf, sizeof(mybuf), "%d sec%s", (uint32_t)val, val>1?"s":""); bstrncat(buf, mybuf, buf_len); } return buf; }
/* SM_DUMP -- Print orphaned buffers (and dump them if BUFDUMP is * True). */ void sm_dump(bool bufdump, bool in_use) { struct abufhead *ap; P(mutex); ap = (struct abufhead *)abqueue.qnext; while (ap != (struct abufhead *) &abqueue) { if ((ap == NULL) || (ap->abq.qnext->qprev != (struct b_queue *) ap) || (ap->abq.qprev->qnext != (struct b_queue *) ap)) { Pmsg1(0, _( "\nOrphaned buffers exist. Dump terminated following\n" " discovery of bad links in chain of orphaned buffers.\n" " Buffer address with bad links: %p\n"), ap); break; } if (ap->abfname != NULL) { char errmsg[500]; uint32_t memsize = ap->ablen - (HEAD_SIZE + 1); char *cp = ((char *)ap) + HEAD_SIZE; Pmsg6(0, "%s buffer: %s %d bytes at %p from %s:%d\n", in_use?"In use":"Orphaned", my_name, memsize, cp, get_basename(ap->abfname), ap->ablineno); if (bufdump) { char buf[20]; unsigned llen = 0; errmsg[0] = EOS; while (memsize) { if (llen >= 16) { bstrncat(errmsg, "\n", sizeof(errmsg)); llen = 0; Pmsg1(0, "%s", errmsg); errmsg[0] = EOS; } bsnprintf(buf, sizeof(buf), " %02X", (*cp++) & 0xFF); bstrncat(errmsg, buf, sizeof(errmsg)); llen++; memsize--; } Pmsg1(0, "%s\n", errmsg); } } ap = (struct abufhead *) ap->abq.qnext; } V(mutex); }
/* * New style options come here */ static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass) { int i; int keyword; char inc_opts[100]; inc_opts[0] = 0; keyword = INC_KW_NONE; /* Look up the keyword */ for (i=0; FS_option_kw[i].name; i++) { if (bstrcasecmp(item->name, FS_option_kw[i].name)) { keyword = FS_option_kw[i].token; break; } } if (keyword == INC_KW_NONE) { scan_err1(lc, _("Expected a FileSet keyword, got: %s"), lc->str); } /* Now scan for the value */ scan_include_options(lc, keyword, inc_opts, sizeof(inc_opts)); if (pass == 1) { bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS); Dmsg2(900, "new pass=%d incexe opts=%s\n", pass, res_incexe.current_opts->opts); } scan_to_eol(lc); }
const char *get_default_configdir() { #if defined(HAVE_WIN32) HRESULT hr; static char szConfigDir[MAX_PATH + 1] = { 0 }; if (!p_SHGetFolderPath) { bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir)); return szConfigDir; } if (szConfigDir[0] == '\0') { hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir); if (SUCCEEDED(hr)) { bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir)); } else { bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir)); } } return szConfigDir; #else return SYSCONFDIR; #endif }
bool VSSClient::GetShadowPath(const char *szFilePath, char *szShadowPath, int nBuflen) { if (!m_bBackupIsInitialized) return false; /* check for valid pathname */ bool bIsValidName; bIsValidName = strlen(szFilePath) > 3; if (bIsValidName) bIsValidName &= isalpha (szFilePath[0]) && szFilePath[1]==':' && szFilePath[2] == '\\'; if (bIsValidName) { int nDriveIndex = toupper(szFilePath[0])-'A'; if (m_szShadowCopyName[nDriveIndex][0] != 0) { if (WideCharToMultiByte(CP_UTF8,0,m_szShadowCopyName[nDriveIndex],-1,szShadowPath,nBuflen-1,NULL,NULL)) { nBuflen -= (int)strlen(szShadowPath); bstrncat(szShadowPath, szFilePath+2, nBuflen); return true; } } } bstrncpy(szShadowPath, szFilePath, nBuflen); errno = EINVAL; return false; }
BOOL VSSClient::GetShadowPath(const char *szFilePath, char *szShadowPath, int nBuflen) { if(!m_bBackupIsInitialized) return FALSE; // check for valid pathname. BOOL bIsValidName; bIsValidName=strlen(szFilePath)>3; if(bIsValidName) bIsValidName &= isalpha(szFilePath[0]) && szFilePath[1]==':' && szFilePath[2]=='\\'; if(bIsValidName) { int nDriveIndex=toupper(szFilePath[0])-'A'; if(m_szShadowCopyName[nDriveIndex][0]) { if(WideCharToMultiByte(CP_UTF8, 0, m_szShadowCopyName[nDriveIndex], -1, szShadowPath, nBuflen-1, NULL, NULL)) { nBuflen-=(int)strlen(szShadowPath); bstrncat(szShadowPath, szFilePath+2, nBuflen); return TRUE; } } } snprintf(szShadowPath, nBuflen, "%s", szFilePath); errno=EINVAL; return FALSE; }
static bool create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) { char num[20]; db_int64_ctx ctx; POOL_MEM query(PM_MESSAGE), name(PM_NAME); char ed1[50]; /* See if volume already exists */ mr->VolumeName[0] = 0; pm_strcpy(name, pr->LabelFormat); ctx.value = 0; Mmsg(query, "SELECT MAX(MediaId) FROM Media,Pool WHERE Pool.PoolId=%s", edit_int64(pr->PoolId, ed1)); if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) { Jmsg(jcr, M_WARNING, 0, _("SQL failed, but ignored. ERR=%s\n"), db_strerror(jcr->db)); ctx.value = pr->NumVols+1; } for (int i=(int)ctx.value+1; i<(int)ctx.value+100; i++) { MEDIA_DBR tmr; memset(&tmr, 0, sizeof(tmr)); sprintf(num, "%04d", i); bstrncpy(tmr.VolumeName, name.c_str(), sizeof(tmr.VolumeName)); bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName)); if (db_get_media_record(jcr, jcr->db, &tmr)) { Jmsg(jcr, M_WARNING, 0, _("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"), tmr.VolumeName); continue; } bstrncpy(mr->VolumeName, name.c_str(), sizeof(mr->VolumeName)); bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName)); break; /* Got good name */ } if (mr->VolumeName[0] == 0) { Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n")); return false; } return true; }
/* * Store a time period in seconds */ static void store_time(LEX *lc, RES_ITEM *item, int index, int pass) { int token; utime_t utime; char period[500]; URES *res_all = (URES *)my_config->m_res_all; token = lex_get_token(lc, T_SKIP_EOL); errno = 0; switch (token) { case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: bstrncpy(period, lc->str, sizeof(period)); /* get first part */ /* * If terminated by space, scan and get modifier */ while (lc->ch == ' ') { token = lex_get_token(lc, T_ALL); switch (token) { case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: bstrncat(period, lc->str, sizeof(period)); break; } } if (!duration_to_utime(period, &utime)) { scan_err1(lc, _("expected a time period, got: %s"), period); return; } *(item->utimevalue) = utime; break; default: scan_err1(lc, _("expected a time period, got: %s"), lc->str); return; } if (token != T_EOL) { scan_to_eol(lc); } set_bit(index, res_all->hdr.item_present); }
/* Store a size in bytes */ void store_size(LEX *lc, RES_ITEM *item, int index, int pass) { int token; uint64_t uvalue; char bsize[500]; Dmsg0(900, "Enter store_size\n"); token = lex_get_token(lc, T_SKIP_EOL); errno = 0; switch (token) { case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */ /* if terminated by space, scan and get modifier */ while (lc->ch == ' ') { token = lex_get_token(lc, T_ALL); switch (token) { case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: bstrncat(bsize, lc->str, sizeof(bsize)); break; } } if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) { scan_err1(lc, _("expected a size number, got: %s"), lc->str); return; } *(uint64_t *)(item->value) = uvalue; break; default: scan_err1(lc, _("expected a size, got: %s"), lc->str); return; } if (token != T_EOL) { scan_to_eol(lc); } set_bit(index, res_all.hdr.item_present); Dmsg0(900, "Leave store_size\n"); }
/* * Scan for right hand side of Include options (keyword=option) is * converted into one or two characters. Verifyopts=xxxx is Vxxxx: * Whatever is found is concatenated to the opts string. * This code is also used inside an Options resource. */ static void scan_include_options(LEX *lc, int keyword, char *opts, int optlen) { int i; char option[3]; int lcopts = lc->options; struct s_sz_matching size_matching; option[0] = 0; /* default option = none */ option[2] = 0; /* terminate options */ lc->options |= LOPT_STRING; /* force string */ lex_get_token(lc, T_STRING); /* expect at least one option */ if (keyword == INC_KW_VERIFY) { /* special case */ /* ***FIXME**** ensure these are in permitted set */ bstrncat(opts, "V", optlen); /* indicate Verify */ bstrncat(opts, lc->str, optlen); bstrncat(opts, ":", optlen); /* terminate it */ Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen); } else if (keyword == INC_KW_ACCURATE) { /* special case */ /* ***FIXME**** ensure these are in permitted set */ bstrncat(opts, "C", optlen); /* indicate Accurate */ bstrncat(opts, lc->str, optlen); bstrncat(opts, ":", optlen); /* terminate it */ Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen); } else if (keyword == INC_KW_BASEJOB) { /* special case */ /* ***FIXME**** ensure these are in permitted set */ bstrncat(opts, "J", optlen); /* indicate BaseJob */ bstrncat(opts, lc->str, optlen); bstrncat(opts, ":", optlen); /* terminate it */ Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen); } else if (keyword == INC_KW_STRIPPATH) { /* special case */ if (!is_an_integer(lc->str)) { scan_err1(lc, _("Expected a strip path positive integer, got:%s:"), lc->str); } bstrncat(opts, "P", optlen); /* indicate strip path */ bstrncat(opts, lc->str, optlen); bstrncat(opts, ":", optlen); /* terminate it */ Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen); } else if (keyword == INC_KW_SIZE) { /* special case */ if (!parse_size_match(lc->str, &size_matching)) { scan_err1(lc, _("Expected a parseable size, got:%s:"), lc->str); } bstrncat(opts, "z", optlen); /* indicate size */ bstrncat(opts, lc->str, optlen); bstrncat(opts, ":", optlen); /* terminate it */ Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen); } else { /* * Standard keyword options for Include/Exclude */ for (i=0; FS_options[i].name; i++) { if (FS_options[i].keyword == keyword && bstrcasecmp(lc->str, FS_options[i].name)) { /* NOTE! maximum 2 letters here or increase option[3] */ option[0] = FS_options[i].option[0]; option[1] = FS_options[i].option[1]; i = 0; break; } } if (i != 0) { scan_err1(lc, _("Expected a FileSet option keyword, got:%s:"), lc->str); } else { /* add option */ bstrncat(opts, option, optlen); Dmsg3(900, "Catopts=%s option=%s optlen=%d\n", opts, option,optlen); } } lc->options = lcopts; /* If option terminated by comma, eat it */ if (lc->ch == ',') { lex_get_token(lc, T_ALL); /* yes, eat comma */ } }
/* * 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"); }
/* Small handler to print the last line of a list xxx command */ static void last_line_handler(void *vctx, const char *str) { LIST_CTX *ctx = (LIST_CTX *)vctx; bstrncat(ctx->line, str, sizeof(ctx->line)); }
void make_session_key(char *key, char *seed, int mode) { int j, k; struct MD5Context md5c; unsigned char md5key[16], md5key1[16]; char s[1024]; #define ss sizeof(s) s[0] = 0; if (seed != NULL) { bstrncat(s, seed, sizeof(s)); } /* The following creates a seed for the session key generator based on a collection of volatile and environment-specific information unlikely to be vulnerable (as a whole) to an exhaustive search attack. If one of these items isn't available on your machine, replace it with something equivalent or, if you like, just delete it. */ #if defined(HAVE_WIN32) { LARGE_INTEGER li; DWORD length; FILETIME ft; bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)GetCurrentProcessId()); (void)getcwd(s + strlen(s), 256); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)GetTickCount()); QueryPerformanceCounter(&li); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)li.LowPart); GetSystemTimeAsFileTime(&ft); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)ft.dwLowDateTime); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)ft.dwHighDateTime); length = 256; GetComputerName(s + strlen(s), &length); length = 256; GetUserName(s + strlen(s), &length); } #else bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getpid()); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getppid()); (void)getcwd(s + strlen(s), 256); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)clock()); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)time(NULL)); #if defined(Solaris) sysinfo(SI_HW_SERIAL,s + strlen(s), 12); #endif #if defined(HAVE_GETHOSTID) bsnprintf(s + strlen(s), ss, "%lu", (uint32_t) gethostid()); #endif gethostname(s + strlen(s), 256); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getuid()); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)getgid()); #endif MD5Init(&md5c); MD5Update(&md5c, (uint8_t *)s, strlen(s)); MD5Final(md5key, &md5c); bsnprintf(s + strlen(s), ss, "%lu", (uint32_t)((time(NULL) + 65121) ^ 0x375F)); MD5Init(&md5c); MD5Update(&md5c, (uint8_t *)s, strlen(s)); MD5Final(md5key1, &md5c); #define nextrand (md5key[j] ^ md5key1[j]) if (mode) { for (j = k = 0; j < 16; j++) { unsigned char rb = nextrand; #define Rad16(x) ((x) + 'A') key[k++] = Rad16((rb >> 4) & 0xF); key[k++] = Rad16(rb & 0xF); #undef Rad16 if (j & 1) { key[k++] = '-'; } } key[--k] = 0; } else { for (j = 0; j < 16; j++) {
/* * Store a size in bytes */ static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass, bool size32, enum store_unit_type type) { int token; uint64_t uvalue; char bsize[500]; Dmsg0(900, "Enter store_unit\n"); token = lex_get_token(lc, T_SKIP_EOL); errno = 0; switch (token) { case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */ /* * If terminated by space, scan and get modifier */ while (lc->ch == ' ') { token = lex_get_token(lc, T_ALL); switch (token) { case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: bstrncat(bsize, lc->str, sizeof(bsize)); break; } } switch (type) { case STORE_SIZE: if (!size_to_uint64(bsize, &uvalue)) { scan_err1(lc, _("expected a size number, got: %s"), lc->str); return; } break; case STORE_SPEED: if (!speed_to_uint64(bsize, &uvalue)) { scan_err1(lc, _("expected a speed number, got: %s"), lc->str); return; } break; default: scan_err0(lc, _("unknown unit type encountered")); return; } if (size32) { *(uint32_t *)(item->value) = (uint32_t)uvalue; } else { *(uint64_t *)(item->value) = uvalue; } break; default: scan_err2(lc, _("expected a %s, got: %s"), (type == STORE_SIZE)?_("size"):_("speed"), lc->str); return; } if (token != T_EOL) { scan_to_eol(lc); } set_bit(index, res_all.hdr.item_present); Dmsg0(900, "Leave store_unit\n"); }
/* * For a given job, we examine all his run records * to see if it is scheduled today or tomorrow. */ RUNRES *find_next_run(RUNRES *run, JOBRES *job, utime_t &runtime, int ndays) { time_t now, future, endtime; SCHEDRES *sched; struct tm tm, runtm; int mday, wday, month, wom, i; int woy; int day; int is_scheduled; sched = job->schedule; if (sched == NULL) { /* scheduled? */ return NULL; /* no nothing to report */ } /* Break down the time into components */ now = time(NULL); endtime = now + (ndays * 60 * 60 * 24); if (run == NULL) { run = sched->run; } else { run = run->next; } for ( ; run; run=run->next) { /* * Find runs in next 24 hours. Day 0 is today, so if * ndays=1, look at today and tomorrow. */ for (day = 0; day <= ndays; day++) { future = now + (day * 60 * 60 * 24); /* Break down the time into components */ (void)localtime_r(&future, &tm); mday = tm.tm_mday - 1; wday = tm.tm_wday; month = tm.tm_mon; wom = mday / 7; woy = tm_woy(future); is_scheduled = bit_is_set(mday, run->mday) && bit_is_set(wday, run->wday) && bit_is_set(month, run->month) && bit_is_set(wom, run->wom) && bit_is_set(woy, run->woy); #ifdef xxx Pmsg2(000, "day=%d is_scheduled=%d\n", day, is_scheduled); Pmsg1(000, "bit_set_mday=%d\n", bit_is_set(mday, run->mday)); Pmsg1(000, "bit_set_wday=%d\n", bit_is_set(wday, run->wday)); Pmsg1(000, "bit_set_month=%d\n", bit_is_set(month, run->month)); Pmsg1(000, "bit_set_wom=%d\n", bit_is_set(wom, run->wom)); Pmsg1(000, "bit_set_woy=%d\n", bit_is_set(woy, run->woy)); #endif if (is_scheduled) { /* Jobs scheduled on that day */ #ifdef xxx char buf[300], num[10]; bsnprintf(buf, sizeof(buf), "tm.hour=%d hour=", tm.tm_hour); for (i=0; i<24; i++) { if (bit_is_set(i, run->hour)) { bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } bstrncat(buf, "\n", sizeof(buf)); Pmsg1(000, "%s", buf); #endif /* find time (time_t) job is to be run */ (void)localtime_r(&future, &runtm); for (i= 0; i < 24; i++) { if (bit_is_set(i, run->hour)) { runtm.tm_hour = i; runtm.tm_min = run->minute; runtm.tm_sec = 0; runtime = mktime(&runtm); Dmsg2(200, "now=%d runtime=%lld\n", now, runtime); if ((runtime > now) && (runtime < endtime)) { Dmsg2(200, "Found it level=%d %c\n", run->level, run->level); return run; /* found it, return run resource */ } } } } } } /* end for loop over runs */ /* Nothing found */ return NULL; }
/* * Prune at least one Volume in current Pool. This is called from * catreq.c => next_vol.c when the Storage daemon is asking for another * volume and no appendable volumes are available. * */ void prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr, STORERES *store) { int i; int count; POOL_DBR spr; UAContext *ua; dbid_list ids; struct del_ctx prune_list; POOL_MEM query(PM_MESSAGE); char ed1[50], ed2[100], ed3[50]; Dmsg1(100, "Prune volumes PoolId=%d\n", jcr->jr.PoolId); if (!jcr->res.job->PruneVolumes && !jcr->res.pool->AutoPrune) { Dmsg0(100, "AutoPrune not set in Pool.\n"); return; } memset(&prune_list, 0, sizeof(prune_list)); prune_list.max_ids = 10000; prune_list.JobId = (JobId_t *)malloc(sizeof(JobId_t) * prune_list.max_ids); ua = new_ua_context(jcr); db_lock(jcr->db); /* Edit PoolId */ edit_int64(mr->PoolId, ed1); /* * Get Pool record for Scratch Pool */ memset(&spr, 0, sizeof(spr)); bstrncpy(spr.Name, "Scratch", sizeof(spr.Name)); if (db_get_pool_record(jcr, jcr->db, &spr)) { edit_int64(spr.PoolId, ed2); bstrncat(ed2, ",", sizeof(ed2)); } else { ed2[0] = 0; } if (mr->ScratchPoolId) { edit_int64(mr->ScratchPoolId, ed3); bstrncat(ed2, ed3, sizeof(ed2)); bstrncat(ed2, ",", sizeof(ed2)); } Dmsg1(100, "Scratch pool(s)=%s\n", ed2); /* * ed2 ends up with scratch poolid and current poolid or * just current poolid if there is no scratch pool */ bstrncat(ed2, ed1, sizeof(ed2)); /* * Get the List of all media ids in the current Pool or whose * RecyclePoolId is the current pool or the scratch pool */ const char *select = "SELECT DISTINCT MediaId,LastWritten FROM Media WHERE " "(PoolId=%s OR RecyclePoolId IN (%s)) AND MediaType='%s' %s" "ORDER BY LastWritten ASC,MediaId"; if (InChanger) { char changer[100]; /* Ensure it is in this autochanger */ bsnprintf(changer, sizeof(changer), "AND InChanger=1 AND StorageId=%s ", edit_int64(mr->StorageId, ed3)); Mmsg(query, select, ed1, ed2, mr->MediaType, changer); } else { Mmsg(query, select, ed1, ed2, mr->MediaType, ""); } Dmsg1(100, "query=%s\n", query.c_str()); if (!db_get_query_dbids(ua->jcr, ua->db, query, ids)) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); goto bail_out; } Dmsg1(100, "Volume prune num_ids=%d\n", ids.num_ids); /* Visit each Volume and Prune it until we find one that is purged */ for (i=0; i<ids.num_ids; i++) { MEDIA_DBR lmr; lmr.MediaId = ids.DBId[i]; Dmsg1(100, "Get record MediaId=%d\n", (int)lmr.MediaId); if (!db_get_media_record(jcr, jcr->db, &lmr)) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); continue; } Dmsg1(100, "Examine vol=%s\n", lmr.VolumeName); /* Don't prune archived volumes */ if (lmr.Enabled == 2) { Dmsg1(100, "Vol=%s disabled\n", lmr.VolumeName); continue; } /* Prune only Volumes with status "Full", or "Used" */ if (bstrcmp(lmr.VolStatus, "Full") || bstrcmp(lmr.VolStatus, "Used")) { Dmsg2(100, "Add prune list MediaId=%d Volume %s\n", (int)lmr.MediaId, lmr.VolumeName); count = get_prune_list_for_volume(ua, &lmr, &prune_list); Dmsg1(100, "Num pruned = %d\n", count); if (count != 0) { purge_job_list_from_catalog(ua, prune_list); prune_list.num_ids = 0; /* reset count */ } if (!is_volume_purged(ua, &lmr)) { Dmsg1(050, "Vol=%s not pruned\n", lmr.VolumeName); continue; } Dmsg1(050, "Vol=%s is purged\n", lmr.VolumeName); /* * Since we are also pruning the Scratch pool, continue * until and check if this volume is available (InChanger + StorageId) * If not, just skip this volume and try the next one */ if (InChanger) { if (!lmr.InChanger || (lmr.StorageId != mr->StorageId)) { Dmsg1(100, "Vol=%s not inchanger or correct StoreId\n", lmr.VolumeName); continue; /* skip this volume, ie not loadable */ } } if (!lmr.Recycle) { Dmsg1(100, "Vol=%s not recyclable\n", lmr.VolumeName); continue; } if (has_volume_expired(jcr, &lmr)) { Dmsg1(100, "Vol=%s has expired\n", lmr.VolumeName); continue; /* Volume not usable */ } /* * If purged and not moved to another Pool, * then we stop pruning and take this volume. */ if (lmr.PoolId == mr->PoolId) { Dmsg2(100, "Got Vol=%s MediaId=%d purged.\n", lmr.VolumeName, (int)lmr.MediaId); mr->copy(&lmr); set_storageid_in_mr(store, mr); break; /* got a volume */ } } } bail_out: Dmsg0(100, "Leave prune volumes\n"); db_unlock(jcr->db); free_ua_context(ua); if (prune_list.JobId) { free(prune_list.JobId); } return; }