X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fbls.c;h=ced369248a141696a8dc095e4827be3aaf02e7da;hb=513c2c6cf9c7991273cf3330404575aafae6d8a2;hp=34b879e1d7a9b02448025a5b82cea320845763d1;hpb=ff667b88694132437eaa6a9d5906bb68f8a39c8d;p=bacula%2Fbacula diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index 34b879e1d7..ced369248a 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -1,45 +1,41 @@ /* - * - * Dumb program to do an "ls" of a Bacula 1.0 mortal file. - * - * Version $Id$ - */ -/* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Bacula(R) - The Network Backup Solution - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + Copyright (C) 2000-2016 Kern Sibbald - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. +*/ +/* + * + * Dumb program to do an "ls" of a Bacula 1.0 mortal file. + * + * Kern Sibbald, MM + * */ #include "bacula.h" #include "stored.h" #include "findlib/find.h" -#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) -int win32_client = 1; -#else -int win32_client = 0; -#endif +extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code); static void do_blocks(char *infname); static void do_jobs(char *infname); static void do_ls(char *fname); static void do_close(JCR *jcr); static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec); -static bool record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec); +static bool record_cb(DCR *dcr, DEV_RECORD *rec); static DEVICE *dev; static DCR *dcr; @@ -47,29 +43,36 @@ static bool dump_label = false; static bool list_blocks = false; static bool list_jobs = false; static DEV_RECORD *rec; -static DEV_BLOCK *block; static JCR *jcr; static SESSION_LABEL sessrec; static uint32_t num_files = 0; static ATTR *attr; +static CONFIG *config; +void *start_heap; #define CONFIG_FILE "bacula-sd.conf" -char *configfile; +char *configfile = NULL; +STORES *me = NULL; /* our Global resource */ bool forge_on = false; +pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER; +bool detect_errors = false; +int errors = 0; - -static FF_PKT ff; +static FF_PKT *ff; static BSR *bsr = NULL; static void usage() { - fprintf(stderr, -"\nVersion: " VERSION " (" BDATE ")\n\n" -"Usage: bls [-d debug_level] \n" + fprintf(stderr, _( +PROG_COPYRIGHT +"\n%sVersion: %s (%s)\n\n" +"Usage: bls [options] \n" " -b specify a bootstrap file\n" -" -c specify a config file\n" -" -d specify debug level\n" +" -c specify a Storage configuration file\n" +" -d set debug level to \n" +" -dt print timestamp in debug output\n" " -e exclude list\n" " -i include list\n" " -j list jobs\n" @@ -79,7 +82,8 @@ static void usage() " -p proceed inspite of errors\n" " -v be verbose\n" " -V specify Volume names (separated by |)\n" -" -? print this message\n\n"); +" -E Check records to detect errors\n" +" -? print this message\n\n"), 2000, "", VERSION, BDATE); exit(1); } @@ -93,88 +97,106 @@ int main (int argc, char *argv[]) char *bsrName = NULL; bool ignore_label_errors = false; + setlocale(LC_ALL, ""); + bindtextdomain("bacula", LOCALEDIR); + textdomain("bacula"); + init_stack_dump(); + lmgr_init_thread(); + working_directory = "/tmp"; my_name_is(argc, argv, "bls"); - init_msg(NULL, NULL); /* initialize message handler */ + init_msg(NULL, NULL); /* initialize message handler */ - memset(&ff, 0, sizeof(ff)); - init_include_exclude_files(&ff); + OSDependentInit(); - while ((ch = getopt(argc, argv, "b:c:d:e:i:jkLpvV:?")) != -1) { + ff = init_find_files(); + + while ((ch = getopt(argc, argv, "b:c:d:e:i:jkLpvV:?E")) != -1) { switch (ch) { case 'b': - bsrName = optarg; - break; + bsrName = optarg; + break; + + case 'E': + detect_errors = true; + break; case 'c': /* specify config file */ - if (configfile != NULL) { - free(configfile); - } - configfile = bstrdup(optarg); - break; + if (configfile != NULL) { + free(configfile); + } + configfile = bstrdup(optarg); + break; case 'd': /* debug level */ - debug_level = atoi(optarg); - if (debug_level <= 0) - debug_level = 1; - break; + if (*optarg == 't') { + dbg_timestamp = true; + } else { + debug_level = atoi(optarg); + if (debug_level <= 0) { + debug_level = 1; + } + } + break; case 'e': /* exclude list */ - if ((fd = fopen(optarg, "r")) == NULL) { + if ((fd = fopen(optarg, "rb")) == NULL) { + berrno be; Pmsg2(0, _("Could not open exclude file: %s, ERR=%s\n"), - optarg, strerror(errno)); - exit(1); - } - while (fgets(line, sizeof(line), fd) != NULL) { - strip_trailing_junk(line); + optarg, be.bstrerror()); + exit(1); + } + while (fgets(line, sizeof(line), fd) != NULL) { + strip_trailing_junk(line); Dmsg1(100, "add_exclude %s\n", line); - add_fname_to_exclude_list(&ff, line); - } - fclose(fd); - break; + add_fname_to_exclude_list(ff, line); + } + fclose(fd); + break; case 'i': /* include list */ - if ((fd = fopen(optarg, "r")) == NULL) { - Pmsg2(0, "Could not open include file: %s, ERR=%s\n", - optarg, strerror(errno)); - exit(1); - } - while (fgets(line, sizeof(line), fd) != NULL) { - strip_trailing_junk(line); + if ((fd = fopen(optarg, "rb")) == NULL) { + berrno be; + Pmsg2(0, _("Could not open include file: %s, ERR=%s\n"), + optarg, be.bstrerror()); + exit(1); + } + while (fgets(line, sizeof(line), fd) != NULL) { + strip_trailing_junk(line); Dmsg1(100, "add_include %s\n", line); - add_fname_to_include_list(&ff, 0, line); - } - fclose(fd); - break; + add_fname_to_include_list(ff, 0, line); + } + fclose(fd); + break; case 'j': - list_jobs = true; - break; + list_jobs = true; + break; case 'k': - list_blocks = true; - break; + list_blocks = true; + break; case 'L': - dump_label = true; - break; + dump_label = true; + break; case 'p': - ignore_label_errors = true; - forge_on = true; - break; + ignore_label_errors = true; + forge_on = true; + break; case 'v': - verbose++; - break; + verbose++; + break; case 'V': /* Volume name */ - VolumeName = optarg; - break; + VolumeName = optarg; + break; case '?': default: - usage(); + usage(); } /* end switch */ } /* end while */ @@ -190,123 +212,131 @@ int main (int argc, char *argv[]) configfile = bstrdup(CONFIG_FILE); } - parse_config(configfile); + config = new_config_parser(); + parse_sd_config(config, configfile, M_ERROR_TERM); + setup_me(); + load_sd_plugins(me->plugin_directory); - if (ff.included_files_list == NULL) { - add_fname_to_include_list(&ff, 0, "/"); + if (ff->included_files_list == NULL) { + add_fname_to_include_list(ff, 0, "/"); } for (i=0; i < argc; i++) { if (bsrName) { - bsr = parse_bsr(NULL, bsrName); + bsr = parse_bsr(NULL, bsrName); + } + jcr = setup_jcr("bls", argv[i], bsr, VolumeName, SD_READ); + if (!jcr) { + exit(1); } - jcr = setup_jcr("bls", argv[i], bsr, VolumeName); jcr->ignore_label_errors = ignore_label_errors; - dev = setup_to_access_device(jcr, 1); /* acquire for read */ + dev = jcr->dcr->dev; if (!dev) { - exit(1); + exit(1); } dcr = jcr->dcr; rec = new_record(); - block = new_block(dev); - attr = new_attr(); + attr = new_attr(jcr); /* * Assume that we have already read the volume label. - * If on second or subsequent volume, adjust buffer pointer + * If on second or subsequent volume, adjust buffer pointer */ - if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */ - Pmsg1(0, "\n\ -Warning, this Volume is a continuation of Volume %s\n", - dev->VolHdr.PrevVolName); + if (dev->VolHdr.PrevVolumeName[0] != 0) { /* second volume */ + Pmsg1(0, _("\n" + "Warning, this Volume is a continuation of Volume %s\n"), + dev->VolHdr.PrevVolumeName); } if (list_blocks) { - do_blocks(argv[i]); + do_blocks(argv[i]); } else if (list_jobs) { - do_jobs(argv[i]); + do_jobs(argv[i]); } else { - do_ls(argv[i]); + do_ls(argv[i]); } do_close(jcr); } if (bsr) { free_bsr(bsr); } + term_include_exclude_files(ff); + term_find_files(ff); + + if (detect_errors) { + return (errors > 0)? 1 : 0; + } return 0; } static void do_close(JCR *jcr) { - release_device(jcr); + release_device(jcr->dcr); free_attr(attr); free_record(rec); - free_block(block); free_jcr(jcr); - term_dev(dev); + dev->term(); } /* List just block information */ static void do_blocks(char *infname) { - if (verbose) { - dump_volume_label(dev); - rec = new_record(); - } + DEV_BLOCK *block = dcr->block; + char buf1[100], buf2[100]; for ( ;; ) { - if (!read_block_from_device(dcr, block, NO_BLOCK_NUMBER_CHECK)) { - Dmsg1(100, "!read_block(): ERR=%s\n", strerror_dev(dev)); - if (dev->state & ST_EOT) { - if (!mount_next_read_volume(jcr, dev, block)) { - Jmsg(jcr, M_INFO, 0, _("Got EOM at file %u on device %s, Volume \"%s\"\n"), - dev->file, dev_name(dev), jcr->VolumeName); - break; - } - /* Read and discard Volume label */ - DEV_RECORD *record; - record = new_record(); - read_block_from_device(dcr, block, NO_BLOCK_NUMBER_CHECK); - read_record_from_block(block, record); - get_session_record(dev, record, &sessrec); - free_record(record); - Jmsg(jcr, M_INFO, 0, _("Mounted Volume \"%s\".\n"), jcr->VolumeName); - - } else if (dev->state & ST_EOF) { - Jmsg(jcr, M_INFO, 0, _("Got EOF at file %u on device %s, Volume \"%s\"\n"), - dev->file, dev_name(dev), jcr->VolumeName); + if (!dcr->read_block_from_device(NO_BLOCK_NUMBER_CHECK)) { + Dmsg1(100, "!read_block(): ERR=%s\n", dev->print_errmsg()); + if (dev->at_eot()) { + if (!mount_next_read_volume(dcr)) { + Jmsg(jcr, M_INFO, 0, _("Got EOM at file %u on device %s, Volume \"%s\"\n"), + dev->file, dev->print_name(), dcr->VolumeName); + break; + } + /* Read and discard Volume label */ + DEV_RECORD *record; + record = new_record(); + dcr->read_block_from_device(NO_BLOCK_NUMBER_CHECK); + read_record_from_block(dcr, record); + get_session_record(dev, record, &sessrec); + free_record(record); + Jmsg(jcr, M_INFO, 0, _("Mounted Volume \"%s\".\n"), dcr->VolumeName); + } else if (dev->at_eof()) { + Jmsg(jcr, M_INFO, 0, _("End of file %u on device %s, Volume \"%s\"\n"), + dev->file, dev->print_name(), dcr->VolumeName); Dmsg0(20, "read_record got eof. try again\n"); - continue; - } else if (dev->state & ST_SHORT) { - Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg); - continue; - } else { - /* I/O error */ - display_tape_error_status(jcr, dev); - break; - } + continue; + } else if (dev->is_short_block()) { + Jmsg(jcr, M_INFO, 0, "%s", dev->print_errmsg()); + continue; + } else { + /* I/O error */ + errors++; + display_tape_error_status(jcr, dev); + break; + } } if (!match_bsr_block(bsr, block)) { Dmsg5(100, "reject Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n", - block->BlockNumber, block->block_len, block->BlockVer, - block->VolSessionId, block->VolSessionTime); - continue; + block->BlockNumber, block->block_len, block->BlockVer, + block->VolSessionId, block->VolSessionTime); + continue; } Dmsg5(100, "Blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n", - block->BlockNumber, block->block_len, block->BlockVer, - block->VolSessionId, block->VolSessionTime); + block->BlockNumber, block->block_len, block->BlockVer, + block->VolSessionId, block->VolSessionTime); if (verbose == 1) { - read_record_from_block(block, rec); - Pmsg9(-1, "File:blk=%u:%u blk_num=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n", - dev->file, dev->block_num, - block->BlockNumber, block->block_len, - FI_to_ascii(rec->FileIndex), rec->VolSessionId, rec->VolSessionTime, - stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len); - rec->remainder = 0; + read_record_from_block(dcr, rec); + Pmsg9(-1, _("File:blk=%u:%u blk_num=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"), + dev->file, dev->block_num, + block->BlockNumber, block->block_len, + FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, rec->VolSessionTime, + stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len); + rec->remainder = 0; } else if (verbose > 1) { dump_block(block, ""); } else { - printf("Block: %d size=%d\n", block->BlockNumber, block->block_len); + printf(_("Block: %d size=%d\n"), block->BlockNumber, block->block_len); } } @@ -316,10 +346,10 @@ static void do_blocks(char *infname) /* * We are only looking for labels or in particular Job Session records */ -static bool jobs_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) +static bool jobs_cb(DCR *dcr, DEV_RECORD *rec) { if (rec->FileIndex < 0) { - dump_label_record(dev, rec, verbose); + dump_label_record(dcr->dev, rec, verbose, detect_errors); } rec->remainder = 0; return true; @@ -328,7 +358,9 @@ static bool jobs_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) /* Do list job records */ static void do_jobs(char *infname) { - read_records(dcr, jobs_cb, mount_next_read_volume); + if (!read_records(dcr, jobs_cb, mount_next_read_volume)) { + errors++; + } } /* Do an ls type listing of an archive */ @@ -338,49 +370,62 @@ static void do_ls(char *infname) dump_volume_label(dev); return; } - read_records(dcr, record_cb, mount_next_read_volume); + if (!read_records(dcr, record_cb, mount_next_read_volume)) { + errors++; + } printf("%u files found.\n", num_files); } /* * Called here for each record from read_records() */ -static bool record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) +static bool record_cb(DCR *dcr, DEV_RECORD *rec) { - if (rec->FileIndex < 0) { - get_session_record(dev, rec, &sessrec); + if (verbose && rec->FileIndex < 0) { + dump_label_record(dcr->dev, rec, verbose, false); return true; } - /* File Attributes stream */ - if (rec->Stream == STREAM_UNIX_ATTRIBUTES || - rec->Stream == STREAM_UNIX_ATTRIBUTES_EX) { + if (verbose) { + char buf1[100], buf2[100]; + Pmsg6(000, "Record: FI=%s SessId=%d Strm=%s len=%u remlen=%d data_len=%d\n", + FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, + stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_bytes, rec->remlen, + rec->data_len); + } - if (verbose > 1) { - const char *rtype = "Attributes"; - Pmsg5(-1, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", - rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); - } - if (!unpack_attributes_record(jcr, rec->Stream, rec->data, attr)) { - if (!forge_on) { + /* File Attributes stream */ + if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES || + rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX) { + if (!unpack_attributes_record(jcr, rec->Stream, rec->data, rec->data_len, attr)) { + if (!forge_on) { Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n")); - } - num_files++; - return true; + } else { + Emsg0(M_ERROR, 0, _("Attrib unpack error!\n")); + } + num_files++; + return true; } - if (attr->file_index != rec->FileIndex) { - Emsg2(forge_on?M_WARNING:M_ERROR_TERM, 0, _("Record header file index %ld not equal record index %ld\n"), - rec->FileIndex, attr->file_index); - } - - attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI); + attr->data_stream = decode_stat(attr->attr, &attr->statp, sizeof(attr->statp), &attr->LinkFI); build_attr_output_fnames(jcr, attr); - if (file_is_included(&ff, attr->fname) && !file_is_excluded(&ff, attr->fname)) { - print_ls_output(jcr, attr); - num_files++; + if (file_is_included(ff, attr->fname) && !file_is_excluded(ff, attr->fname)) { + if (verbose) { + Pmsg5(000, _("FileIndex=%d VolSessionId=%d VolSessionTime=%d Stream=%d DataLen=%d\n"), + rec->FileIndex, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); + } + print_ls_output(jcr, attr); + num_files++; } + } else if (rec->Stream == STREAM_PLUGIN_NAME) { + char data[100]; + int len = MIN(rec->data_len+1, sizeof(data)); + bstrncpy(data, rec->data, len); + Dmsg1(100, "Plugin data: %s\n", data); + } else if (rec->Stream == STREAM_RESTORE_OBJECT) { + Dmsg0(100, "Restore Object record\n"); } + return true; } @@ -388,54 +433,76 @@ static bool record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec) { const char *rtype; - memset(sessrec, 0, sizeof(sessrec)); + memset(sessrec, 0, sizeof(SESSION_LABEL)); + jcr->JobId = 0; switch (rec->FileIndex) { case PRE_LABEL: - rtype = "Fresh Volume Label"; + rtype = _("Fresh Volume Label"); break; case VOL_LABEL: - rtype = "Volume Label"; + rtype = _("Volume Label"); unser_volume_label(dev, rec); break; case SOS_LABEL: - rtype = "Begin Job Session"; + rtype = _("Begin Job Session"); unser_session_label(sessrec, rec); + jcr->JobId = sessrec->JobId; break; case EOS_LABEL: - rtype = "End Job Session"; + rtype = _("End Job Session"); break; + case 0: case EOM_LABEL: - rtype = "End of Medium"; + rtype = _("End of Medium"); + break; + case EOT_LABEL: + rtype = _("End of Physical Medium"); + break; + case SOB_LABEL: + rtype = _("Start of object"); + break; + case EOB_LABEL: + rtype = _("End of object"); break; default: - rtype = "Unknown"; + rtype = _("Unknown"); + Dmsg1(10, "FI rtype=%d unknown\n", rec->FileIndex); break; } Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", - rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); + rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); if (verbose) { - Pmsg5(-1, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n", - rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); + Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"), + rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); } } /* Dummies to replace askdir.c */ -bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { return 1;} -bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} -bool dir_update_volume_info(DCR *dcr, bool relabel) { return 1; } -bool dir_create_jobmedia_record(DCR *dcr) { return 1; } -bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } -bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} -bool dir_send_job_status(JCR *jcr) {return 1;} +bool dir_find_next_appendable_volume(DCR *dcr) { return 1;} +bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; } +bool dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; } +bool flush_jobmedia_queue(JCR *jcr) { return true; } +bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; } +bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;} +bool dir_send_job_status(JCR *jcr) {return 1;} +int generate_job_event(JCR *jcr, const char *event) { return 1; } -bool dir_ask_sysop_to_mount_volume(DCR *dcr) +bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool /*writing*/) { - JCR *jcr = dcr->jcr; DEVICE *dev = dcr->dev; - fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ", - jcr->VolumeName, dev_name(dev)); - getchar(); + fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "), + dcr->VolumeName, dev->print_name()); + dev->close(); + getchar(); return true; } + +bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) +{ + Dmsg0(100, "Fake dir_get_volume_info\n"); + dcr->setVolCatName(dcr->VolumeName); + Dmsg2(500, "Vol=%s VolType=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatType); + return 1; +}