From: Kern Sibbald Date: Fri, 1 Apr 2005 15:21:46 +0000 (+0000) Subject: - Convert more atoi to str_to_int64() for DB. X-Git-Tag: Release-7.0.0~8905 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=a99080b63218b00f4f58416e08365ce49404abf7;p=bacula%2Fbacula - Convert more atoi to str_to_int64() for DB. - Implement filling in NumVols by querying DB rather than trying to keep track of it. - Add storage name to string passed to in use storage= - Fix newVolume() so that the Python script is always called. - Fix handling of pool,PoolId, and storage in ua_output. - Same fix in ua_status.c - Remove required locking of resources - Replace pthread_cond_signal() by pthread_cond_broadcast() hoping to fix the /lib/tls hang problems (lost signal). - Move resource locking seaching from parse_conf.c to res.c in src/lib. - Modify end of volume handling so that fixup_... does not redo what block.c has already done -- writing Vol info to DIR. This fixes a bug with bad numbers of files on a tape when it filled as reported by Peter. - In release_device() do not update the DIR on the Volume info if the the information was already written at the end of the tape. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1905 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index ccc09c81f8..63f5012697 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -26,13 +26,13 @@ Autochangers: and possibly manipulating the autochanger (much asked for). For 1.37: +- Add disk seeking on restore. - If the user puts "Purge Oldest Volume = yes" or "Recycle Oldest Volume = yes" and there is only one volume in the pool, refuse to do it -- otherwise he fills the Volume, then immediately starts reusing it. -- Add disk seeking on restore. - Implement "NewVolumeEachJob = yes|no" in Dir. - Make "update slots" when pointing to Autochanger, remove - all Volumes from other drives. + all Volumes from other drives. "update slots all-drives"? - Add Python writable variable for changing the Priority, Client, Storage, JobStatus (error), ... - SD Python @@ -44,7 +44,6 @@ For 1.37: - Look at Preben's acl.c error handling code. - Look at adding full Volume and Pool information to a Volume label so that bscan can get *all* the info. -- Scratch Pool where the volumes can be re-assigned to any Pool. - Implement Maximum Job Spool Size - 28-Mar 23:19 rufus-sd: acquire.c:379 Device "DDS-4" (/dev/nst0) is busy reading. Job 6 canceled. @@ -54,7 +53,14 @@ For 1.37: Dir next_vol.c - Finish implementation of passing all Storage and Device needs to the SD. - +- Check locking of resources -- be sure to lock devices where previously + resources were locked. +- Add global lock on all devices when creating a device structure. +- Remove separate thread for opening devices in SD. On the other + hand, don't block waiting for open() for devices. +- Make sure that Python has access to Client address/port so that + it can check if Clients are alive. +- Implement copies and stripes. Maybe in 1.37: - By the way: on page http://www.bacula.org/?page=tapedrives , at the @@ -1275,3 +1281,4 @@ Block Position: 0 - When Python creates a new label, the tape is immediately recycled and no label created. This happens when using autolabeling -- even when Python doesn't generate the name. +- Scratch Pool where the volumes can be re-assigned to any Pool. diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index e7b09f6115..e61133530e 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -56,7 +56,7 @@ static int int_handler(void *ctx, int num_fields, char **row) if (row[0]) { Dmsg1(800, "int_handler finds '%s'\n", row[0]); - *val = atoi(row[0]); + *val = str_to_int64(row[0]); } else { Dmsg0(800, "int_handler finds zero\n"); *val = 0; @@ -209,7 +209,7 @@ int get_sql_record_max(JCR *jcr, B_DB *mdb) Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); stat = -1; } else { - stat = atoi(row[0]); + stat = str_to_int64(row[0]); } sql_free_result(mdb); } else { diff --git a/bacula/src/cats/sql_delete.c b/bacula/src/cats/sql_delete.c index c24c786317..e03cf5cdaf 100644 --- a/bacula/src/cats/sql_delete.c +++ b/bacula/src/cats/sql_delete.c @@ -91,7 +91,7 @@ db_delete_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) db_unlock(mdb); return 0; } - pr->PoolId = atoi(row[0]); + pr->PoolId = str_to_int64(row[0]); sql_free_result(mdb); } diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 6151fa1502..354038280f 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -241,7 +241,7 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) return 0; } - jr->JobId = atoi(row[0]); + jr->JobId = str_to_int64(row[0]); sql_free_result(mdb); Dmsg1(100, "db_get_last_jobid: got JobId=%d\n", jr->JobId); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index da17f30695..78d0f13400 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -1,8 +1,8 @@ /* * Bacula Catalog Database Get record interface routines * Note, these routines generally get a record by id or - * by name. If more logic is involved, the routine - * should be in find.c + * by name. If more logic is involved, the routine + * should be in find.c * * Kern Sibbald, March 2000 * @@ -33,7 +33,7 @@ /* The following is necessary so that we do not include * the dummy external definition of DB. */ -#define __SQL_C /* indicate that this is sql.c */ +#define __SQL_C /* indicate that this is sql.c */ #include "bacula.h" #include "cats.h" @@ -65,7 +65,7 @@ extern void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname); * (with attributes) in the database. * * Returns: 0 on failure - * 1 on success with the File record in FILE_DBR + * 1 on success with the File record in FILE_DBR */ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr) { @@ -90,7 +90,7 @@ int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, /* * Get a File record * Returns: 0 on failure - * 1 on success + * 1 on success * * DO NOT use Jmsg in this routine. * @@ -133,21 +133,21 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr) Dmsg1(050, "get_file_record num_rows=%d\n", (int)mdb->num_rows); if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("get_file_record want 1 got rows=%d\n"), - mdb->num_rows); + mdb->num_rows); } if (mdb->num_rows >= 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("Error fetching row: %s\n"), sql_strerror(mdb)); - } else { - fdbr->FileId = (FileId_t)str_to_int64(row[0]); - bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat)); - bstrncpy(fdbr->SIG, row[2], sizeof(fdbr->SIG)); - stat = 1; - } + } else { + fdbr->FileId = (FileId_t)str_to_int64(row[0]); + bstrncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat)); + bstrncpy(fdbr->SIG, row[2], sizeof(fdbr->SIG)); + stat = 1; + } } else { Mmsg2(&mdb->errmsg, _("File record for PathId=%s FilenameId=%s not found.\n"), - edit_int64(fdbr->PathId, ed1), - edit_int64(fdbr->FilenameId, ed2)); + edit_int64(fdbr->PathId, ed1), + edit_int64(fdbr->FilenameId, ed2)); } sql_free_result(mdb); } else { @@ -159,7 +159,7 @@ int db_get_file_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, FILE_DBR *fdbr) /* Get Filename record * Returns: 0 on failure - * FilenameId on success + * FilenameId on success * * DO NOT use Jmsg in this routine (see notes for get_file_record) */ @@ -177,20 +177,20 @@ static int db_get_filename_record(JCR *jcr, B_DB *mdb) mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { Mmsg2(&mdb->errmsg, _("More than one Filename!: %s for file: %s\n"), - edit_uint64(mdb->num_rows, ed1), mdb->fname); + edit_uint64(mdb->num_rows, ed1), mdb->fname); Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg); } if (mdb->num_rows >= 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - } else { - FilenameId = atoi(row[0]); - if (FilenameId <= 0) { + } else { + FilenameId = str_to_int64(row[0]); + if (FilenameId <= 0) { Mmsg2(&mdb->errmsg, _("Get DB Filename record %s found bad record: %d\n"), - mdb->cmd, FilenameId); - FilenameId = 0; - } - } + mdb->cmd, FilenameId); + FilenameId = 0; + } + } } else { Mmsg1(&mdb->errmsg, _("Filename record: %s not found.\n"), mdb->fname); } @@ -203,7 +203,7 @@ static int db_get_filename_record(JCR *jcr, B_DB *mdb) /* Get path record * Returns: 0 on failure - * PathId on success + * PathId on success * * DO NOT use Jmsg in this routine (see notes for get_file_record) */ @@ -227,28 +227,28 @@ static int db_get_path_record(JCR *jcr, B_DB *mdb) mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { Mmsg2(&mdb->errmsg, _("More than one Path!: %s for path: %s\n"), - edit_uint64(mdb->num_rows, ed1), mdb->path); + edit_uint64(mdb->num_rows, ed1), mdb->path); Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg); } /* Even if there are multiple paths, take the first one */ if (mdb->num_rows >= 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - } else { - PathId = atoi(row[0]); - if (PathId <= 0) { + } else { + PathId = str_to_int64(row[0]); + if (PathId <= 0) { Mmsg2(&mdb->errmsg, _("Get DB path record %s found bad record: %s\n"), - mdb->cmd, edit_int64(PathId, ed1)); - PathId = 0; - } else { - /* Cache path */ - if (PathId != mdb->cached_path_id) { - mdb->cached_path_id = PathId; - mdb->cached_path_len = mdb->pnl; - pm_strcpy(&mdb->cached_path, mdb->path); - } - } - } + mdb->cmd, edit_int64(PathId, ed1)); + PathId = 0; + } else { + /* Cache path */ + if (PathId != mdb->cached_path_id) { + mdb->cached_path_id = PathId; + mdb->cached_path_len = mdb->pnl; + pm_strcpy(&mdb->cached_path, mdb->path); + } + } + } } else { Mmsg1(&mdb->errmsg, _("Path record: %s not found.\n"), mdb->path); } @@ -263,7 +263,7 @@ static int db_get_path_record(JCR *jcr, B_DB *mdb) /* * Get Job record for given JobId or Job name * Returns: 0 on failure - * 1 on success + * 1 on success */ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { @@ -281,18 +281,18 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) "PoolId,StartTime,EndTime,JobFiles,JobBytes,JobTDate,Job,JobStatus," "Type,Level,ClientId " "FROM Job WHERE JobId=%s", - edit_int64(jr->JobId, ed1)); + edit_int64(jr->JobId, ed1)); } if (!QUERY_DB(jcr, mdb, mdb->cmd)) { db_unlock(mdb); - return 0; /* failed */ + return 0; /* failed */ } if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("No Job found for JobId %s\n"), edit_int64(jr->JobId, ed1)); sql_free_result(mdb); db_unlock(mdb); - return 0; /* failed */ + return 0; /* failed */ } jr->VolSessionId = str_to_uint64(row[0]); @@ -300,7 +300,7 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) jr->PoolId = str_to_int64(row[2]); bstrncpy(jr->cStartTime, row[3]!=NULL?row[3]:"", sizeof(jr->cStartTime)); bstrncpy(jr->cEndTime, row[4]!=NULL?row[4]:"", sizeof(jr->cEndTime)); - jr->JobFiles = atol(row[5]); + jr->JobFiles = str_to_int64(row[5]); jr->JobBytes = str_to_int64(row[6]); jr->JobTDate = str_to_int64(row[7]); bstrncpy(jr->Job, row[8]!=NULL?row[8]:"", sizeof(jr->Job)); @@ -317,10 +317,10 @@ int db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) /* * Find VolumeNames for a given JobId * Returns: 0 on error or no Volumes found - * number of volumes on success - * Volumes are concatenated in VolumeNames - * separated by a vertical bar (|) in the order - * that they were written. + * number of volumes on success + * Volumes are concatenated in VolumeNames + * separated by a vertical bar (|) in the order + * that they were written. * * Returns: number of volumes on success */ @@ -346,22 +346,22 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **Volume Dmsg1(130, "Num rows=%d\n", mdb->num_rows); if (mdb->num_rows <= 0) { Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId); - stat = 0; + stat = 0; } else { - stat = mdb->num_rows; - for (i=0; i < stat; i++) { - if ((row = sql_fetch_row(mdb)) == NULL) { + stat = mdb->num_rows; + for (i=0; i < stat; i++) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - stat = 0; - break; - } else { - if (*VolumeNames[0] != 0) { + stat = 0; + break; + } else { + if (*VolumeNames[0] != 0) { pm_strcat(VolumeNames, "|"); - } - pm_strcat(VolumeNames, row[0]); - } - } + } + pm_strcat(VolumeNames, row[0]); + } + } } sql_free_result(mdb); } else { @@ -374,8 +374,8 @@ int db_get_job_volume_names(JCR *jcr, B_DB *mdb, JobId_t JobId, POOLMEM **Volume /* * Find Volume parameters for a give JobId * Returns: 0 on error or no Volumes found - * number of volumes on success - * List of Volumes and start/end file/blocks (malloced structure!) + * number of volumes on success + * List of Volumes and start/end file/blocks (malloced structure!) * * Returns: number of volumes on success */ @@ -393,7 +393,7 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS "JobMedia.EndFile,StartBlock,JobMedia.EndBlock" " FROM JobMedia,Media WHERE JobMedia.JobId=%s" " AND JobMedia.MediaId=Media.MediaId ORDER BY VolIndex,JobMediaId", - edit_int64(JobId, ed1)); + edit_int64(JobId, ed1)); Dmsg1(130, "VolNam=%s\n", mdb->cmd); if (QUERY_DB(jcr, mdb, mdb->cmd)) { @@ -401,29 +401,29 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS Dmsg1(130, "Num rows=%d\n", mdb->num_rows); if (mdb->num_rows <= 0) { Mmsg1(&mdb->errmsg, _("No volumes found for JobId=%d\n"), JobId); - stat = 0; + stat = 0; } else { - stat = mdb->num_rows; - if (stat > 0) { - *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS)); - } - for (i=0; i < stat; i++) { - if ((row = sql_fetch_row(mdb)) == NULL) { + stat = mdb->num_rows; + if (stat > 0) { + *VolParams = Vols = (VOL_PARAMS *)malloc(stat * sizeof(VOL_PARAMS)); + } + for (i=0; i < stat; i++) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg2(&mdb->errmsg, _("Error fetching row %d: ERR=%s\n"), i, sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - stat = 0; - break; - } else { - bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH); - bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH); - Vols[i].FirstIndex = str_to_uint64(row[2]); - Vols[i].LastIndex = str_to_uint64(row[3]); - Vols[i].StartFile = str_to_uint64(row[4]); - Vols[i].EndFile = str_to_uint64(row[5]); - Vols[i].StartBlock = str_to_uint64(row[6]); - Vols[i].EndBlock = str_to_uint64(row[7]); - } - } + stat = 0; + break; + } else { + bstrncpy(Vols[i].VolumeName, row[0], MAX_NAME_LENGTH); + bstrncpy(Vols[i].MediaType, row[1], MAX_NAME_LENGTH); + Vols[i].FirstIndex = str_to_uint64(row[2]); + Vols[i].LastIndex = str_to_uint64(row[3]); + Vols[i].StartFile = str_to_uint64(row[4]); + Vols[i].EndFile = str_to_uint64(row[5]); + Vols[i].StartBlock = str_to_uint64(row[6]); + Vols[i].EndBlock = str_to_uint64(row[7]); + } + } } sql_free_result(mdb); } @@ -437,7 +437,7 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS * Get the number of pool records * * Returns: -1 on failure - * number on success + * number on success */ int db_get_num_pool_records(JCR *jcr, B_DB *mdb) { @@ -455,7 +455,7 @@ int db_get_num_pool_records(JCR *jcr, B_DB *mdb) * The caller must free ids if non-NULL. * * Returns 0: on failure - * 1: on success + * 1: on success */ int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) { @@ -470,11 +470,11 @@ int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) if (QUERY_DB(jcr, mdb, mdb->cmd)) { *num_ids = sql_num_rows(mdb); if (*num_ids > 0) { - id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t)); - while ((row = sql_fetch_row(mdb)) != NULL) { - id[i++] = str_to_uint64(row[0]); - } - *ids = id; + id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t)); + while ((row = sql_fetch_row(mdb)) != NULL) { + id[i++] = str_to_uint64(row[0]); + } + *ids = id; } sql_free_result(mdb); stat = 1; @@ -492,7 +492,7 @@ int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) * The caller must free ids if non-NULL. * * Returns 0: on failure - * 1: on success + * 1: on success */ int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) { @@ -507,11 +507,11 @@ int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) if (QUERY_DB(jcr, mdb, mdb->cmd)) { *num_ids = sql_num_rows(mdb); if (*num_ids > 0) { - id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t)); - while ((row = sql_fetch_row(mdb)) != NULL) { - id[i++] = str_to_uint64(row[0]); - } - *ids = id; + id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t)); + while ((row = sql_fetch_row(mdb)) != NULL) { + id[i++] = str_to_uint64(row[0]); + } + *ids = id; } sql_free_result(mdb); stat = 1; @@ -531,7 +531,7 @@ int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) * otherwise, we search on the PoolName * * Returns: false on failure - * true on success + * true on success */ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) { @@ -540,51 +540,51 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) char ed1[50]; db_lock(mdb); - if (pdbr->PoolId != 0) { /* find by id */ + if (pdbr->PoolId != 0) { /* find by id */ Mmsg(mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume," "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "MaxVolBytes,PoolType,LabelType,LabelFormat FROM Pool WHERE Pool.PoolId=%s", - edit_int64(pdbr->PoolId, ed1)); - } else { /* find by name */ + edit_int64(pdbr->PoolId, ed1)); + } else { /* find by name */ Mmsg(mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,AcceptAnyVolume," "AutoPrune,Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," "MaxVolBytes,PoolType,LabelType,LabelFormat FROM Pool WHERE Pool.Name='%s'", - pdbr->Name); + pdbr->Name); } if (QUERY_DB(jcr, mdb, mdb->cmd)) { mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { - char ed1[30]; + char ed1[30]; Mmsg1(&mdb->errmsg, _("More than one Pool!: %s\n"), - edit_uint64(mdb->num_rows, ed1)); + edit_uint64(mdb->num_rows, ed1)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); } else if (mdb->num_rows == 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - } else { - pdbr->PoolId = str_to_int64(row[0]); + } else { + pdbr->PoolId = str_to_int64(row[0]); bstrncpy(pdbr->Name, row[1]!=NULL?row[1]:"", sizeof(pdbr->Name)); - pdbr->NumVols = str_to_int64(row[2]); - pdbr->MaxVols = str_to_int64(row[3]); - pdbr->UseOnce = str_to_int64(row[4]); - pdbr->UseCatalog = str_to_int64(row[5]); - pdbr->AcceptAnyVolume = str_to_int64(row[6]); - pdbr->AutoPrune = str_to_int64(row[7]); - pdbr->Recycle = str_to_int64(row[8]); - pdbr->VolRetention = str_to_int64(row[9]); - pdbr->VolUseDuration = str_to_int64(row[10]); - pdbr->MaxVolJobs = str_to_int64(row[11]); - pdbr->MaxVolFiles = str_to_int64(row[12]); - pdbr->MaxVolBytes = str_to_uint64(row[13]); + pdbr->NumVols = str_to_int64(row[2]); + pdbr->MaxVols = str_to_int64(row[3]); + pdbr->UseOnce = str_to_int64(row[4]); + pdbr->UseCatalog = str_to_int64(row[5]); + pdbr->AcceptAnyVolume = str_to_int64(row[6]); + pdbr->AutoPrune = str_to_int64(row[7]); + pdbr->Recycle = str_to_int64(row[8]); + pdbr->VolRetention = str_to_int64(row[9]); + pdbr->VolUseDuration = str_to_int64(row[10]); + pdbr->MaxVolJobs = str_to_int64(row[11]); + pdbr->MaxVolFiles = str_to_int64(row[12]); + pdbr->MaxVolBytes = str_to_uint64(row[13]); bstrncpy(pdbr->PoolType, row[14]!=NULL?row[14]:"", sizeof(pdbr->PoolType)); - pdbr->LabelType = str_to_int64(row[15]); + pdbr->LabelType = str_to_int64(row[15]); bstrncpy(pdbr->LabelFormat, row[16]!=NULL?row[16]:"", sizeof(pdbr->LabelFormat)); - ok = true; - } + ok = true; + } } else { Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n")); } @@ -592,6 +592,10 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) } else { Mmsg(mdb->errmsg, _("Pool record not found in Catalog.\n")); } + if (ok) { + Mmsg(mdb->cmd, "SELECT count(*) from Pool"); + pdbr->NumVols = get_sql_record_max(jcr, mdb); + } db_unlock(mdb); return ok; } @@ -601,7 +605,7 @@ bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr) * otherwise, we search on the Client Name * * Returns: 0 on failure - * 1 on success + * 1 on success */ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr) { @@ -610,12 +614,12 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr) char ed1[50]; db_lock(mdb); - if (cdbr->ClientId != 0) { /* find by id */ + if (cdbr->ClientId != 0) { /* find by id */ Mmsg(mdb->cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention " "FROM Client WHERE Client.ClientId=%s", - edit_int64(cdbr->ClientId, ed1)); - } else { /* find by name */ + edit_int64(cdbr->ClientId, ed1)); + } else { /* find by name */ Mmsg(mdb->cmd, "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,JobRetention " "FROM Client WHERE Client.Name='%s'", cdbr->Name); @@ -625,21 +629,21 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr) mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("More than one Client!: %s\n"), - edit_uint64(mdb->num_rows, ed1)); + edit_uint64(mdb->num_rows, ed1)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); } else if (mdb->num_rows == 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - } else { - cdbr->ClientId = str_to_int64(row[0]); + } else { + cdbr->ClientId = str_to_int64(row[0]); bstrncpy(cdbr->Name, row[1]!=NULL?row[1]:"", sizeof(cdbr->Name)); bstrncpy(cdbr->Uname, row[2]!=NULL?row[1]:"", sizeof(cdbr->Uname)); - cdbr->AutoPrune = str_to_int64(row[3]); - cdbr->FileRetention = str_to_int64(row[4]); - cdbr->JobRetention = str_to_int64(row[5]); - stat = 1; - } + cdbr->AutoPrune = str_to_int64(row[3]); + cdbr->FileRetention = str_to_int64(row[4]); + cdbr->JobRetention = str_to_int64(row[5]); + stat = 1; + } } else { Mmsg(mdb->errmsg, _("Client record not found in Catalog.\n")); } @@ -655,7 +659,7 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr) * Get Counter Record * * Returns: 0 on failure - * 1 on success + * 1 on success */ int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) { @@ -674,24 +678,24 @@ int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); } if (mdb->num_rows >= 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - sql_free_result(mdb); - db_unlock(mdb); - return 0; - } - cr->MinValue = atoi(row[0]); - cr->MaxValue = atoi(row[1]); - cr->CurrentValue = atoi(row[2]); - if (row[3]) { - bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter)); - } else { - cr->WrapCounter[0] = 0; - } - sql_free_result(mdb); - db_unlock(mdb); - return 1; + sql_free_result(mdb); + db_unlock(mdb); + return 0; + } + cr->MinValue = str_to_int64(row[0]); + cr->MaxValue = str_to_int64(row[1]); + cr->CurrentValue = str_to_int64(row[2]); + if (row[3]) { + bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter)); + } else { + cr->WrapCounter[0] = 0; + } + sql_free_result(mdb); + db_unlock(mdb); + return 1; } sql_free_result(mdb); } else { @@ -707,7 +711,7 @@ int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) * otherwise, we search on the name * * Returns: 0 on failure - * id on success + * id on success */ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) { @@ -716,12 +720,12 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) char ed1[50]; db_lock(mdb); - if (fsr->FileSetId != 0) { /* find by id */ + if (fsr->FileSetId != 0) { /* find by id */ Mmsg(mdb->cmd, "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet " "WHERE FileSetId=%s", - edit_int64(fsr->FileSetId, ed1)); - } else { /* find by name */ + edit_int64(fsr->FileSetId, ed1)); + } else { /* find by name */ Mmsg(mdb->cmd, "SELECT FileSetId,FileSet,CreateTime,MD5 FROM FileSet " "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", fsr->FileSet); @@ -730,19 +734,19 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) if (QUERY_DB(jcr, mdb, mdb->cmd)) { mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { - char ed1[30]; + char ed1[30]; Mmsg1(&mdb->errmsg, _("Error got %s FileSets but expected only one!\n"), - edit_uint64(mdb->num_rows, ed1)); - sql_data_seek(mdb, mdb->num_rows-1); + edit_uint64(mdb->num_rows, ed1)); + sql_data_seek(mdb, mdb->num_rows-1); } if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("FileSet record \"%s\" not found.\n"), fsr->FileSet); } else { - fsr->FileSetId = str_to_int64(row[0]); + fsr->FileSetId = str_to_int64(row[0]); bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet)); bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5)); bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime)); - stat = fsr->FileSetId; + stat = fsr->FileSetId; } sql_free_result(mdb); } else { @@ -757,7 +761,7 @@ int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) * Get the number of Media records * * Returns: -1 on failure - * number on success + * number on success */ int db_get_num_media_records(JCR *jcr, B_DB *mdb) { @@ -777,7 +781,7 @@ int db_get_num_media_records(JCR *jcr, B_DB *mdb) * The caller must free ids if non-NULL. * * Returns 0: on failure - * 1: on success + * 1: on success */ int db_get_media_ids(JCR *jcr, B_DB *mdb, uint32_t PoolId, int *num_ids, uint32_t *ids[]) { @@ -794,11 +798,11 @@ int db_get_media_ids(JCR *jcr, B_DB *mdb, uint32_t PoolId, int *num_ids, uint32_ if (QUERY_DB(jcr, mdb, mdb->cmd)) { *num_ids = sql_num_rows(mdb); if (*num_ids > 0) { - id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t)); - while ((row = sql_fetch_row(mdb)) != NULL) { - id[i++] = (uint32_t)atoi(row[0]); - } - *ids = id; + id = (uint32_t *)malloc(*num_ids * sizeof(uint32_t)); + while ((row = sql_fetch_row(mdb)) != NULL) { + id[i++] = str_to_uint64(row[0]); + } + *ids = id; } sql_free_result(mdb); stat = 1; @@ -815,7 +819,7 @@ int db_get_media_ids(JCR *jcr, B_DB *mdb, uint32_t PoolId, int *num_ids, uint32_ /* Get Media Record * * Returns: 0 on failure - * id on success + * id on success */ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) { @@ -830,15 +834,15 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) db_unlock(mdb); return 1; } - if (mr->MediaId != 0) { /* find by id */ + if (mr->MediaId != 0) { /* find by id */ Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs," "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger," "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId " "FROM Media WHERE MediaId=%s", - edit_int64(mr->MediaId, ed1)); - } else { /* find by name */ + edit_int64(mr->MediaId, ed1)); + } else { /* find by name */ Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs," @@ -852,65 +856,65 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mdb->num_rows = sql_num_rows(mdb); if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("More than one Volume!: %s\n"), - edit_uint64(mdb->num_rows, ed1)); + edit_uint64(mdb->num_rows, ed1)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); } else if (mdb->num_rows == 1) { - if ((row = sql_fetch_row(mdb)) == NULL) { + if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); - } else { - /* return values */ - mr->MediaId = str_to_int64(row[0]); + } else { + /* return values */ + mr->MediaId = str_to_int64(row[0]); bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName)); - mr->VolJobs = str_to_int64(row[2]); - mr->VolFiles = str_to_int64(row[3]); - mr->VolBlocks = str_to_int64(row[4]); - mr->VolBytes = str_to_uint64(row[5]); - mr->VolMounts = str_to_int64(row[6]); - mr->VolErrors = str_to_int64(row[7]); - mr->VolWrites = str_to_int64(row[8]); - mr->MaxVolBytes = str_to_uint64(row[9]); - mr->VolCapacityBytes = str_to_uint64(row[10]); + mr->VolJobs = str_to_int64(row[2]); + mr->VolFiles = str_to_int64(row[3]); + mr->VolBlocks = str_to_int64(row[4]); + mr->VolBytes = str_to_uint64(row[5]); + mr->VolMounts = str_to_int64(row[6]); + mr->VolErrors = str_to_int64(row[7]); + mr->VolWrites = str_to_int64(row[8]); + mr->MaxVolBytes = str_to_uint64(row[9]); + mr->VolCapacityBytes = str_to_uint64(row[10]); bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType)); bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus)); - mr->PoolId = str_to_int64(row[13]); - mr->VolRetention = str_to_uint64(row[14]); - mr->VolUseDuration = str_to_uint64(row[15]); - mr->MaxVolJobs = str_to_int64(row[16]); - mr->MaxVolFiles = str_to_int64(row[17]); - mr->Recycle = str_to_int64(row[18]); - mr->Slot = str_to_int64(row[19]); + mr->PoolId = str_to_int64(row[13]); + mr->VolRetention = str_to_uint64(row[14]); + mr->VolUseDuration = str_to_uint64(row[15]); + mr->MaxVolJobs = str_to_int64(row[16]); + mr->MaxVolFiles = str_to_int64(row[17]); + mr->Recycle = str_to_int64(row[18]); + mr->Slot = str_to_int64(row[19]); bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten)); - mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten); + mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten); bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten)); - mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten); - mr->InChanger = str_to_uint64(row[22]); - mr->EndFile = str_to_uint64(row[23]); - mr->EndBlock = str_to_uint64(row[24]); - mr->VolParts = str_to_int64(row[25]); - mr->LabelType = str_to_int64(row[26]); + mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten); + mr->InChanger = str_to_uint64(row[22]); + mr->EndFile = str_to_uint64(row[23]); + mr->EndBlock = str_to_uint64(row[24]); + mr->VolParts = str_to_int64(row[25]); + mr->LabelType = str_to_int64(row[26]); bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate)); - mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate); - mr->StorageId = str_to_int64(row[28]); - stat = mr->MediaId; - } + mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate); + mr->StorageId = str_to_int64(row[28]); + stat = mr->MediaId; + } } else { - if (mr->MediaId != 0) { + if (mr->MediaId != 0) { Mmsg1(&mdb->errmsg, _("Media record MediaId=%s not found.\n"), - edit_int64(mr->MediaId, ed1)); - } else { + edit_int64(mr->MediaId, ed1)); + } else { Mmsg1(&mdb->errmsg, _("Media record for Volume \"%s\" not found.\n"), - mr->VolumeName); - } + mr->VolumeName); + } } sql_free_result(mdb); } else { if (mr->MediaId != 0) { Mmsg(mdb->errmsg, _("Media record for MediaId=%u not found in Catalog.\n"), - mr->MediaId); + mr->MediaId); } else { Mmsg(mdb->errmsg, _("Media record for Vol=%s not found in Catalog.\n"), - mr->VolumeName); + mr->VolumeName); } } db_unlock(mdb); return stat; diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index c1e499cd2d..17ff0a1946 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -134,13 +134,14 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { bnet_fsend(bs, "1901 No Media.\n"); + Dmsg0(500, "1901 No Media.\n"); } /* * Request to find specific Volume information */ } else if (sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName, &writing) == 3) { - Dmsg1(400, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName); + Dmsg1(500, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName); /* * Find the Volume */ @@ -194,6 +195,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) } else { bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName); + Dmsg1(400, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName); } /* diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 9fed95bc7a..6d7af10e52 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -517,7 +517,7 @@ static int check_resources() int64_t *def_lvalue, *lvalue; /* 64 bit values */ uint32_t offset; - Dmsg4(400, "Job \"%s\", field \"%s\" bit=%d def=%d\n", + Dmsg4(1400, "Job \"%s\", field \"%s\" bit=%d def=%d\n", job->hdr.name, job_items[i].name, bit_is_set(i, job->hdr.item_present), bit_is_set(i, job->jobdefs->hdr.item_present)); diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index ef9a1d7c58..8175a89258 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -36,8 +36,6 @@ static void job_monitor_destructor(watchdog_t *self); static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr); static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr); -/* Exported subroutines */ - /* Imported subroutines */ extern void term_scheduler(); extern void term_ua_server(); diff --git a/bacula/src/dird/jobq.c b/bacula/src/dird/jobq.c index 984fea3238..ccc794e929 100755 --- a/bacula/src/dird/jobq.c +++ b/bacula/src/dird/jobq.c @@ -55,7 +55,7 @@ static bool acquire_resources(JCR *jcr); * Initialize a job queue * * Returns: 0 on success - * errno on failure + * errno on failure */ int jobq_init(jobq_t *jq, int threads, void *(*engine)(void *arg)) { @@ -85,10 +85,10 @@ int jobq_init(jobq_t *jq, int threads, void *(*engine)(void *arg)) return stat; } jq->quit = false; - jq->max_workers = threads; /* max threads to create */ - jq->num_workers = 0; /* no threads yet */ - jq->idle_workers = 0; /* no idle threads */ - jq->engine = engine; /* routine to run */ + jq->max_workers = threads; /* max threads to create */ + jq->num_workers = 0; /* no threads yet */ + jq->idle_workers = 0; /* no idle threads */ + jq->engine = engine; /* routine to run */ jq->valid = JOBQ_VALID; /* Initialize the job queues */ jq->waiting_jobs = New(dlist(item, &item->link)); @@ -101,7 +101,7 @@ int jobq_init(jobq_t *jq, int threads, void *(*engine)(void *arg)) * Destroy the job queue * * Returns: 0 on success - * errno on failure + * errno on failure */ int jobq_destroy(jobq_t *jq) { @@ -115,7 +115,7 @@ int jobq_destroy(jobq_t *jq) Jmsg1(NULL, M_ERROR, 0, "pthread_mutex_lock: ERR=%s\n", be.strerror(stat)); return stat; } - jq->valid = 0; /* prevent any more operations */ + jq->valid = 0; /* prevent any more operations */ /* * If any threads are active, wake them @@ -123,20 +123,20 @@ int jobq_destroy(jobq_t *jq) if (jq->num_workers > 0) { jq->quit = true; if (jq->idle_workers) { - if ((stat = pthread_cond_broadcast(&jq->work)) != 0) { - berrno be; + if ((stat = pthread_cond_broadcast(&jq->work)) != 0) { + berrno be; Jmsg1(NULL, M_ERROR, 0, "pthread_cond_broadcast: ERR=%s\n", be.strerror(stat)); - pthread_mutex_unlock(&jq->mutex); - return stat; - } + pthread_mutex_unlock(&jq->mutex); + return stat; + } } while (jq->num_workers > 0) { - if ((stat = pthread_cond_wait(&jq->work, &jq->mutex)) != 0) { - berrno be; + if ((stat = pthread_cond_wait(&jq->work, &jq->mutex)) != 0) { + berrno be; Jmsg1(NULL, M_ERROR, 0, "pthread_cond_wait: ERR=%s\n", be.strerror(stat)); - pthread_mutex_unlock(&jq->mutex); - return stat; - } + pthread_mutex_unlock(&jq->mutex); + return stat; + } } } if ((stat = pthread_mutex_unlock(&jq->mutex)) != 0) { @@ -178,24 +178,24 @@ void *sched_wait(void *arg) /* Wait until scheduled time arrives */ if (wtime > 0) { Jmsg(jcr, M_INFO, 0, _("Job %s waiting %d seconds for scheduled start time.\n"), - jcr->Job, wtime); + jcr->Job, wtime); } /* Check every 30 seconds if canceled */ while (wtime > 0) { Dmsg2(2300, "Waiting on sched time, jobid=%d secs=%d\n", jcr->JobId, wtime); if (wtime > 30) { - wtime = 30; + wtime = 30; } bmicrosleep(wtime, 0); if (job_canceled(jcr)) { - break; + break; } wtime = jcr->sched_time - time(NULL); } - P(jcr->mutex); /* lock jcr */ + P(jcr->mutex); /* lock jcr */ jobq_add(jq, jcr); V(jcr->mutex); - free_jcr(jcr); /* we are done with jcr */ + free_jcr(jcr); /* we are done with jcr */ Dmsg0(2300, "Exit sched_wait\n"); return NULL; } @@ -222,17 +222,17 @@ int jobq_add(jobq_t *jq, JCR *jcr) return EINVAL; } - jcr->use_count++; /* mark jcr in use by us */ + jcr->use_count++; /* mark jcr in use by us */ Dmsg3(2300, "jobq_add jobid=%d jcr=0x%x use_count=%d\n", jcr->JobId, jcr, jcr->use_count); if (!job_canceled(jcr) && wtime > 0) { set_thread_concurrency(jq->max_workers + 2); sched_pkt = (wait_pkt *)malloc(sizeof(wait_pkt)); sched_pkt->jcr = jcr; sched_pkt->jq = jq; -// jcr->use_count--; /* release our use of jcr */ - stat = pthread_create(&id, &jq->attr, sched_wait, (void *)sched_pkt); - if (stat != 0) { /* thread not created */ - berrno be; +// jcr->use_count--; /* release our use of jcr */ + stat = pthread_create(&id, &jq->attr, sched_wait, (void *)sched_pkt); + if (stat != 0) { /* thread not created */ + berrno be; Jmsg1(jcr, M_ERROR, 0, "pthread_thread_create: ERR=%s\n", be.strerror(stat)); } return stat; @@ -241,12 +241,12 @@ int jobq_add(jobq_t *jq, JCR *jcr) if ((stat = pthread_mutex_lock(&jq->mutex)) != 0) { berrno be; Jmsg1(jcr, M_ERROR, 0, "pthread_mutex_lock: ERR=%s\n", be.strerror(stat)); - jcr->use_count--; /* release jcr */ + jcr->use_count--; /* release jcr */ return stat; } if ((item = (jobq_item_t *)malloc(sizeof(jobq_item_t))) == NULL) { - jcr->use_count--; /* release jcr */ + jcr->use_count--; /* release jcr */ return ENOMEM; } item->jcr = jcr; @@ -259,18 +259,18 @@ int jobq_add(jobq_t *jq, JCR *jcr) /* Add this job to the wait queue in priority sorted order */ foreach_dlist(li, jq->waiting_jobs) { Dmsg2(2300, "waiting item jobid=%d priority=%d\n", - li->jcr->JobId, li->jcr->JobPriority); - if (li->jcr->JobPriority > jcr->JobPriority) { - jq->waiting_jobs->insert_before(item, li); + li->jcr->JobId, li->jcr->JobPriority); + if (li->jcr->JobPriority > jcr->JobPriority) { + jq->waiting_jobs->insert_before(item, li); Dmsg2(2300, "insert_before jobid=%d before waiting job=%d\n", - li->jcr->JobId, jcr->JobId); - inserted = true; - break; - } + li->jcr->JobId, jcr->JobId); + inserted = true; + break; + } } /* If not jobs in wait queue, append it */ if (!inserted) { - jq->waiting_jobs->append(item); + jq->waiting_jobs->append(item); Dmsg1(2300, "Appended item jobid=%d to waiting queue\n", jcr->JobId); } } @@ -311,8 +311,8 @@ int jobq_remove(jobq_t *jq, JCR *jcr) foreach_dlist(item, jq->waiting_jobs) { if (jcr == item->jcr) { - found = true; - break; + found = true; + break; } } if (!found) { @@ -342,22 +342,26 @@ static int start_server(jobq_t *jq) int stat = 0; pthread_t id; - /* if any threads are idle, wake one */ + /* + * if any threads are idle, wake one -- + * actually we do a broadcast because on /lib/tls + * these signals seem to get lost from time to time. + */ if (jq->idle_workers > 0) { Dmsg0(2300, "Signal worker to wake up\n"); - if ((stat = pthread_cond_signal(&jq->work)) != 0) { - berrno be; + if ((stat = pthread_cond_broadcast(&jq->work)) != 0) { + berrno be; Jmsg1(NULL, M_ERROR, 0, "pthread_cond_signal: ERR=%s\n", be.strerror(stat)); - return stat; + return stat; } } else if (jq->num_workers < jq->max_workers) { Dmsg0(2300, "Create worker thread\n"); /* No idle threads so create a new one */ set_thread_concurrency(jq->max_workers + 1); if ((stat = pthread_create(&id, &jq->attr, jobq_server, (void *)jq)) != 0) { - berrno be; + berrno be; Jmsg1(NULL, M_ERROR, 0, "pthread_create: ERR=%s\n", be.strerror(stat)); - return stat; + return stat; } } return stat; @@ -374,7 +378,7 @@ void *jobq_server(void *arg) { struct timespec timeout; jobq_t *jq = (jobq_t *)arg; - jobq_item_t *je; /* job entry in queue */ + jobq_item_t *je; /* job entry in queue */ int stat; bool timedout = false; bool work = true; @@ -393,138 +397,138 @@ void *jobq_server(void *arg) Dmsg0(2300, "Top of for loop\n"); if (!work && !jq->quit) { - gettimeofday(&tv, &tz); - timeout.tv_nsec = 0; - timeout.tv_sec = tv.tv_sec + 4; - - while (!jq->quit) { - /* - * Wait 4 seconds, then if no more work, exit - */ + gettimeofday(&tv, &tz); + timeout.tv_nsec = 0; + timeout.tv_sec = tv.tv_sec + 4; + + while (!jq->quit) { + /* + * Wait 4 seconds, then if no more work, exit + */ Dmsg0(2300, "pthread_cond_timedwait()\n"); - stat = pthread_cond_timedwait(&jq->work, &jq->mutex, &timeout); - if (stat == ETIMEDOUT) { + stat = pthread_cond_timedwait(&jq->work, &jq->mutex, &timeout); + if (stat == ETIMEDOUT) { Dmsg0(2300, "timedwait timedout.\n"); - timedout = true; - break; - } else if (stat != 0) { + timedout = true; + break; + } else if (stat != 0) { /* This shouldn't happen */ Dmsg0(2300, "This shouldn't happen\n"); - jq->num_workers--; - pthread_mutex_unlock(&jq->mutex); - return NULL; - } - break; - } + jq->num_workers--; + pthread_mutex_unlock(&jq->mutex); + return NULL; + } + break; + } } /* * If anything is in the ready queue, run it */ Dmsg0(2300, "Checking ready queue.\n"); while (!jq->ready_jobs->empty() && !jq->quit) { - JCR *jcr; - je = (jobq_item_t *)jq->ready_jobs->first(); - jcr = je->jcr; - jq->ready_jobs->remove(je); - if (!jq->ready_jobs->empty()) { + JCR *jcr; + je = (jobq_item_t *)jq->ready_jobs->first(); + jcr = je->jcr; + jq->ready_jobs->remove(je); + if (!jq->ready_jobs->empty()) { Dmsg0(2300, "ready queue not empty start server\n"); - if (start_server(jq) != 0) { - jq->num_workers--; - pthread_mutex_unlock(&jq->mutex); - return NULL; - } - } - jq->running_jobs->append(je); + if (start_server(jq) != 0) { + jq->num_workers--; + pthread_mutex_unlock(&jq->mutex); + return NULL; + } + } + jq->running_jobs->append(je); Dmsg1(2300, "Took jobid=%d from ready and appended to run\n", jcr->JobId); - /* Release job queue lock */ - V(jq->mutex); + /* Release job queue lock */ + V(jq->mutex); /* Call user's routine here */ Dmsg1(2300, "Calling user engine for jobid=%d\n", jcr->JobId); - jq->engine(je->jcr); + jq->engine(je->jcr); Dmsg1(2300, "Back from user engine jobid=%d.\n", jcr->JobId); - /* Reacquire job queue lock */ - P(jq->mutex); + /* Reacquire job queue lock */ + P(jq->mutex); Dmsg0(200, "Done lock mutex after running job. Release locks.\n"); - jq->running_jobs->remove(je); - /* - * Release locks if acquired. Note, they will not have - * been acquired for jobs canceled before they were - * put into the ready queue. - */ - if (jcr->acquired_resource_locks) { - jcr->store->NumConcurrentJobs--; - jcr->client->NumConcurrentJobs--; - jcr->job->NumConcurrentJobs--; - } - - /* - * Reschedule the job if necessary and requested - */ - if (jcr->job->RescheduleOnError && - jcr->JobStatus != JS_Terminated && - jcr->JobStatus != JS_Canceled && - jcr->job->RescheduleTimes > 0 && - jcr->reschedule_count < jcr->job->RescheduleTimes) { - char dt[50]; - - /* - * Reschedule this job by cleaning it up, but - * reuse the same JobId if possible. - */ - jcr->reschedule_count++; - jcr->sched_time = time(NULL) + jcr->job->RescheduleInterval; + jq->running_jobs->remove(je); + /* + * Release locks if acquired. Note, they will not have + * been acquired for jobs canceled before they were + * put into the ready queue. + */ + if (jcr->acquired_resource_locks) { + jcr->store->NumConcurrentJobs--; + jcr->client->NumConcurrentJobs--; + jcr->job->NumConcurrentJobs--; + } + + /* + * Reschedule the job if necessary and requested + */ + if (jcr->job->RescheduleOnError && + jcr->JobStatus != JS_Terminated && + jcr->JobStatus != JS_Canceled && + jcr->job->RescheduleTimes > 0 && + jcr->reschedule_count < jcr->job->RescheduleTimes) { + char dt[50]; + + /* + * Reschedule this job by cleaning it up, but + * reuse the same JobId if possible. + */ + jcr->reschedule_count++; + jcr->sched_time = time(NULL) + jcr->job->RescheduleInterval; Dmsg2(2300, "Rescheduled Job %s to re-run in %d seconds.\n", jcr->Job, - (int)jcr->job->RescheduleInterval); - bstrftime(dt, sizeof(dt), time(NULL)); + (int)jcr->job->RescheduleInterval); + bstrftime(dt, sizeof(dt), time(NULL)); Jmsg(jcr, M_INFO, 0, _("Rescheduled Job %s at %s to re-run in %d seconds.\n"), - jcr->Job, dt, (int)jcr->job->RescheduleInterval); - dird_free_jcr_pointers(jcr); /* partial cleanup old stuff */ - jcr->JobStatus = JS_WaitStartTime; - jcr->SDJobStatus = 0; - if (jcr->JobBytes == 0) { + jcr->Job, dt, (int)jcr->job->RescheduleInterval); + dird_free_jcr_pointers(jcr); /* partial cleanup old stuff */ + jcr->JobStatus = JS_WaitStartTime; + jcr->SDJobStatus = 0; + if (jcr->JobBytes == 0) { Dmsg1(2300, "Requeue job=%d\n", jcr->JobId); - jcr->JobStatus = JS_WaitStartTime; - V(jq->mutex); - jobq_add(jq, jcr); /* queue the job to run again */ - P(jq->mutex); - free(je); /* free the job entry */ - continue; /* look for another job to run */ - } - /* - * Something was actually backed up, so we cannot reuse - * the old JobId or there will be database record - * conflicts. We now create a new job, copying the - * appropriate fields. - */ - JCR *njcr = new_jcr(sizeof(JCR), dird_free_jcr); - set_jcr_defaults(njcr, jcr->job); - njcr->reschedule_count = jcr->reschedule_count; - njcr->JobLevel = jcr->JobLevel; - njcr->JobStatus = jcr->JobStatus; - copy_storage(njcr, jcr); - njcr->messages = jcr->messages; + jcr->JobStatus = JS_WaitStartTime; + V(jq->mutex); + jobq_add(jq, jcr); /* queue the job to run again */ + P(jq->mutex); + free(je); /* free the job entry */ + continue; /* look for another job to run */ + } + /* + * Something was actually backed up, so we cannot reuse + * the old JobId or there will be database record + * conflicts. We now create a new job, copying the + * appropriate fields. + */ + JCR *njcr = new_jcr(sizeof(JCR), dird_free_jcr); + set_jcr_defaults(njcr, jcr->job); + njcr->reschedule_count = jcr->reschedule_count; + njcr->JobLevel = jcr->JobLevel; + njcr->JobStatus = jcr->JobStatus; + copy_storage(njcr, jcr); + njcr->messages = jcr->messages; Dmsg0(2300, "Call to run new job\n"); - V(jq->mutex); + V(jq->mutex); run_job(njcr); /* This creates a "new" job */ free_jcr(njcr); /* release "new" jcr */ - P(jq->mutex); + P(jq->mutex); Dmsg0(2300, "Back from running new job.\n"); - } - /* Clean up and release old jcr */ - if (jcr->db) { - db_close_database(jcr, jcr->db); - jcr->db = NULL; - } + } + /* Clean up and release old jcr */ + if (jcr->db) { + db_close_database(jcr, jcr->db); + jcr->db = NULL; + } Dmsg2(2300, "====== Termination job=%d use_cnt=%d\n", jcr->JobId, jcr->use_count); - jcr->SDJobStatus = 0; - V(jq->mutex); /* release internal lock */ - free_jcr(jcr); - free(je); /* release job entry */ - P(jq->mutex); /* reacquire job queue lock */ + jcr->SDJobStatus = 0; + V(jq->mutex); /* release internal lock */ + free_jcr(jcr); + free(je); /* release job entry */ + P(jq->mutex); /* reacquire job queue lock */ } /* * If any job in the wait queue can be run, @@ -532,48 +536,48 @@ void *jobq_server(void *arg) */ Dmsg0(2300, "Done check ready, now check wait queue.\n"); if (!jq->waiting_jobs->empty() && !jq->quit) { - int Priority; - je = (jobq_item_t *)jq->waiting_jobs->first(); - jobq_item_t *re = (jobq_item_t *)jq->running_jobs->first(); - if (re) { - Priority = re->jcr->JobPriority; + int Priority; + je = (jobq_item_t *)jq->waiting_jobs->first(); + jobq_item_t *re = (jobq_item_t *)jq->running_jobs->first(); + if (re) { + Priority = re->jcr->JobPriority; Dmsg2(2300, "JobId %d is running. Look for pri=%d\n", re->jcr->JobId, Priority); - } else { - Priority = je->jcr->JobPriority; + } else { + Priority = je->jcr->JobPriority; Dmsg1(2300, "No job running. Look for Job pri=%d\n", Priority); - } - /* - * Walk down the list of waiting jobs and attempt - * to acquire the resources it needs. - */ - for ( ; je; ) { - /* je is current job item on the queue, jn is the next one */ - JCR *jcr = je->jcr; - jobq_item_t *jn = (jobq_item_t *)jq->waiting_jobs->next(je); + } + /* + * Walk down the list of waiting jobs and attempt + * to acquire the resources it needs. + */ + for ( ; je; ) { + /* je is current job item on the queue, jn is the next one */ + JCR *jcr = je->jcr; + jobq_item_t *jn = (jobq_item_t *)jq->waiting_jobs->next(je); Dmsg3(2300, "Examining Job=%d JobPri=%d want Pri=%d\n", - jcr->JobId, jcr->JobPriority, Priority); - - /* Take only jobs of correct Priority */ - if (jcr->JobPriority != Priority) { - set_jcr_job_status(jcr, JS_WaitPriority); - break; - } - - if (!acquire_resources(jcr)) { - je = jn; /* point to next waiting job */ - continue; - } - - /* Got all locks, now remove it from wait queue and append it - * to the ready queue - */ - jcr->acquired_resource_locks = true; - jq->waiting_jobs->remove(je); - jq->ready_jobs->append(je); + jcr->JobId, jcr->JobPriority, Priority); + + /* Take only jobs of correct Priority */ + if (jcr->JobPriority != Priority) { + set_jcr_job_status(jcr, JS_WaitPriority); + break; + } + + if (!acquire_resources(jcr)) { + je = jn; /* point to next waiting job */ + continue; + } + + /* Got all locks, now remove it from wait queue and append it + * to the ready queue + */ + jcr->acquired_resource_locks = true; + jq->waiting_jobs->remove(je); + jq->ready_jobs->append(je); Dmsg1(2300, "moved JobId=%d from wait to ready queue\n", je->jcr->JobId); - je = jn; /* Point to next waiting job */ - } /* end for loop */ + je = jn; /* Point to next waiting job */ + } /* end for loop */ } /* end if */ @@ -582,39 +586,39 @@ void *jobq_server(void *arg) * If no more ready work and we are asked to quit, then do it */ if (jq->ready_jobs->empty() && jq->quit) { - jq->num_workers--; - if (jq->num_workers == 0) { + jq->num_workers--; + if (jq->num_workers == 0) { Dmsg0(2300, "Wake up destroy routine\n"); - /* Wake up destroy routine if he is waiting */ - pthread_cond_broadcast(&jq->work); - } - break; + /* Wake up destroy routine if he is waiting */ + pthread_cond_broadcast(&jq->work); + } + break; } Dmsg0(2300, "Check for work request\n"); /* * If no more work requests, and we waited long enough, quit */ Dmsg2(2300, "timedout=%d read empty=%d\n", timedout, - jq->ready_jobs->empty()); + jq->ready_jobs->empty()); if (jq->ready_jobs->empty() && timedout) { Dmsg0(2300, "break big loop\n"); - jq->num_workers--; - break; + jq->num_workers--; + break; } work = !jq->ready_jobs->empty() || !jq->waiting_jobs->empty(); if (work) { - /* + /* * If a job is waiting on a Resource, don't consume all - * the CPU time looping looking for work, and even more - * important, release the lock so that a job that has - * terminated can give us the resource. - */ - V(jq->mutex); - bmicrosleep(2, 0); /* pause for 2 seconds */ - P(jq->mutex); - /* Recompute work as something may have changed in last 2 secs */ - work = !jq->ready_jobs->empty() || !jq->waiting_jobs->empty(); + * the CPU time looping looking for work, and even more + * important, release the lock so that a job that has + * terminated can give us the resource. + */ + V(jq->mutex); + bmicrosleep(2, 0); /* pause for 2 seconds */ + P(jq->mutex); + /* Recompute work as something may have changed in last 2 secs */ + work = !jq->ready_jobs->empty() || !jq->waiting_jobs->empty(); } Dmsg1(2300, "Loop again. work=%d\n", work); } /* end of big for loop */ @@ -629,7 +633,7 @@ void *jobq_server(void *arg) * See if we can acquire all the necessary resources for the job (JCR) * * Returns: true if successful - * false if resource failure + * false if resource failure */ static bool acquire_resources(JCR *jcr) { @@ -641,14 +645,14 @@ static bool acquire_resources(JCR *jcr) * of MaxConcurrentJobs. */ if (jcr->store->NumConcurrentJobs == 0) { - jcr->store->NumConcurrentJobs = 1; + jcr->store->NumConcurrentJobs = 1; } else { - set_jcr_job_status(jcr, JS_WaitStoreRes); - return false; + set_jcr_job_status(jcr, JS_WaitStoreRes); + return false; } /* We are not doing a Restore or Verify */ } else if (jcr->store->NumConcurrentJobs == 0 && - jcr->store->NumConcurrentJobs < jcr->store->MaxConcurrentJobs) { + jcr->store->NumConcurrentJobs < jcr->store->MaxConcurrentJobs) { /* Simple case, first job */ jcr->store->NumConcurrentJobs = 1; } else if (jcr->store->NumConcurrentJobs < jcr->store->MaxConcurrentJobs) { diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index cd00b7170a..3215f71742 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -42,7 +42,7 @@ static char jobcmd[] = "JobId=%d job=%s job_name=%s client_name=%s " "type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s " "SpoolData=%d WritePartAfterJob=%d NewVol=%d\n"; -static char use_storage[] = "use storage media_type=%s pool_name=%s " +static char use_storage[] = "use storage=%s media_type=%s pool_name=%s " "pool_type=%s append=%d\n"; static char use_device[] = "use device=%s\n"; //static char query_device[] = "query device=%s"; @@ -130,7 +130,7 @@ int start_storage_daemon_job(JCR *jcr, alist *store, int append) STORE *storage; BSOCK *sd; char auth_key[100]; - POOL_MEM device_name, pool_name, pool_type, media_type; + POOL_MEM store_name, device_name, pool_name, pool_type, media_type; char PoolId[50]; sd = jcr->store_bsock; @@ -187,10 +187,12 @@ int start_storage_daemon_job(JCR *jcr, alist *store, int append) */ // foreach_alist(storage, store) { storage = (STORE *)store->first(); + pm_strcpy(store_name, storage->hdr.name); + bash_spaces(store_name); pm_strcpy(media_type, storage->media_type); bash_spaces(media_type); - bnet_fsend(sd, use_storage, media_type.c_str(), pool_name.c_str(), - pool_type.c_str(), append); + bnet_fsend(sd, use_storage, store_name.c_str(), media_type.c_str(), + pool_name.c_str(), pool_type.c_str(), append); DEVICE *dev; /* Loop over alternative storage Devices until one is OK */ diff --git a/bacula/src/dird/newvol.c b/bacula/src/dird/newvol.c index 831cd93ad3..7038aae3a7 100644 --- a/bacula/src/dird/newvol.c +++ b/bacula/src/dird/newvol.c @@ -36,12 +36,15 @@ #include "dird.h" /* Forward referenced functions */ -static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr); -static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr); +static bool create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr); +static bool perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr); /* * Automatic Volume name creation using the LabelFormat + * + * The media record must have the PoolId filled in when + * calling this routine. */ bool newVolume(JCR *jcr, MEDIA_DBR *mr) { @@ -51,18 +54,21 @@ bool newVolume(JCR *jcr, MEDIA_DBR *mr) /* See if we can create a new Volume */ db_lock(jcr->db); - pr.PoolId = jcr->PoolId; - if (db_get_pool_record(jcr, jcr->db, &pr) && pr.LabelFormat[0] && - pr.LabelFormat[0] != '*') { - if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) { - memset(mr, 0, sizeof(MEDIA_DBR)); - set_pool_dbr_defaults_in_media_dbr(mr, &pr); - jcr->VolumeName[0] = 0; - bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType)); - if (generate_event(jcr, "NewVolume") == 1 && jcr->VolumeName[0]) { - bstrncpy(mr->VolumeName, jcr->VolumeName, sizeof(mr->VolumeName)); - /* Check for special characters */ - } else if (is_volume_name_legal(NULL, pr.LabelFormat)) { + pr.PoolId = mr->PoolId; + if (!db_get_pool_record(jcr, jcr->db, &pr)) { + goto bail_out; + } + if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) { + memset(mr, 0, sizeof(MEDIA_DBR)); + set_pool_dbr_defaults_in_media_dbr(mr, &pr); + jcr->VolumeName[0] = 0; + bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType)); + if (generate_event(jcr, "NewVolume") == 1 && jcr->VolumeName[0] && + is_volume_name_legal(NULL, jcr->VolumeName)) { + bstrncpy(mr->VolumeName, jcr->VolumeName, sizeof(mr->VolumeName)); + /* Check for special characters */ + } else if (pr.LabelFormat[0] && pr.LabelFormat[0] != '*') { + if (is_volume_name_legal(NULL, pr.LabelFormat)) { /* No special characters, so apply simple algorithm */ if (!create_simple_name(jcr, mr, &pr)) { goto bail_out; @@ -78,16 +84,16 @@ bool newVolume(JCR *jcr, MEDIA_DBR *mr) goto bail_out; } } - pr.NumVols++; - if (db_create_media_record(jcr, jcr->db, mr) && - db_update_pool_record(jcr, jcr->db, &pr)) { - db_unlock(jcr->db); - Jmsg(jcr, M_INFO, 0, _("Created new Volume \"%s\" in catalog.\n"), mr->VolumeName); - Dmsg1(90, "Created new Volume=%s\n", mr->VolumeName); - return true; - } else { - Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); - } + } + pr.NumVols++; + if (db_create_media_record(jcr, jcr->db, mr) && + db_update_pool_record(jcr, jcr->db, &pr)) { + db_unlock(jcr->db); + Jmsg(jcr, M_INFO, 0, _("Created new Volume \"%s\" in catalog.\n"), mr->VolumeName); + Dmsg1(90, "Created new Volume=%s\n", mr->VolumeName); + return true; + } else { + Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); } } bail_out: @@ -95,7 +101,7 @@ bail_out: return false; } -static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) +static bool create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) { char name[MAXSTRING]; char num[20]; @@ -121,23 +127,23 @@ static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) } if (mr->VolumeName[0] == 0) { Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n")); - return 0; + return false; } - return 1; + return true; } /* * Perform full substitution on Label */ -static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) +static bool perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) { - int stat = 0; + bool ok = false; POOLMEM *label = get_pool_memory(PM_FNAME); jcr->NumVols = pr->NumVols; if (variable_expansion(jcr, pr->LabelFormat, &label)) { bstrncpy(mr->VolumeName, label, sizeof(mr->VolumeName)); - stat = 1; + ok = true; } free_pool_memory(label); - return stat; + return ok; } diff --git a/bacula/src/dird/next_vol.c b/bacula/src/dird/next_vol.c index ccf37a4bfc..7db844bbea 100644 --- a/bacula/src/dird/next_vol.c +++ b/bacula/src/dird/next_vol.c @@ -107,7 +107,7 @@ int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, bool create) * 6. Try pulling a volume from the Scratch pool */ memset(&pr, 0, sizeof(pr)); - bstrncpy(pr.Name, "Scratch", 7); + bstrncpy(pr.Name, "Scratch", sizeof(pr.Name)); if (db_get_pool_record(jcr, jcr->db, &pr)) { memset(&smr, 0, sizeof(smr)); smr.PoolId = pr.PoolId; diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index af30220093..3d889fe340 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -421,7 +421,6 @@ static bool list_nextvol(UAContext *ua) MEDIA_DBR mr; memset(&mr, 0, sizeof(mr)); - mr.PoolId = jcr->PoolId; int i = find_arg_with_value(ua, "job"); if (i <= 0) { if ((job = select_job_resource(ua)) == NULL) { @@ -437,11 +436,14 @@ static bool list_nextvol(UAContext *ua) } } for (run=NULL; (run = find_next_run(run, job, runtime)); ) { - pool = run ? run->pool : NULL; + pool = run->pool ? run->pool : NULL; if (!complete_jcr_for_job(jcr, job, pool)) { return false; } - + mr.PoolId = jcr->PoolId; + if (run->storage) { + jcr->store = run->storage; + } if (!find_next_volume_for_append(jcr, &mr, 0)) { bsendmsg(ua, _("Could not find next Volume.\n")); } else { diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 5cd149e200..8b02aeaf48 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -8,7 +8,7 @@ */ /* - Copyright (C) 2001-20054 Kern Sibbald + Copyright (C) 2001-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -118,7 +118,7 @@ int run_cmd(UAContext *ua, const char *cmd) bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]); return 1; } - Dmsg1(800, "Got keyword=%s\n", kw[j]); + Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j])); switch (j) { case 0: /* job */ if (job_name) { @@ -287,7 +287,7 @@ int run_cmd(UAContext *ua, const char *cmd) return 0; } } - Dmsg1(800, "Using catalog=%s\n", catalog_name); + Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name)); if (job_name) { /* Find Job */ diff --git a/bacula/src/dird/ua_status.c b/bacula/src/dird/ua_status.c index 3c6c372ea5..9e97944a2c 100644 --- a/bacula/src/dird/ua_status.c +++ b/bacula/src/dird/ua_status.c @@ -371,8 +371,8 @@ static void prt_runtime(UAContext *ua, sched_pkt *sp) bool close_db = false; JCR *jcr = ua->jcr; MEDIA_DBR mr; + memset(&mr, 0, sizeof(mr)); - mr.PoolId = jcr->PoolId; if (sp->job->JobType == JT_BACKUP) { jcr->db = NULL; ok = complete_jcr_for_job(jcr, sp->job, sp->pool); @@ -380,6 +380,7 @@ static void prt_runtime(UAContext *ua, sched_pkt *sp) close_db = true; /* new db opened, remember to close it */ } if (ok) { + mr.PoolId = jcr->PoolId; ok = find_next_volume_for_append(jcr, &mr, 0); } if (!ok) { diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 56ee2afbe3..a228d29e92 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -282,8 +282,10 @@ void *handle_client_request(void *dirp) fileset->exclude_list.destroy(); free(fileset); } + ff->fileset = NULL; Dmsg0(100, "Calling term_find_files\n"); term_find_files((FF_PKT *)jcr->ff); + jcr->ff = NULL; Dmsg0(100, "Done with term_find_files\n"); free_jcr(jcr); /* destroy JCR record */ Dmsg0(100, "Done with free_jcr\n"); diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index eff2a1a945..f1bc25f0a1 100755 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -557,5 +557,6 @@ int term_find_one(FF_PKT *ff) count++; } } + ff->linklist = NULL; return count; } diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index fa6349e9bb..9aa98beb0d 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -39,7 +39,7 @@ LIBSRCS = alloc.c attr.c base64.c berrno.c bsys.c bget_msg.c \ cram-md5.c crc32.c daemon.c edit.c fnmatch.c \ hmac.c idcache.c jcr.c lex.c alist.c dlist.c \ md5.c message.c mem_pool.c parse_conf.c \ - queue.c rwlock.c scan.c serial.c sha1.c \ + queue.c res.c rwlock.c scan.c serial.c sha1.c \ semlock.c signal.c smartall.c tree.c \ util.c var.c watchdog.c workq.c btimers.c \ address_conf.c python.c @@ -51,7 +51,7 @@ LIBOBJS = alloc.o attr.o base64.o berrno.o bsys.o bget_msg.o \ cram-md5.o crc32.o daemon.o edit.o fnmatch.o \ hmac.o idcache.o jcr.o lex.o alist.o dlist.o \ md5.o message.o mem_pool.o parse_conf.o \ - queue.o rwlock.o scan.o serial.o sha1.o \ + queue.o res.o rwlock.o scan.o serial.o sha1.o \ semlock.o signal.o smartall.o tree.o \ util.o var.o watchdog.o workq.o btimers.o \ address_conf.o python.o diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index d5dc130815..ae9fe194fa 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -77,9 +77,8 @@ extern CURES res_all; extern int res_all_size; #endif +extern brwlock_t res_lock; /* resource lock */ -static brwlock_t res_lock; /* resource lock */ -static int res_locked = 0; /* set when resource chains locked -- for debug */ /* Forward referenced subroutines */ static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd); @@ -727,82 +726,6 @@ void store_label(LEX *lc, RES_ITEM *item, int index, int pass) } -/* #define TRACE_RES */ - -void b_LockRes(const char *file, int line) -{ - int errstat; -#ifdef TRACE_RES - Pmsg4(000, "LockRes %d,%d at %s:%d\n", res_locked, res_lock.w_active, - file, line); -#endif - if ((errstat=rwl_writelock(&res_lock)) != 0) { - Emsg3(M_ABORT, 0, "rwl_writelock failure at %s:%d: ERR=%s\n", - file, line, strerror(errstat)); - } - res_locked++; -} - -void b_UnlockRes(const char *file, int line) -{ - int errstat; - res_locked--; -#ifdef TRACE_RES - Pmsg4(000, "UnLockRes %d,%d at %s:%d\n", res_locked, res_lock.w_active, - file, line); -#endif - if ((errstat=rwl_writeunlock(&res_lock)) != 0) { - Emsg3(M_ABORT, 0, "rwl_writeunlock failure at %s:%d:. ERR=%s\n", - file, line, strerror(errstat)); - } -} - -/* - * Return resource of type rcode that matches name - */ -RES * -GetResWithName(int rcode, char *name) -{ - RES *res; - int rindex = rcode - r_first; - - LockRes(); - res = res_head[rindex]; - while (res) { - if (strcmp(res->name, name) == 0) { - break; - } - res = res->next; - } - UnlockRes(); - return res; - -} - -/* - * Return next resource of type rcode. On first - * call second arg (res) is NULL, on subsequent - * calls, it is called with previous value. - */ -RES * -GetNextRes(int rcode, RES *res) -{ - RES *nres; - int rindex = rcode - r_first; - - - if (!res_locked) { - Emsg0(M_ABORT, 0, "Resource chain not locked.\n"); - } - if (res == NULL) { - nres = res_head[rindex]; - } else { - nres = res->next; - } - return nres; -} - - /* Parser state */ enum parse_state { p_none, diff --git a/bacula/src/lib/python.c b/bacula/src/lib/python.c index aaf71faf8f..884bbe79c3 100644 --- a/bacula/src/lib/python.c +++ b/bacula/src/lib/python.c @@ -9,7 +9,7 @@ */ /* - Copyright (C) 2004 Kern Sibbald + Copyright (C) 2004-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -33,6 +33,7 @@ EVENT_HANDLER *generate_event; #ifdef HAVE_PYTHON + #undef _POSIX_C_SOURCE #include @@ -54,7 +55,7 @@ void init_python_interpreter(const char *progname, const char *scripts) PyEval_InitThreads(); Py_InitModule("bacula", BaculaMethods); bsnprintf(buf, sizeof(buf), "import sys\n" - "sys.path.append('%s')\n", scripts); + "sys.path.append('%s')\n", scripts); PyRun_SimpleString(buf); PyEval_ReleaseLock(); generate_event = _generate_event; @@ -78,7 +79,8 @@ int _generate_event(JCR *jcr, const char *event) { PyObject *pName, *pModule, *pDict, *pFunc; PyObject *pArgs, *pValue; - + + Dmsg1(100, "Generate event %s\n", event); pName = PyString_FromString(event); if (!pName) { Jmsg(jcr, M_ERROR, 0, "Could not convert \"%s\" to Python string.\n", event); @@ -102,7 +104,7 @@ int _generate_event(JCR *jcr, const char *event) if (!pValue) { Py_DECREF(pArgs); Py_DECREF(pModule); - Jmsg(jcr, M_ERROR, 0, "Could not convert JCR to Python CObject.\n"); + Jmsg(jcr, M_ERROR, 0, "Could not convert JCR to Python CObject.\n"); return -1; /* Could not convert JCR to CObject */ } /* pValue reference stolen here: */ @@ -116,7 +118,7 @@ int _generate_event(JCR *jcr, const char *event) } else { Py_DECREF(pModule); PyErr_Print(); - Jmsg(jcr, M_ERROR, 0, "Error running Python module: %s\n", event); + Jmsg(jcr, M_ERROR, 0, "Error running Python module: %s\n", event); return 0; /* error running function */ } /* pDict and pFunc are borrowed and must not be Py_DECREF-ed */ @@ -124,13 +126,14 @@ int _generate_event(JCR *jcr, const char *event) if (PyErr_Occurred()) { PyErr_Print(); } - Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found in module.\n", event); + Jmsg(jcr, M_ERROR, 0, "Python function \"%s\" not found in module.\n", event); return -1; /* function not found */ } Py_DECREF(pModule); } else { return 0; /* Module not present */ } + Dmsg0(100, "Generate event OK\n"); return 1; } diff --git a/bacula/src/lib/res.c b/bacula/src/lib/res.c new file mode 100644 index 0000000000..04dab6bfe7 --- /dev/null +++ b/bacula/src/lib/res.c @@ -0,0 +1,144 @@ +/* + * This file handles locking and seaching resources + * + * Kern Sibbald, January MM + * Split from parse_conf.c April MMV + * + * Version $Id$ + */ + +/* + Copyright (C) 2000-2005 Kern Sibbald + + 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. + + 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. + + 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. + + */ + + +#include "bacula.h" + +extern int debug_level; + +/* Each daemon has a slightly different set of + * resources, so it will define the following + * global values. + */ +extern int r_first; +extern int r_last; +extern RES_TABLE resources[]; +extern RES **res_head; + +#ifdef HAVE_WIN32 +// work around visual studio name manling preventing external linkage since res_all +// is declared as a different type when instantiated. +extern "C" CURES res_all; +extern "C" int res_all_size; +#else +extern CURES res_all; +extern int res_all_size; +#endif + + +brwlock_t res_lock; /* resource lock */ +static int res_locked = 0; /* set when resource chains locked -- for debug */ + + + +/* #define TRACE_RES */ + +void b_LockRes(const char *file, int line) +{ + int errstat; +#ifdef TRACE_RES + Pmsg4(000, "LockRes locked=%d w_active=%d at %s:%d\n", + res_locked, res_lock.w_active, file, line); + if (res_locked) { + Pmsg2(000, "LockRes writerid=%d myid=%d\n", res_lock.writer_id, + pthread_self()); + } +#endif + if ((errstat=rwl_writelock(&res_lock)) != 0) { + Emsg3(M_ABORT, 0, "rwl_writelock failure at %s:%d: ERR=%s\n", + file, line, strerror(errstat)); + } + res_locked++; +} + +void b_UnlockRes(const char *file, int line) +{ + int errstat; + if ((errstat=rwl_writeunlock(&res_lock)) != 0) { + Emsg3(M_ABORT, 0, "rwl_writeunlock failure at %s:%d:. ERR=%s\n", + file, line, strerror(errstat)); + } + res_locked--; +#ifdef TRACE_RES + Pmsg4(000, "UnLockRes locked=%d wactive=%d at %s:%d\n", + res_locked, res_lock.w_active, file, line); +#endif +} + +/* + * Return resource of type rcode that matches name + */ +RES * +GetResWithName(int rcode, char *name) +{ + RES *res; + int rindex = rcode - r_first; + + LockRes(); + res = res_head[rindex]; + while (res) { + if (strcmp(res->name, name) == 0) { + break; + } + res = res->next; + } + UnlockRes(); + return res; + +} + +/* + * Return next resource of type rcode. On first + * call second arg (res) is NULL, on subsequent + * calls, it is called with previous value. + */ +RES * +GetNextRes(int rcode, RES *res) +{ + RES *nres; + int rindex = rcode - r_first; + + +// if (!res_locked) { +// Emsg0(M_ABORT, 0, "Resource chain not locked.\n"); +// } + if (res == NULL) { + nres = res_head[rindex]; + } else { + nres = res->next; + } + return nres; +} + + +/* Parser state */ +enum parse_state { + p_none, + p_resource +}; diff --git a/bacula/src/lib/rwlock.c b/bacula/src/lib/rwlock.c index 0b9b352f72..16ce457fb0 100644 --- a/bacula/src/lib/rwlock.c +++ b/bacula/src/lib/rwlock.c @@ -38,7 +38,7 @@ * Initialize a read/write lock * * Returns: 0 on success - * errno on failure + * errno on failure */ int rwl_init(brwlock_t *rwl) { @@ -66,7 +66,7 @@ int rwl_init(brwlock_t *rwl) * Destroy a read/write lock * * Returns: 0 on success - * errno on failure + * errno on failure */ int rwl_destroy(brwlock_t *rwl) { @@ -99,7 +99,7 @@ int rwl_destroy(brwlock_t *rwl) if ((stat = pthread_mutex_unlock(&rwl->mutex)) != 0) { return stat; } - stat = pthread_mutex_destroy(&rwl->mutex); + stat = pthread_mutex_destroy(&rwl->mutex); stat1 = pthread_cond_destroy(&rwl->read); stat2 = pthread_cond_destroy(&rwl->write); return (stat != 0 ? stat : (stat1 != 0 ? stat1 : stat2)); @@ -143,19 +143,19 @@ int rwl_readlock(brwlock_t *rwl) return stat; } if (rwl->w_active) { - rwl->r_wait++; /* indicate that we are waiting */ + rwl->r_wait++; /* indicate that we are waiting */ pthread_cleanup_push(rwl_read_release, (void *)rwl); while (rwl->w_active) { - stat = pthread_cond_wait(&rwl->read, &rwl->mutex); - if (stat != 0) { - break; /* error, bail out */ - } + stat = pthread_cond_wait(&rwl->read, &rwl->mutex); + if (stat != 0) { + break; /* error, bail out */ + } } pthread_cleanup_pop(0); - rwl->r_wait--; /* we are no longer waiting */ + rwl->r_wait--; /* we are no longer waiting */ } if (stat == 0) { - rwl->r_active++; /* we are running */ + rwl->r_active++; /* we are running */ } pthread_mutex_unlock(&rwl->mutex); return stat; @@ -177,7 +177,7 @@ int rwl_readtrylock(brwlock_t *rwl) if (rwl->w_active) { stat = EBUSY; } else { - rwl->r_active++; /* we are running */ + rwl->r_active++; /* we are running */ } stat2 = pthread_mutex_unlock(&rwl->mutex); return (stat == 0 ? stat2 : stat); @@ -198,7 +198,7 @@ int rwl_readunlock(brwlock_t *rwl) } rwl->r_active--; if (rwl->r_active == 0 && rwl->w_wait > 0) { /* if writers waiting */ - stat = pthread_cond_signal(&rwl->write); + stat = pthread_cond_broadcast(&rwl->write); } stat2 = pthread_mutex_unlock(&rwl->mutex); return (stat == 0 ? stat2 : stat); @@ -225,18 +225,18 @@ int rwl_writelock(brwlock_t *rwl) return 0; } if (rwl->w_active || rwl->r_active > 0) { - rwl->w_wait++; /* indicate that we are waiting */ + rwl->w_wait++; /* indicate that we are waiting */ pthread_cleanup_push(rwl_write_release, (void *)rwl); while (rwl->w_active || rwl->r_active > 0) { - if ((stat = pthread_cond_wait(&rwl->write, &rwl->mutex)) != 0) { - break; /* error, bail out */ - } + if ((stat = pthread_cond_wait(&rwl->write, &rwl->mutex)) != 0) { + break; /* error, bail out */ + } } pthread_cleanup_pop(0); - rwl->w_wait--; /* we are no longer waiting */ + rwl->w_wait--; /* we are no longer waiting */ } if (stat == 0) { - rwl->w_active++; /* we are running */ + rwl->w_active++; /* we are running */ rwl->writer_id = pthread_self(); /* save writer thread's id */ } pthread_mutex_unlock(&rwl->mutex); @@ -264,7 +264,7 @@ int rwl_writetrylock(brwlock_t *rwl) if (rwl->w_active || rwl->r_active > 0) { stat = EBUSY; } else { - rwl->w_active = 1; /* we are running */ + rwl->w_active = 1; /* we are running */ rwl->writer_id = pthread_self(); /* save writer thread's id */ } stat2 = pthread_mutex_unlock(&rwl->mutex); @@ -293,13 +293,13 @@ int rwl_writeunlock(brwlock_t *rwl) Emsg0(M_ABORT, 0, "rwl_writeunlock by non-owner.\n"); } if (rwl->w_active > 0) { - stat = 0; /* writers still active */ + stat = 0; /* writers still active */ } else { /* No more writers, awaken someone */ - if (rwl->r_wait > 0) { /* if readers waiting */ - stat = pthread_cond_broadcast(&rwl->read); + if (rwl->r_wait > 0) { /* if readers waiting */ + stat = pthread_cond_broadcast(&rwl->read); } else if (rwl->w_wait > 0) { - stat = pthread_cond_signal(&rwl->write); + stat = pthread_cond_broadcast(&rwl->write); } } stat2 = pthread_mutex_unlock(&rwl->mutex); @@ -353,43 +353,43 @@ void *thread_routine(void *arg) * lock). */ if ((iteration % self->interval) == 0) { - status = rwl_writelock(&data[element].lock); - if (status != 0) { - Emsg1(M_ABORT, 0, "Write lock failed. ERR=%s\n", strerror(status)); - } - data[element].data = self->thread_num; - data[element].writes++; - self->writes++; - status = rwl_writeunlock(&data[element].lock); - if (status != 0) { - Emsg1(M_ABORT, 0, "Write unlock failed. ERR=%s\n", strerror(status)); - } + status = rwl_writelock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Write lock failed. ERR=%s\n", strerror(status)); + } + data[element].data = self->thread_num; + data[element].writes++; + self->writes++; + status = rwl_writeunlock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Write unlock failed. ERR=%s\n", strerror(status)); + } } else { - /* - * Look at the current data element to see whether - * the current thread last updated it. Count the - * times to report later. - */ - status = rwl_readlock(&data[element].lock); - if (status != 0) { - Emsg1(M_ABORT, 0, "Read lock failed. ERR=%s\n", strerror(status)); - } - self->reads++; - if (data[element].data == self->thread_num) - repeats++; - status = rwl_readunlock(&data[element].lock); - if (status != 0) { - Emsg1(M_ABORT, 0, "Read unlock failed. ERR=%s\n", strerror(status)); - } + /* + * Look at the current data element to see whether + * the current thread last updated it. Count the + * times to report later. + */ + status = rwl_readlock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Read lock failed. ERR=%s\n", strerror(status)); + } + self->reads++; + if (data[element].data == self->thread_num) + repeats++; + status = rwl_readunlock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Read unlock failed. ERR=%s\n", strerror(status)); + } } element++; if (element >= DATASIZE) { - element = 0; + element = 0; } } if (repeats > 0) { Pmsg2(000, "Thread %d found unchanged elements %d times\n", - self->thread_num, repeats); + self->thread_num, repeats); } return NULL; } @@ -416,27 +416,27 @@ int main (int argc, char *argv[]) * Initialize the shared data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { - data[data_count].data = 0; - data[data_count].writes = 0; - status = rwl_init (&data[data_count].lock); - if (status != 0) { - Emsg1(M_ABORT, 0, "Init rwlock failed. ERR=%s\n", strerror(status)); - } + data[data_count].data = 0; + data[data_count].writes = 0; + status = rwl_init (&data[data_count].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Init rwlock failed. ERR=%s\n", strerror(status)); + } } /* * Create THREADS threads to access shared data. */ for (count = 0; count < THREADS; count++) { - threads[count].thread_num = count + 1; - threads[count].writes = 0; - threads[count].reads = 0; - threads[count].interval = rand_r (&seed) % 71; - status = pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)&threads[count]); - if (status != 0) { - Emsg1(M_ABORT, 0, "Create thread failed. ERR=%s\n", strerror(status)); - } + threads[count].thread_num = count + 1; + threads[count].writes = 0; + threads[count].reads = 0; + threads[count].interval = rand_r (&seed) % 71; + status = pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]); + if (status != 0) { + Emsg1(M_ABORT, 0, "Create thread failed. ERR=%s\n", strerror(status)); + } } /* @@ -444,28 +444,28 @@ int main (int argc, char *argv[]) * statistics. */ for (count = 0; count < THREADS; count++) { - status = pthread_join (threads[count].thread_id, NULL); - if (status != 0) { - Emsg1(M_ABORT, 0, "Join thread failed. ERR=%s\n", strerror(status)); - } - thread_writes += threads[count].writes; - printf ("%02d: interval %d, writes %d, reads %d\n", - count, threads[count].interval, - threads[count].writes, threads[count].reads); + status = pthread_join (threads[count].thread_id, NULL); + if (status != 0) { + Emsg1(M_ABORT, 0, "Join thread failed. ERR=%s\n", strerror(status)); + } + thread_writes += threads[count].writes; + printf ("%02d: interval %d, writes %d, reads %d\n", + count, threads[count].interval, + threads[count].writes, threads[count].reads); } /* * Collect statistics for the data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { - data_writes += data[data_count].writes; - printf ("data %02d: value %d, %d writes\n", - data_count, data[data_count].data, data[data_count].writes); - rwl_destroy (&data[data_count].lock); + data_writes += data[data_count].writes; + printf ("data %02d: value %d, %d writes\n", + data_count, data[data_count].data, data[data_count].writes); + rwl_destroy (&data[data_count].lock); } printf ("Total: %d thread writes, %d data writes\n", - thread_writes, data_writes); + thread_writes, data_writes); return 0; } @@ -485,29 +485,29 @@ int main (int argc, char *argv[]) #include "rwlock.h" #include "errors.h" -#define THREADS 5 -#define ITERATIONS 1000 -#define DATASIZE 15 +#define THREADS 5 +#define ITERATIONS 1000 +#define DATASIZE 15 /* * Keep statistics for each thread. */ typedef struct thread_tag { - int thread_num; - pthread_t thread_id; - int r_collisions; - int w_collisions; - int updates; - int interval; + int thread_num; + pthread_t thread_id; + int r_collisions; + int w_collisions; + int updates; + int interval; } thread_t; /* * Read-write lock and shared data */ typedef struct data_tag { - brwlock_t lock; - int data; - int updates; + brwlock_t lock; + int data; + int updates; } data_t; thread_t threads[THREADS]; @@ -523,38 +523,38 @@ void *thread_routine (void *arg) int element; int status; - element = 0; /* Current data element */ + element = 0; /* Current data element */ for (iteration = 0; iteration < ITERATIONS; iteration++) { - if ((iteration % self->interval) == 0) { - status = rwl_writetrylock (&data[element].lock); - if (status == EBUSY) - self->w_collisions++; - else if (status == 0) { - data[element].data++; - data[element].updates++; - self->updates++; - rwl_writeunlock (&data[element].lock); - } else - err_abort (status, "Try write lock"); - } else { - status = rwl_readtrylock (&data[element].lock); - if (status == EBUSY) - self->r_collisions++; - else if (status != 0) { - err_abort (status, "Try read lock"); - } else { - if (data[element].data != data[element].updates) - printf ("%d: data[%d] %d != %d\n", - self->thread_num, element, - data[element].data, data[element].updates); - rwl_readunlock (&data[element].lock); - } - } - - element++; - if (element >= DATASIZE) - element = 0; + if ((iteration % self->interval) == 0) { + status = rwl_writetrylock (&data[element].lock); + if (status == EBUSY) + self->w_collisions++; + else if (status == 0) { + data[element].data++; + data[element].updates++; + self->updates++; + rwl_writeunlock (&data[element].lock); + } else + err_abort (status, "Try write lock"); + } else { + status = rwl_readtrylock (&data[element].lock); + if (status == EBUSY) + self->r_collisions++; + else if (status != 0) { + err_abort (status, "Try read lock"); + } else { + if (data[element].data != data[element].updates) + printf ("%d: data[%d] %d != %d\n", + self->thread_num, element, + data[element].data, data[element].updates); + rwl_readunlock (&data[element].lock); + } + } + + element++; + if (element >= DATASIZE) + element = 0; } return NULL; } @@ -580,24 +580,24 @@ int main (int argc, char *argv[]) * Initialize the shared data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { - data[data_count].data = 0; - data[data_count].updates = 0; - rwl_init (&data[data_count].lock); + data[data_count].data = 0; + data[data_count].updates = 0; + rwl_init (&data[data_count].lock); } /* * Create THREADS threads to access shared data. */ for (count = 0; count < THREADS; count++) { - threads[count].thread_num = count; - threads[count].r_collisions = 0; - threads[count].w_collisions = 0; - threads[count].updates = 0; - threads[count].interval = rand_r (&seed) % ITERATIONS; - status = pthread_create (&threads[count].thread_id, - NULL, thread_routine, (void*)&threads[count]); - if (status != 0) - err_abort (status, "Create thread"); + threads[count].thread_num = count; + threads[count].r_collisions = 0; + threads[count].w_collisions = 0; + threads[count].updates = 0; + threads[count].interval = rand_r (&seed) % ITERATIONS; + status = pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]); + if (status != 0) + err_abort (status, "Create thread"); } /* @@ -605,25 +605,25 @@ int main (int argc, char *argv[]) * statistics. */ for (count = 0; count < THREADS; count++) { - status = pthread_join (threads[count].thread_id, NULL); - if (status != 0) - err_abort (status, "Join thread"); - thread_updates += threads[count].updates; - printf ("%02d: interval %d, updates %d, " - "r_collisions %d, w_collisions %d\n", - count, threads[count].interval, - threads[count].updates, - threads[count].r_collisions, threads[count].w_collisions); + status = pthread_join (threads[count].thread_id, NULL); + if (status != 0) + err_abort (status, "Join thread"); + thread_updates += threads[count].updates; + printf ("%02d: interval %d, updates %d, " + "r_collisions %d, w_collisions %d\n", + count, threads[count].interval, + threads[count].updates, + threads[count].r_collisions, threads[count].w_collisions); } /* * Collect statistics for the data. */ for (data_count = 0; data_count < DATASIZE; data_count++) { - data_updates += data[data_count].updates; - printf ("data %02d: value %d, %d updates\n", - data_count, data[data_count].data, data[data_count].updates); - rwl_destroy (&data[data_count].lock); + data_updates += data[data_count].updates; + printf ("data %02d: value %d, %d updates\n", + data_count, data[data_count].data, data[data_count].updates); + rwl_destroy (&data[data_count].lock); } return 0; diff --git a/bacula/src/lib/workq.c b/bacula/src/lib/workq.c index 91f812bc5f..a00adbfb37 100755 --- a/bacula/src/lib/workq.c +++ b/bacula/src/lib/workq.c @@ -56,7 +56,7 @@ extern "C" void *workq_server(void *arg); * Initialize a work queue * * Returns: 0 on success - * errno on failure + * errno on failure */ int workq_init(workq_t *wq, int threads, void *(*engine)(void *arg)) { @@ -80,10 +80,10 @@ int workq_init(workq_t *wq, int threads, void *(*engine)(void *arg)) } wq->quit = 0; wq->first = wq->last = NULL; - wq->max_workers = threads; /* max threads to create */ - wq->num_workers = 0; /* no threads yet */ - wq->idle_workers = 0; /* no idle threads */ - wq->engine = engine; /* routine to run */ + wq->max_workers = threads; /* max threads to create */ + wq->num_workers = 0; /* no threads yet */ + wq->idle_workers = 0; /* no idle threads */ + wq->engine = engine; /* routine to run */ wq->valid = WORKQ_VALID; return 0; } @@ -92,7 +92,7 @@ int workq_init(workq_t *wq, int threads, void *(*engine)(void *arg)) * Destroy a work queue * * Returns: 0 on success - * errno on failure + * errno on failure */ int workq_destroy(workq_t *wq) { @@ -104,7 +104,7 @@ int workq_destroy(workq_t *wq) if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) { return stat; } - wq->valid = 0; /* prevent any more operations */ + wq->valid = 0; /* prevent any more operations */ /* * If any threads are active, wake them @@ -112,22 +112,22 @@ int workq_destroy(workq_t *wq) if (wq->num_workers > 0) { wq->quit = 1; if (wq->idle_workers) { - if ((stat = pthread_cond_broadcast(&wq->work)) != 0) { - pthread_mutex_unlock(&wq->mutex); - return stat; - } + if ((stat = pthread_cond_broadcast(&wq->work)) != 0) { + pthread_mutex_unlock(&wq->mutex); + return stat; + } } while (wq->num_workers > 0) { - if ((stat = pthread_cond_wait(&wq->work, &wq->mutex)) != 0) { - pthread_mutex_unlock(&wq->mutex); - return stat; - } + if ((stat = pthread_cond_wait(&wq->work, &wq->mutex)) != 0) { + pthread_mutex_unlock(&wq->mutex); + return stat; + } } } if ((stat = pthread_mutex_unlock(&wq->mutex)) != 0) { return stat; } - stat = pthread_mutex_destroy(&wq->mutex); + stat = pthread_mutex_destroy(&wq->mutex); stat1 = pthread_cond_destroy(&wq->work); stat2 = pthread_attr_destroy(&wq->attr); return (stat != 0 ? stat : (stat1 != 0 ? stat1 : stat2)); @@ -138,10 +138,10 @@ int workq_destroy(workq_t *wq) * Add work to a queue * wq is a queue that was created with workq_init * element is a user unique item that will be passed to the - * processing routine + * processing routine * work_item will get internal work queue item -- if it is not NULL * priority if non-zero will cause the item to be placed on the - * head of the list instead of the tail. + * head of the list instead of the tail. */ int workq_add(workq_t *wq, void *element, workq_ele_t **work_item, int priority) { @@ -168,18 +168,18 @@ int workq_add(workq_t *wq, void *element, workq_ele_t **work_item, int priority) if (priority) { /* Add to head of queue */ if (wq->first == NULL) { - wq->first = item; - wq->last = item; + wq->first = item; + wq->last = item; } else { - item->next = wq->first; - wq->first = item; + item->next = wq->first; + wq->first = item; } } else { /* Add to end of queue */ if (wq->first == NULL) { - wq->first = item; + wq->first = item; } else { - wq->last->next = item; + wq->last->next = item; } wq->last = item; } @@ -187,17 +187,17 @@ int workq_add(workq_t *wq, void *element, workq_ele_t **work_item, int priority) /* if any threads are idle, wake one */ if (wq->idle_workers > 0) { Dmsg0(1400, "Signal worker\n"); - if ((stat = pthread_cond_signal(&wq->work)) != 0) { - pthread_mutex_unlock(&wq->mutex); - return stat; + if ((stat = pthread_cond_broadcast(&wq->work)) != 0) { + pthread_mutex_unlock(&wq->mutex); + return stat; } } else if (wq->num_workers < wq->max_workers) { Dmsg0(1400, "Create worker thread\n"); /* No idle threads so create a new one */ set_thread_concurrency(wq->max_workers + 1); if ((stat = pthread_create(&id, &wq->attr, workq_server, (void *)wq)) != 0) { - pthread_mutex_unlock(&wq->mutex); - return stat; + pthread_mutex_unlock(&wq->mutex); + return stat; } wq->num_workers++; } @@ -236,8 +236,8 @@ int workq_remove(workq_t *wq, workq_ele_t *work_item) for (prev=item=wq->first; item; item=item->next) { if (item == work_item) { - found = 1; - break; + found = 1; + break; } prev = item; } @@ -249,7 +249,7 @@ int workq_remove(workq_t *wq, workq_ele_t *work_item) if (wq->first != work_item) { prev->next = work_item->next; if (wq->last == work_item) { - wq->last = prev; + wq->last = prev; } work_item->next = wq->first; wq->first = work_item; @@ -258,17 +258,17 @@ int workq_remove(workq_t *wq, workq_ele_t *work_item) /* if any threads are idle, wake one */ if (wq->idle_workers > 0) { Dmsg0(1400, "Signal worker\n"); - if ((stat = pthread_cond_signal(&wq->work)) != 0) { - pthread_mutex_unlock(&wq->mutex); - return stat; + if ((stat = pthread_cond_broadcast(&wq->work)) != 0) { + pthread_mutex_unlock(&wq->mutex); + return stat; } } else { Dmsg0(1400, "Create worker thread\n"); /* No idle threads so create a new one */ set_thread_concurrency(wq->max_workers + 1); if ((stat = pthread_create(&id, &wq->attr, workq_server, (void *)wq)) != 0) { - pthread_mutex_unlock(&wq->mutex); - return stat; + pthread_mutex_unlock(&wq->mutex); + return stat; } wq->num_workers++; } @@ -307,66 +307,66 @@ void *workq_server(void *arg) timeout.tv_sec = tv.tv_sec + 2; while (wq->first == NULL && !wq->quit) { - /* - * Wait 2 seconds, then if no more work, exit - */ + /* + * Wait 2 seconds, then if no more work, exit + */ Dmsg0(1400, "pthread_cond_timedwait()\n"); #ifdef xxxxxxxxxxxxxxxx_was_HAVE_CYGWIN - /* CYGWIN dies with a page fault the second - * time that pthread_cond_timedwait() is called - * so fake it out. - */ - pthread_mutex_lock(&wq->mutex); - stat = ETIMEDOUT; + /* CYGWIN dies with a page fault the second + * time that pthread_cond_timedwait() is called + * so fake it out. + */ + pthread_mutex_lock(&wq->mutex); + stat = ETIMEDOUT; #else - stat = pthread_cond_timedwait(&wq->work, &wq->mutex, &timeout); + stat = pthread_cond_timedwait(&wq->work, &wq->mutex, &timeout); #endif Dmsg1(1400, "timedwait=%d\n", stat); - if (stat == ETIMEDOUT) { - timedout = 1; - break; - } else if (stat != 0) { + if (stat == ETIMEDOUT) { + timedout = 1; + break; + } else if (stat != 0) { /* This shouldn't happen */ Dmsg0(1400, "This shouldn't happen\n"); - wq->num_workers--; - pthread_mutex_unlock(&wq->mutex); - return NULL; - } + wq->num_workers--; + pthread_mutex_unlock(&wq->mutex); + return NULL; + } } we = wq->first; if (we != NULL) { - wq->first = we->next; - if (wq->last == we) { - wq->last = NULL; - } - if ((stat = pthread_mutex_unlock(&wq->mutex)) != 0) { - return NULL; - } + wq->first = we->next; + if (wq->last == we) { + wq->last = NULL; + } + if ((stat = pthread_mutex_unlock(&wq->mutex)) != 0) { + return NULL; + } /* Call user's routine here */ Dmsg0(1400, "Calling user engine.\n"); - wq->engine(we->data); + wq->engine(we->data); Dmsg0(1400, "Back from user engine.\n"); - free(we); /* release work entry */ + free(we); /* release work entry */ Dmsg0(1400, "relock mutex\n"); - if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) { - return NULL; - } + if ((stat = pthread_mutex_lock(&wq->mutex)) != 0) { + return NULL; + } Dmsg0(1400, "Done lock mutex\n"); } /* * If no more work request, and we are asked to quit, then do it */ if (wq->first == NULL && wq->quit) { - wq->num_workers--; - if (wq->num_workers == 0) { + wq->num_workers--; + if (wq->num_workers == 0) { Dmsg0(1400, "Wake up destroy routine\n"); - /* Wake up destroy routine if he is waiting */ - pthread_cond_broadcast(&wq->work); - } + /* Wake up destroy routine if he is waiting */ + pthread_cond_broadcast(&wq->work); + } Dmsg0(1400, "Unlock mutex\n"); - pthread_mutex_unlock(&wq->mutex); + pthread_mutex_unlock(&wq->mutex); Dmsg0(1400, "Return from workq_server\n"); - return NULL; + return NULL; } Dmsg0(1400, "Check for work request\n"); /* @@ -376,8 +376,8 @@ void *workq_server(void *arg) Dmsg1(1400, "timedout=%d\n", timedout); if (wq->first == NULL && timedout) { Dmsg0(1400, "break big loop\n"); - wq->num_workers--; - break; + wq->num_workers--; + break; } Dmsg0(1400, "Loop again\n"); } /* end of big for loop */ diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 29cdd7b0ec..4c44872002 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -55,8 +55,8 @@ DCR *new_dcr(JCR *jcr, DEVICE *dev) dcr->max_spool_size = dev->device->max_spool_size; /* Attach this dcr only if dev is initialized */ if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { - dev->attached_dcrs->append(dcr); /* attach dcr to device */ -// jcr->dcrs->append(dcr); /* put dcr in list for Job */ + dev->attached_dcrs->append(dcr); /* attach dcr to device */ +// jcr->dcrs->append(dcr); /* put dcr in list for Job */ } return dcr; } @@ -75,13 +75,13 @@ static void remove_dcr_from_dcrs(DCR *dcr) DCR *ldcr; int num = jcr->dcrs->size(); for (i=0; i < num; i++) { - ldcr = (DCR *)jcr->dcrs->get(i); - if (ldcr == dcr) { - jcr->dcrs->remove(i); - if (jcr->dcr == dcr) { - jcr->dcr = NULL; - } - } + ldcr = (DCR *)jcr->dcrs->get(i); + if (ldcr == dcr) { + jcr->dcrs->remove(i); + if (jcr->dcr == dcr) { + jcr->dcr = NULL; + } + } } } } @@ -105,15 +105,15 @@ void free_dcr(DCR *dcr) dev->num_writers--; if (dev->num_writers < 0) { Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers); - dev->num_writers = 0; - dcr->reserved_device = false; + dev->num_writers = 0; + dcr->reserved_device = false; } unlock_device(dev); } /* Detach this dcr only if the dev is initialized */ if (dev->fd != 0 && jcr && jcr->JobType != JT_SYSTEM) { - dev->attached_dcrs->remove(dcr); /* detach dcr from device */ + dev->attached_dcrs->remove(dcr); /* detach dcr from device */ // remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */ } if (dcr->block) { @@ -149,21 +149,21 @@ bool reserve_device_for_read(DCR *dcr) dev->block(BST_DOING_ACQUIRE); Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), - dev->print_name()); + dev->print_name()); for (first=true; device_is_unmounted(dev); first=false) { dev->unblock(); if (!wait_for_device(dcr, jcr->errmsg, first)) { - return false; + return false; } dev->block(BST_DOING_ACQUIRE); } Mmsg2(jcr->errmsg, _("Device %s is busy. Job %d canceled.\n"), - dev->print_name(), jcr->JobId); + dev->print_name(), jcr->JobId); for (first=true; dev->is_busy(); first=false) { dev->unblock(); if (!wait_for_device(dcr, jcr->errmsg, first)) { - return false; + return false; } dev->block(BST_DOING_ACQUIRE); } @@ -182,7 +182,7 @@ bool reserve_device_for_read(DCR *dcr) * leave the block pointers just after the label. * * Returns: NULL if failed for any reason - * dcr if successful + * dcr if successful */ DCR *acquire_device_for_read(DCR *dcr) { @@ -200,7 +200,7 @@ DCR *acquire_device_for_read(DCR *dcr) if (dev->num_writers > 0) { Jmsg2(jcr, M_FATAL, 0, _("Num_writers=%d not zero. Job %d canceled.\n"), - dev->num_writers, jcr->JobId); + dev->num_writers, jcr->JobId); goto get_out; } @@ -215,15 +215,15 @@ DCR *acquire_device_for_read(DCR *dcr) vol = vol->next; } if (!vol) { - goto get_out; /* should not happen */ + goto get_out; /* should not happen */ } bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); init_device_wait_timers(dcr); tape_previously_mounted = dev->can_read() || - dev->can_append() || - dev->is_labeled(); + dev->can_append() || + dev->is_labeled(); tape_initially_mounted = tape_previously_mounted; @@ -236,10 +236,10 @@ DCR *acquire_device_for_read(DCR *dcr) dev->num_parts = dcr->VolCatInfo.VolCatParts; for (i=0; i<5; i++) { - dev->clear_labeled(); /* force reread of label */ + dev->clear_labeled(); /* force reread of label */ if (job_canceled(jcr)) { Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId); - goto get_out; /* error return */ + goto get_out; /* error return */ } /* * This code ensures that the device is ready for @@ -248,91 +248,91 @@ DCR *acquire_device_for_read(DCR *dcr) */ for ( ; !dev->is_open(); ) { Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName); - if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) { - if (dev->dev_errno == EIO) { /* no tape loaded */ + if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) { + if (dev->dev_errno == EIO) { /* no tape loaded */ Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"), - dev->print_name(), dcr->VolumeName, strerror_dev(dev)); - goto default_path; - } - - /* If we have a dvd that requires mount, - * we need to try to open the label, so the info can be reported - * if a wrong volume has been mounted. */ - if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) { - break; - } - + dev->print_name(), dcr->VolumeName, strerror_dev(dev)); + goto default_path; + } + + /* If we have a dvd that requires mount, + * we need to try to open the label, so the info can be reported + * if a wrong volume has been mounted. */ + if (dev->is_dvd() && (dcr->VolCatInfo.VolCatParts > 0)) { + break; + } + Jmsg3(jcr, M_FATAL, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"), - dev->print_name(), dcr->VolumeName, strerror_dev(dev)); - goto get_out; - } + dev->print_name(), dcr->VolumeName, strerror_dev(dev)); + goto get_out; + } Dmsg1(129, "open_dev %s OK\n", dev->print_name()); } if (dev->is_dvd()) { - vol_label_status = read_dev_volume_label_guess(dcr, 0); + vol_label_status = read_dev_volume_label_guess(dcr, 0); } else { - vol_label_status = read_dev_volume_label(dcr); + vol_label_status = read_dev_volume_label(dcr); } Dmsg0(200, "calling read-vol-label\n"); switch (vol_label_status) { case VOL_OK: - vol_ok = true; - memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); - break; /* got it */ + vol_ok = true; + memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + break; /* got it */ case VOL_IO_ERROR: - /* - * Send error message generated by read_dev_volume_label() - * only we really had a tape mounted. This supresses superfluous - * error messages when nothing is mounted. - */ - if (tape_previously_mounted) { + /* + * Send error message generated by read_dev_volume_label() + * only we really had a tape mounted. This supresses superfluous + * error messages when nothing is mounted. + */ + if (tape_previously_mounted) { Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); - } - goto default_path; + } + goto default_path; case VOL_NAME_ERROR: - if (tape_initially_mounted) { - tape_initially_mounted = false; - goto default_path; - } - /* Fall through */ + if (tape_initially_mounted) { + tape_initially_mounted = false; + goto default_path; + } + /* Fall through */ default: Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg); default_path: - tape_previously_mounted = true; - - /* If the device requires mount, close it, so the device can be ejected. - * FIXME: This should perhaps be done for all devices. */ - if (dev_cap(dev, CAP_REQMOUNT)) { - force_close_dev(dev); - } - - /* Call autochanger only once unless ask_sysop called */ - if (try_autochanger) { - int stat; + tape_previously_mounted = true; + + /* If the device requires mount, close it, so the device can be ejected. + * FIXME: This should perhaps be done for all devices. */ + if (dev_cap(dev, CAP_REQMOUNT)) { + force_close_dev(dev); + } + + /* Call autochanger only once unless ask_sysop called */ + if (try_autochanger) { + int stat; Dmsg2(200, "calling autoload Vol=%s Slot=%d\n", - dcr->VolumeName, dcr->VolCatInfo.Slot); - stat = autoload_device(dcr, 0, NULL); - if (stat > 0) { - try_autochanger = false; - continue; /* try reading volume mounted */ - } - } - - /* Mount a specific volume and no other */ + dcr->VolumeName, dcr->VolCatInfo.Slot); + stat = autoload_device(dcr, 0, NULL); + if (stat > 0) { + try_autochanger = false; + continue; /* try reading volume mounted */ + } + } + + /* Mount a specific volume and no other */ Dmsg0(200, "calling dir_ask_sysop\n"); - if (!dir_ask_sysop_to_mount_volume(dcr)) { - goto get_out; /* error return */ - } - try_autochanger = true; /* permit using autochanger again */ - continue; /* try reading again */ + if (!dir_ask_sysop_to_mount_volume(dcr)) { + goto get_out; /* error return */ + } + try_autochanger = true; /* permit using autochanger again */ + continue; /* try reading again */ } /* end switch */ break; } /* end for loop */ if (!vol_ok) { Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), - dev->print_name()); + dev->print_name()); goto get_out; } @@ -381,22 +381,22 @@ bool reserve_device_for_append(DCR *dcr) dev->block(BST_DOING_ACQUIRE); Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), - dev->print_name()); + dev->print_name()); for (first=true; dev->can_read(); first=false) { dev->unblock(); if (!wait_for_device(dcr, jcr->errmsg, first)) { - return false; + return false; } dev->block(BST_DOING_ACQUIRE); } Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), - dev->print_name()); + dev->print_name()); for (first=true; device_is_unmounted(dev); first=false) { - dev->unblock(); + dev->unblock(); if (!wait_for_device(dcr, jcr->errmsg, first)) { - return false; + return false; } dev->block(BST_DOING_ACQUIRE); } @@ -407,16 +407,16 @@ bool reserve_device_for_append(DCR *dcr) switch (can_reserve_drive(dcr)) { case 0: Mmsg1(jcr->errmsg, _("Device %s is busy writing on another Volume.\n"), dev->print_name()); - dev->unblock(); - if (!wait_for_device(dcr, jcr->errmsg, first)) { - return false; - } - dev->block(BST_DOING_ACQUIRE); - continue; + dev->unblock(); + if (!wait_for_device(dcr, jcr->errmsg, first)) { + return false; + } + dev->block(BST_DOING_ACQUIRE); + continue; case -1: - goto bail_out; /* error */ + goto bail_out; /* error */ default: - break; /* OK, reserve drive */ + break; /* OK, reserve drive */ } break; } @@ -433,8 +433,8 @@ bail_out: /* * Returns: 1 if drive can be reserved - * 0 if we should wait - * -1 on error + * 0 if we should wait + * -1 on error */ static int can_reserve_drive(DCR *dcr) { @@ -445,21 +445,21 @@ static int can_reserve_drive(DCR *dcr) */ if (!dev->can_append() && dev->num_writers == 0) { /* Now check if there are any reservations on the drive */ - if (dev->reserved_device) { - /* Yes, now check if we want the same Pool and pool type */ - if (strcmp(dev->pool_name, dcr->pool_name) == 0 && - strcmp(dev->pool_type, dcr->pool_type) == 0) { - /* OK, compatible device */ - } else { - /* Drive not suitable for us */ - return 0; /* wait */ - } + if (dev->reserved_device) { + /* Yes, now check if we want the same Pool and pool type */ + if (strcmp(dev->pool_name, dcr->pool_name) == 0 && + strcmp(dev->pool_type, dcr->pool_type) == 0) { + /* OK, compatible device */ + } else { + /* Drive not suitable for us */ + return 0; /* wait */ + } } else { - /* Device is available but not yet reserved, reserve it for us */ - bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name)); - bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type)); + /* Device is available but not yet reserved, reserve it for us */ + bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name)); + bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type)); } - return 1; /* reserve drive */ + return 1; /* reserve drive */ } /* @@ -469,19 +469,19 @@ static int can_reserve_drive(DCR *dcr) Dmsg0(190, "device already in append.\n"); /* Yes, now check if we want the same Pool and pool type */ if (strcmp(dev->pool_name, dcr->pool_name) == 0 && - strcmp(dev->pool_type, dcr->pool_type) == 0) { - /* OK, compatible device */ + strcmp(dev->pool_type, dcr->pool_type) == 0) { + /* OK, compatible device */ } else { - /* Drive not suitable for us */ + /* Drive not suitable for us */ Jmsg(jcr, M_WARNING, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name()); - return 0; /* wait */ + return 0; /* wait */ } } else { Pmsg0(000, "Logic error!!!! Should not get here.\n"); Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n")); - return -1; /* error, should not get here */ + return -1; /* error, should not get here */ } - return 1; /* reserve drive */ + return 1; /* reserve drive */ } /* @@ -489,7 +489,7 @@ static int can_reserve_drive(DCR *dcr) * If this is the first one, we read the label. * * Returns: NULL if failed for any reason - * dcr if successful. + * dcr if successful. * Note, normally reserve_device_for_append() is called * before this routine. */ @@ -532,33 +532,34 @@ DCR *acquire_device_for_append(DCR *dcr) */ bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName)); if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) && - !(dir_find_next_appendable_volume(dcr) && - strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */ + !(dir_find_next_appendable_volume(dcr) && + strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */ Dmsg0(190, "Wrong tape mounted.\n"); - if (dev->num_writers != 0 || dev->reserved_device) { + if (dev->num_writers != 0 || dev->reserved_device) { Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev->print_name()); - goto get_out; - } - /* Wrong tape mounted, release it, then fall through to get correct one */ + goto get_out; + } + /* Wrong tape mounted, release it, then fall through to get correct one */ Dmsg0(190, "Wrong tape mounted, release and try mount.\n"); - release = true; - do_mount = true; + release = true; + do_mount = true; } else { - /* - * At this point, the correct tape is already mounted, so - * we do not need to do mount_next_write_volume(), unless - * we need to recycle the tape. - */ + /* + * At this point, the correct tape is already mounted, so + * we do not need to do mount_next_write_volume(), unless + * we need to recycle the tape. + */ recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle); - if (recycle && dev->num_writers != 0) { + if (recycle && dev->num_writers != 0) { Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\"" - " because it is in use by another job.\n")); - goto get_out; - } - if (dev->num_writers == 0) { - memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); - } + " on device %s because it is in use by another job.\n"), + dev->VolHdr.VolName, dev->print_name()); + goto get_out; + } + if (dev->num_writers == 0) { + memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); + } } } else { /* Not already in append mode, so mount the device */ @@ -571,16 +572,16 @@ DCR *acquire_device_for_append(DCR *dcr) Dmsg0(190, "Do mount_next_write_vol\n"); bool mounted = mount_next_write_volume(dcr, release); if (!mounted) { - if (!job_canceled(jcr)) { + if (!job_canceled(jcr)) { /* Reduce "noise" -- don't print if job canceled */ Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"), - dev->print_name()); - } - goto get_out; + dev->print_name()); + } + goto get_out; } } - dev->num_writers++; /* we are now a writer */ + dev->num_writers++; /* we are now a writer */ if (jcr->NumVolumes == 0) { jcr->NumVolumes = 1; } @@ -605,9 +606,9 @@ ok_out: */ bool release_device(DCR *dcr) { - bool ok = true; JCR *jcr = dcr->jcr; DEVICE *dev = dcr->dev; + bool ok = true; lock_device(dev); Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk"); @@ -619,38 +620,45 @@ bool release_device(DCR *dcr) } if (dev->can_read()) { - dev->clear_read(); /* clear read bit */ + dev->clear_read(); /* clear read bit */ /******FIXME**** send read volume usage statistics to director */ } else if (dev->num_writers > 0) { + /* + * Note if WEOT is set, we are at the end of the tape + * and may not be positioned correctly, so the + * job_media_record and update_vol_info have already been + * done, which means we skip them here. + */ dev->num_writers--; Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers); if (dev->is_labeled()) { Dmsg0(100, "dir_create_jobmedia_record. Release\n"); - if (!dir_create_jobmedia_record(dcr)) { + if (!dev->at_weot() && !dir_create_jobmedia_record(dcr)) { Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), - dcr->VolCatInfo.VolCatName, jcr->Job); - ok = false; - } - /* If no more writers, write an EOF */ - if (!dev->num_writers && dev_can_write(dev)) { - weof_dev(dev, 1); - write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolName); - } - dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ - dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */ - /* Note! do volume update before close, which zaps VolCatInfo */ - Dmsg0(100, "dir_update_vol_info. Release0\n"); - dir_update_volume_info(dcr, false); /* send Volume info to Director */ - Dmsg0(100, "==== write ansi eof label \n"); + dcr->VolCatInfo.VolCatName, jcr->Job); + } + /* If no more writers, write an EOF */ + if (!dev->num_writers && dev_can_write(dev)) { + weof_dev(dev, 1); + write_ansi_ibm_labels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolName); + Dmsg0(100, "==== write ansi eof label \n"); + } + if (!dev->at_weot()) { + dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ + dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */ + /* Note! do volume update before close, which zaps VolCatInfo */ + Dmsg0(100, "dir_update_vol_info. Release0\n"); + dir_update_volume_info(dcr, false); /* send Volume info to Director */ + } } } else { - /* - * If we reach here, it is most likely because the + /* + * If we reach here, it is most likely because the job * has failed, since the device is not in read mode and - * there are no writers. + * there are no writers. It was probably reserved. */ } @@ -670,17 +678,17 @@ bool release_device(DCR *dcr) alert = edit_device_codes(dcr, alert, ""); bpipe = open_bpipe(alert, 0, "r"); if (bpipe) { - while (fgets(line, sizeof(line), bpipe->rfd)) { + while (fgets(line, sizeof(line), bpipe->rfd)) { Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line); - } - status = close_bpipe(bpipe); + } + status = close_bpipe(bpipe); } else { - status = errno; + status = errno; } if (status != 0) { - berrno be; + berrno be; Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"), - alert, be.strerror(status)); + alert, be.strerror(status)); } Dmsg1(400, "alert status=%d\n", status); diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index 8904fad771..95d9bdf0e5 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -86,7 +86,7 @@ bool do_append_data(JCR *jcr) */ if (!write_session_label(dcr, SOS_LABEL)) { Jmsg1(jcr, M_FATAL, 0, _("Write session label failed. ERR=%s\n"), - strerror_dev(dev)); + strerror_dev(dev)); set_jcr_job_status(jcr, JS_ErrorTerminated); ok = false; } @@ -98,29 +98,29 @@ bool do_append_data(JCR *jcr) if (!bnet_fsend(fd_sock, OK_data)) { berrno be; Jmsg1(jcr, M_FATAL, 0, _("Network send error to FD. ERR=%s\n"), - be.strerror(fd_sock->b_errno)); + be.strerror(fd_sock->b_errno)); ok = false; } /* * Get Data from File daemon, write to device. To clarify what is - * going on here. We expect: - * - A stream header - * - Multiple records of data - * - EOD record + * going on here. We expect: + * - A stream header + * - Multiple records of data + * - EOD record * - * The Stream header is just used to sychronize things, and - * none of the stream header is written to tape. - * The Multiple records of data, contain first the Attributes, - * then after another stream header, the file data, then - * after another stream header, the MD5 data if any. + * The Stream header is just used to sychronize things, and + * none of the stream header is written to tape. + * The Multiple records of data, contain first the Attributes, + * then after another stream header, the file data, then + * after another stream header, the MD5 data if any. * - * So we get the (stream header, data, EOD) three time for each - * file. 1. for the Attributes, 2. for the file data if any, - * and 3. for the MD5 if any. + * So we get the (stream header, data, EOD) three time for each + * file. 1. for the Attributes, 2. for the file data if any, + * and 3. for the MD5 if any. */ dcr->VolFirstIndex = dcr->VolLastIndex = 0; - jcr->run_time = time(NULL); /* start counting time for rates */ + jcr->run_time = time(NULL); /* start counting time for rates */ for (last_file_index = 0; ok && !job_canceled(jcr); ) { /* Read Stream header from the File daemon. @@ -131,13 +131,13 @@ bool do_append_data(JCR *jcr) * info is not currently used, so is read, but ignored! */ if ((n=bget_msg(ds)) <= 0) { - if (n == BNET_SIGNAL && ds->msglen == BNET_EOD) { - break; /* end of data */ - } + if (n == BNET_SIGNAL && ds->msglen == BNET_EOD) { + break; /* end of data */ + } Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"), - bnet_strerror(ds)); - ok = false; - break; + bnet_strerror(ds)); + ok = false; + break; } /* @@ -149,95 +149,95 @@ bool do_append_data(JCR *jcr) */ char *p = ds->msg; while (B_ISSPACE(*p)) { - p++; + p++; } file_index = (int32_t)str_to_int64(p); while (B_ISDIGIT(*p)) { - p++; + p++; } if (!B_ISSPACE(*p) || !B_ISDIGIT(*(p+1))) { Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg); - ok = false; - break; + ok = false; + break; } stream = (int32_t)str_to_int64(p); Dmsg2(890, " 0 && (file_index == last_file_index || - file_index == last_file_index + 1))) { + file_index == last_file_index + 1))) { Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n")); - ok = false; - break; + ok = false; + break; } if (file_index != last_file_index) { - jcr->JobFiles = file_index; - last_file_index = file_index; + jcr->JobFiles = file_index; + last_file_index = file_index; } /* Read data stream from the File daemon. * The data stream is just raw bytes */ while ((n=bget_msg(ds)) > 0 && !job_canceled(jcr)) { - rec.VolSessionId = jcr->VolSessionId; - rec.VolSessionTime = jcr->VolSessionTime; - rec.FileIndex = file_index; - rec.Stream = stream; - rec.data_len = ds->msglen; - rec.data = ds->msg; /* use message buffer */ + rec.VolSessionId = jcr->VolSessionId; + rec.VolSessionTime = jcr->VolSessionTime; + rec.FileIndex = file_index; + rec.Stream = stream; + rec.data_len = ds->msglen; + rec.data = ds->msg; /* use message buffer */ Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n", - rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream,rec.FileIndex), - rec.data_len); + rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream,rec.FileIndex), + rec.data_len); - while (!write_record_to_block(dcr->block, &rec)) { + while (!write_record_to_block(dcr->block, &rec)) { Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len, - rec.remainder); - if (!write_block_to_device(dcr)) { + rec.remainder); + if (!write_block_to_device(dcr)) { Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n", - dev->print_name(), strerror_dev(dev)); + dev->print_name(), strerror_dev(dev)); Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); - ok = false; - break; - } - } - if (!ok) { + dev->print_name(), strerror_dev(dev)); + ok = false; + break; + } + } + if (!ok) { Dmsg0(400, "Not OK\n"); - break; - } - jcr->JobBytes += rec.data_len; /* increment bytes this job */ + break; + } + jcr->JobBytes += rec.data_len; /* increment bytes this job */ Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n", - FI_to_ascii(rec.FileIndex), rec.VolSessionId, - stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len); - - /* Send attributes and MD5 to Director for Catalog */ - if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_MD5_SIGNATURE || - stream == STREAM_UNIX_ATTRIBUTES_EX || stream == STREAM_SHA1_SIGNATURE) { - if (!jcr->no_attributes) { - if (are_attributes_spooled(jcr)) { - jcr->dir_bsock->spool = true; - } + FI_to_ascii(rec.FileIndex), rec.VolSessionId, + stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len); + + /* Send attributes and MD5 to Director for Catalog */ + if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_MD5_SIGNATURE || + stream == STREAM_UNIX_ATTRIBUTES_EX || stream == STREAM_SHA1_SIGNATURE) { + if (!jcr->no_attributes) { + if (are_attributes_spooled(jcr)) { + jcr->dir_bsock->spool = true; + } Dmsg0(850, "Send attributes to dir.\n"); - if (!dir_update_file_attributes(dcr, &rec)) { - jcr->dir_bsock->spool = false; + if (!dir_update_file_attributes(dcr, &rec)) { + jcr->dir_bsock->spool = false; Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), - bnet_strerror(jcr->dir_bsock)); - ok = false; - break; - } - jcr->dir_bsock->spool = false; - } - } + bnet_strerror(jcr->dir_bsock)); + ok = false; + break; + } + jcr->dir_bsock->spool = false; + } + } Dmsg0(350, "Enter bnet_get\n"); } Dmsg1(350, "End read loop with FD. Stat=%d\n", n); if (is_bnet_error(ds)) { Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds)); Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"), - bnet_strerror(ds)); - ok = false; - break; + bnet_strerror(ds)); + ok = false; + break; } } @@ -256,9 +256,9 @@ bool do_append_data(JCR *jcr) if (ok || dev_can_write(dev)) { if (!write_session_label(dcr, EOS_LABEL)) { Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"), - strerror_dev(dev)); - set_jcr_job_status(jcr, JS_ErrorTerminated); - ok = false; + strerror_dev(dev)); + set_jcr_job_status(jcr, JS_ErrorTerminated); + ok = false; } if (dev->VolCatInfo.VolCatName[0] == 0) { Pmsg0(000, "NULL Volume name. This shouldn't happen!!!\n"); @@ -267,9 +267,9 @@ bool do_append_data(JCR *jcr) /* Flush out final partial block of this session */ if (!write_block_to_device(dcr)) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); + dev->print_name(), strerror_dev(dev)); Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); - ok = false; + ok = false; } } if (dev->VolCatInfo.VolCatName[0] == 0) { @@ -281,45 +281,21 @@ bool do_append_data(JCR *jcr) } else { commit_data_spool(dcr); } - - /* If the device is nor a dvd and WritePartAfterJob - * is set to yes, open the next part, so, in case of a device - * that requires mount, it will be written to the device. - */ - if (ok && dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) { - Dmsg0(100, "Writing last part because write_part_after_job is set.\n"); - if (dev->part < dev->num_parts) { - Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), - dev->part, dev->num_parts, dev->print_name()); - dev->dev_errno = EIO; - ok = false; - } - - if (ok && (open_next_part(dev) < 0)) { - Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"), - dev->print_name(), strerror_dev(dev)); - dev->dev_errno = EIO; - ok = false; - } - - dev->VolCatInfo.VolCatParts = dev->num_parts; - } - Dmsg1(200, "calling release device JobStatus=%d\n", jcr->JobStatus); - /* Release the device */ - if (!release_device(dcr)) { - Pmsg0(000, _("Error in release_device\n")); - set_jcr_job_status(jcr, JS_ErrorTerminated); - ok = false; + if (ok) { + ok = dvd_close_job(dcr); /* do DVD cleanup if any */ } + + /* Release the device -- and send final Vol info to DIR */ + release_device(dcr); - if (!ok) { + if (!ok || job_canceled(jcr)) { discard_attribute_spool(jcr); } else { commit_attribute_spool(jcr); } - dir_send_job_status(jcr); /* update director */ + dir_send_job_status(jcr); /* update director */ Dmsg1(100, "return from do_append_data() stat=%d\n", ok); return ok; diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index 97844bd103..ebbf56a04d 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -36,6 +36,7 @@ extern int debug_level; static bool terminate_writing_volume(DCR *dcr); static bool do_new_file_bookkeeping(DCR *dcr); static bool do_dvd_size_checks(DCR *dcr); +static void reread_last_block(DCR *dcr); /* * Dump the block header, then walk through @@ -434,7 +435,7 @@ bool write_block_to_dev(DCR *dcr) blen = wlen; /* Adjust write size to min/max for tapes only */ - if (dev->state & ST_TAPE) { + if (dev->is_tape()) { /* check for fixed block size */ if (dev->min_block_size == dev->max_block_size) { wlen = block->buf_len; /* fixed block size already rounded */ @@ -470,6 +471,7 @@ bool write_block_to_dev(DCR *dcr) Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"), edit_uint64_with_commas(max_cap, ed1), dev->dev_name); terminate_writing_volume(dcr); + reread_last_block(dcr); /* DEBUG */ dev->dev_errno = ENOSPC; return false; } @@ -511,6 +513,9 @@ bool write_block_to_dev(DCR *dcr) } #endif + /* + * Do write here + */ stat = write(dev->fd, block->buf, (size_t)wlen); #ifdef DEBUG_BLOCK_ZEROING @@ -551,60 +556,9 @@ bool write_block_to_dev(DCR *dcr) if (!ok && !forge_on) { return false; } - -#define CHECK_LAST_BLOCK -#ifdef CHECK_LAST_BLOCK - /* - * If the device is a tape and it supports backspace record, - * we backspace over one or two eof marks depending on - * how many we just wrote, then over the last record, - * then re-read it and verify that the block number is - * correct. - */ - if (ok && (dev->state & ST_TAPE) && dev_cap(dev, CAP_BSR)) { - /* Now back up over what we wrote and read the last block */ - if (!bsf_dev(dev, 1)) { - ok = false; - Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); - } - if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) { - ok = false; - Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); - } - /* Backspace over record */ - if (ok && !bsr_dev(dev, 1)) { - ok = false; - Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); - /* - * On FreeBSD systems, if the user got here, it is likely that his/her - * tape drive is "frozen". The correct thing to do is a - * rewind(), but if we do that, higher levels in cleaning up, will - * most likely write the EOS record over the beginning of the - * tape. The rewind *is* done later in mount.c when another - * tape is requested. Note, the clrerror_dev() call in bsr_dev() - * calls ioctl(MTCERRSTAT), which *should* fix the problem. - */ - } - if (ok) { - DEV_BLOCK *lblock = new_block(dev); - /* Note, this can destroy dev->errmsg */ - dcr->block = lblock; - if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { - Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"), dev->errmsg); - } else { - if (lblock->BlockNumber+1 == block->BlockNumber) { - Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n")); - } else { - Jmsg(jcr, M_ERROR, 0, _( -"Re-read of last block failed. Last block=%u Current block=%u.\n"), - lblock->BlockNumber, block->BlockNumber); - } - } - free_block(lblock); - dcr->block = block; - } + if (ok) { + reread_last_block(dcr); } -#endif return false; } @@ -618,7 +572,7 @@ bool write_block_to_dev(DCR *dcr) block->BlockNumber++; /* Update dcr values */ - if (dev_state(dev, ST_TAPE)) { + if (dev->is_tape()) { dcr->EndBlock = dev->EndBlock; dcr->EndFile = dev->EndFile; } else { @@ -642,6 +596,74 @@ bool write_block_to_dev(DCR *dcr) return true; } +static void reread_last_block(DCR *dcr) +{ +#define CHECK_LAST_BLOCK +#ifdef CHECK_LAST_BLOCK + bool ok = true; + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + DEV_BLOCK *block = dcr->block; + /* + * If the device is a tape and it supports backspace record, + * we backspace over one or two eof marks depending on + * how many we just wrote, then over the last record, + * then re-read it and verify that the block number is + * correct. + */ + if (dev->is_tape() && dev_cap(dev, CAP_BSR)) { + /* Now back up over what we wrote and read the last block */ + if (!bsf_dev(dev, 1)) { + berrno be; + ok = false; + Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), + be.strerror(dev->dev_errno)); + } + if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) { + berrno be; + ok = false; + Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), + be.strerror(dev->dev_errno)); + } + /* Backspace over record */ + if (ok && !bsr_dev(dev, 1)) { + berrno be; + ok = false; + Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), + be.strerror(dev->dev_errno)); + /* + * On FreeBSD systems, if the user got here, it is likely that his/her + * tape drive is "frozen". The correct thing to do is a + * rewind(), but if we do that, higher levels in cleaning up, will + * most likely write the EOS record over the beginning of the + * tape. The rewind *is* done later in mount.c when another + * tape is requested. Note, the clrerror_dev() call in bsr_dev() + * calls ioctl(MTCERRSTAT), which *should* fix the problem. + */ + } + if (ok) { + DEV_BLOCK *lblock = new_block(dev); + /* Note, this can destroy dev->errmsg */ + dcr->block = lblock; + if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { + Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"), + dev->errmsg); + } else { + if (lblock->BlockNumber+1 == block->BlockNumber) { + Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n")); + } else { + Jmsg(jcr, M_ERROR, 0, _( +"Re-read of last block failed. Last block=%u Current block=%u.\n"), + lblock->BlockNumber, block->BlockNumber); + } + } + free_block(lblock); + dcr->block = block; + } + } +#endif +} + static bool terminate_writing_volume(DCR *dcr) { DEVICE *dev = dcr->dev; @@ -668,7 +690,9 @@ static bool terminate_writing_volume(DCR *dcr) if (ok) { ok = write_ansi_ibm_labels(dcr, ANSI_EOV_LABEL, dev->VolHdr.VolName); } - dev->VolCatInfo.VolCatFiles = dev->file; + bstrncpy(dev->VolCatInfo.VolCatStatus, "Full", sizeof(dev->VolCatInfo.VolCatStatus)); + dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ + dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */ if (dev->is_dvd()) { /* Write the current (and last) part. */ open_next_part(dev); @@ -699,7 +723,7 @@ static bool terminate_writing_volume(DCR *dcr) Jmsg(dcr->jcr, M_ERROR, 0, "%s", dev->errmsg); } bail_out: - dev->set_eot(); + dev->set_eot(); /* no more writing this tape */ Dmsg1(100, "Leave terminate_writing_volume -- %s\n", ok?"OK":"ERROR"); return ok; } @@ -954,7 +978,7 @@ reread: Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); Pmsg1(000, "%s", dev->errmsg); /* Attempt to reposition to re-read the block */ - if (dev->state & ST_TAPE) { + if (dev->is_tape()) { Dmsg0(200, "BSR for reread; block too big for buffer.\n"); if (!bsr_dev(dev, 1)) { Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev)); @@ -1002,7 +1026,7 @@ reread: dev->block_num++; /* Update dcr values */ - if (dev->state & ST_TAPE) { + if (dev->is_tape()) { dcr->EndBlock = dev->EndBlock; dcr->EndFile = dev->EndFile; } else { diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index e7d2e1655d..bad6ba545e 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -80,6 +80,10 @@ #include "bacula.h" #include "stored.h" +#ifndef O_NONBLOCK +#define O_NONBLOCK 0 +#endif + /* Functions in dvd.c */ void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name); int mount_dev(DEVICE* dev, int timeout); @@ -90,6 +94,8 @@ void update_free_space_dev(DEVICE* dev); /* Forward referenced functions */ void set_os_device_parameters(DEVICE *dev); static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat); +static void open_tape_device(DEVICE *dev, int mode); +static void open_file_device(DEVICE *dev, int mode); /* * Allocate and initialize the DEVICE structure @@ -292,6 +298,8 @@ open_dev(DEVICE *dev, char *VolName, int mode) } if (VolName) { bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName)); + } else { + dev->VolCatInfo.VolCatName[0] = 0; } Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev), @@ -299,145 +307,180 @@ open_dev(DEVICE *dev, char *VolName, int mode) dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); dev->label_type = B_BACULA_LABEL; if (dev->is_tape() || dev->is_fifo()) { - dev->file_size = 0; - int timeout; - int ioerrcnt = 10; - Dmsg0(29, "open_dev: device is tape\n"); - if (mode == OPEN_READ_WRITE) { - dev->mode = O_RDWR | O_BINARY; - } else if (mode == OPEN_READ_ONLY) { - dev->mode = O_RDONLY | O_BINARY; - } else if (mode == OPEN_WRITE_ONLY) { - dev->mode = O_WRONLY | O_BINARY; - } else { - Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); + open_tape_device(dev, mode); + } else { + open_file_device(dev, mode); + } + return dev->fd; +} + +static void open_tape_device(DEVICE *dev, int mode) +{ + int nonblocking = 0;; + dev->file_size = 0; + int timeout; + int ioerrcnt = 10; + Dmsg0(29, "open_dev: device is tape\n"); + if (mode == OPEN_READ_WRITE) { + dev->mode = O_RDWR | O_BINARY; + } else if (mode == OPEN_READ_ONLY) { + dev->mode = O_RDONLY | O_BINARY; + } else if (mode == OPEN_WRITE_ONLY) { + dev->mode = O_WRONLY | O_BINARY; + } else { + Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); + } + timeout = dev->max_open_wait; + errno = 0; + if (dev->open_nowait) { + /* Set wait counters to zero for no wait */ + timeout = ioerrcnt = 0; + /* Open drive in non-block mode */ + nonblocking = O_NONBLOCK; + } + if (dev->is_fifo() && timeout) { + /* Set open timer */ + dev->tid = start_thread_timer(pthread_self(), timeout); + } + /* If busy retry each second for max_open_wait seconds */ +open_again: + Dmsg1(500, "Try open %s\n", dev->dev_name); + while ((dev->fd = open(dev->dev_name, dev->mode, MODE_RW+nonblocking)) < 0) { + berrno be; + Dmsg2(500, "Open error errno=%d ERR=%s\n", errno, be.strerror()); + if (errno == EINTR || errno == EAGAIN) { + Dmsg0(500, "Continue open\n"); + continue; } - timeout = dev->max_open_wait; - errno = 0; - if (dev->is_fifo() && timeout) { - /* Set open timer */ - dev->tid = start_thread_timer(pthread_self(), timeout); + /* Busy wait for specified time (default = 5 mins) */ + if (errno == EBUSY && timeout-- > 0) { + Dmsg2(100, "Device %s busy. ERR=%s\n", dev->print_name(), be.strerror()); + bmicrosleep(1, 0); + continue; } - /* If busy retry each second for max_open_wait seconds */ - while ((dev->fd = open(dev->dev_name, dev->mode, MODE_RW)) < 0) { - berrno be; - if (errno == EINTR || errno == EAGAIN) { - continue; - } - /* Busy wait for specified time (default = 5 mins) */ - if (errno == EBUSY && timeout-- > 0) { - Dmsg2(100, "Device %s busy. ERR=%s\n", dev->print_name(), be.strerror()); - bmicrosleep(1, 0); - continue; - } - /* IO error (no volume) try 10 times every 6 seconds */ - if (errno == EIO && ioerrcnt-- > 0) { - bmicrosleep(5, 0); - continue; - } - dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("Unable to open device %s: ERR=%s\n"), - dev->print_name(), be.strerror(dev->dev_errno)); - /* Stop any open timer we set */ - if (dev->tid) { - stop_thread_timer(dev->tid); - dev->tid = 0; - } - Emsg0(M_FATAL, 0, dev->errmsg); - break; + /* IO error (no volume) try 10 times every 6 seconds */ + if (errno == EIO && ioerrcnt-- > 0) { + bmicrosleep(5, 0); + Dmsg0(500, "Continue open\n"); + continue; } - if (dev->fd >= 0) { - dev->dev_errno = 0; - dev->state |= ST_OPENED; - dev->use_count = 1; - update_pos_dev(dev); /* update position */ - set_os_device_parameters(dev); /* do system dependent stuff */ - } - /* Stop any open() timer we started */ + dev->dev_errno = errno; + Mmsg2(&dev->errmsg, _("Unable to open device %s: ERR=%s\n"), + dev->print_name(), be.strerror(dev->dev_errno)); + /* Stop any open timer we set */ if (dev->tid) { stop_thread_timer(dev->tid); dev->tid = 0; } - Dmsg1(29, "open_dev: tape %d opened\n", dev->fd); - } else { - POOL_MEM archive_name(PM_FNAME); - struct stat filestat; - /* - * Handle opening of File Archive (not a tape) - */ - if (dev->part == 0) { - dev->file_size = 0; - } - dev->part_size = 0; - - /* if num_parts has not been set, but VolCatInfo is available, copy - * it from the VolCatInfo.VolCatParts */ - if (dev->num_parts < dev->VolCatInfo.VolCatParts) { - dev->num_parts = dev->VolCatInfo.VolCatParts; - } - - if (VolName == NULL || *VolName == 0) { - Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"), - dev->print_name()); - return -1; + Emsg0(M_FATAL, 0, dev->errmsg); + break; + } + if (dev->fd >= 0) { + if (mode != 0) { + /* If opened in non-block mode, close it an open it normally */ + mode = 0; + close(dev->fd); + goto open_again; } - get_filename(dev, VolName, archive_name); + dev->dev_errno = 0; + dev->state |= ST_OPENED; + dev->use_count = 1; + update_pos_dev(dev); /* update position */ + set_os_device_parameters(dev); /* do system dependent stuff */ + Dmsg0(500, "Open OK\n"); + } + /* Stop any open() timer we started */ + if (dev->tid) { + stop_thread_timer(dev->tid); + dev->tid = 0; + } + Dmsg1(29, "open_dev: tape %d opened\n", dev->fd); +} - if (mount_dev(dev, 1) < 0) { - Mmsg(dev->errmsg, _("Could not mount device %s.\n"), - dev->print_name()); - Emsg0(M_FATAL, 0, dev->errmsg); - dev->fd = -1; - return dev->fd; - } - - Dmsg2(29, "open_dev: device is disk %s (mode:%d)\n", archive_name.c_str(), mode); - dev->openmode = mode; - - /* - * If we are not trying to access the last part, set mode to - * OPEN_READ_ONLY as writing would be an error. - */ - if (dev->part < dev->num_parts) { - mode = OPEN_READ_ONLY; - } - - if (mode == OPEN_READ_WRITE) { - dev->mode = O_CREAT | O_RDWR | O_BINARY; - } else if (mode == OPEN_READ_ONLY) { - dev->mode = O_RDONLY | O_BINARY; - } else if (mode == OPEN_WRITE_ONLY) { - dev->mode = O_WRONLY | O_BINARY; - } else { - Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); - } - /* If creating file, give 0640 permissions */ - if ((dev->fd = open(archive_name.c_str(), dev->mode, 0640)) < 0) { +/* + * Open a file or DVD device + */ +static void open_file_device(DEVICE *dev, int mode) +{ + POOL_MEM archive_name(PM_FNAME); + struct stat filestat; + /* + * Handle opening of File Archive (not a tape) + */ + if (dev->part == 0) { + dev->file_size = 0; + } + dev->part_size = 0; + + /* if num_parts has not been set, but VolCatInfo is available, copy + * it from the VolCatInfo.VolCatParts */ + if (dev->num_parts < dev->VolCatInfo.VolCatParts) { + dev->num_parts = dev->VolCatInfo.VolCatParts; + } + + if (dev->VolCatInfo.VolCatName[0] == 0) { + Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"), + dev->print_name()); + dev->fd = -1; + return; + } + get_filename(dev, dev->VolCatInfo.VolCatName, archive_name); + + if (mount_dev(dev, 1) < 0) { + Mmsg(dev->errmsg, _("Could not mount device %s.\n"), + dev->print_name()); + Emsg0(M_FATAL, 0, dev->errmsg); + dev->fd = -1; + return; + } + + Dmsg2(29, "open_dev: device is disk %s (mode:%d)\n", archive_name.c_str(), mode); + dev->openmode = mode; + + /* + * If we are not trying to access the last part, set mode to + * OPEN_READ_ONLY as writing would be an error. + */ + if (dev->part < dev->num_parts) { + mode = OPEN_READ_ONLY; + } + + if (mode == OPEN_READ_WRITE) { + dev->mode = O_CREAT | O_RDWR | O_BINARY; + } else if (mode == OPEN_READ_ONLY) { + dev->mode = O_RDONLY | O_BINARY; + } else if (mode == OPEN_WRITE_ONLY) { + dev->mode = O_WRONLY | O_BINARY; + } else { + Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); + } + /* If creating file, give 0640 permissions */ + if ((dev->fd = open(archive_name.c_str(), dev->mode, 0640)) < 0) { + berrno be; + dev->dev_errno = errno; + Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), + be.strerror()); + Emsg0(M_FATAL, 0, dev->errmsg); + } else { + dev->dev_errno = 0; + dev->state |= ST_OPENED; + dev->use_count = 1; + update_pos_dev(dev); /* update position */ + if (fstat(dev->fd, &filestat) < 0) { berrno be; dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.strerror()); + Mmsg2(&dev->errmsg, _("Could not fstat: %s, ERR=%s\n"), archive_name.c_str(), + be.strerror()); Emsg0(M_FATAL, 0, dev->errmsg); } else { - dev->dev_errno = 0; - dev->state |= ST_OPENED; - dev->use_count = 1; - update_pos_dev(dev); /* update position */ - if (fstat(dev->fd, &filestat) < 0) { - berrno be; - dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("Could not fstat: %s, ERR=%s\n"), archive_name.c_str(), be.strerror()); - Emsg0(M_FATAL, 0, dev->errmsg); - } else { - dev->part_size = filestat.st_size; - } - } - Dmsg4(29, "open_dev: disk fd=%d opened, part=%d/%d, part_size=%u\n", dev->fd, dev->part, dev->num_parts, dev->part_size); - if (dev->is_dvd() && (dev->mode != OPEN_READ_ONLY) && - (dev->free_space_errno == 0 || dev->num_parts == dev->part)) { - update_free_space_dev(dev); + dev->part_size = filestat.st_size; } } - return dev->fd; + Dmsg4(29, "open_dev: disk fd=%d opened, part=%d/%d, part_size=%u\n", dev->fd, dev->part, dev->num_parts, dev->part_size); + if (dev->is_dvd() && (dev->mode != OPEN_READ_ONLY) && + (dev->free_space_errno == 0 || dev->num_parts == dev->part)) { + update_free_space_dev(dev); + } } #ifdef debug_tracing diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 545d2b2604..bd9df85310 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -197,6 +197,7 @@ public: int mode; /* read/write modes */ int openmode; /* parameter passed to open_dev (useful to reopen the device) */ bool autoselect; /* Autoselect in autochanger */ + bool open_nowait; /* If set, don t wait on open */ int label_type; /* Bacula/ANSI/IBM label types */ uint32_t drive_index; /* Autochanger drive index */ POOLMEM *dev_name; /* Physical device name */ @@ -239,6 +240,10 @@ public: char pool_name[MAX_NAME_LENGTH]; /* pool name */ char pool_type[MAX_NAME_LENGTH]; /* pool type */ + + + + /* Device wait times ***FIXME*** look at durations */ char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */ bool poll; /* set to poll Volume */ @@ -250,19 +255,19 @@ public: int num_wait; /* Methods */ - int is_tape() const; - int is_file() const; - int is_fifo() const; - int is_dvd() const; - int is_open() const; - int is_offline() const; - int is_labeled() const; + int is_tape() const { return state & ST_TAPE; } + int is_file() const { return state & ST_FILE; } + int is_fifo() const { return state & ST_FIFO; } + int is_dvd() const { return state & ST_DVD; } + int is_open() const { return state & ST_OPENED; } + int is_offline() const { return state & ST_OFFLINE; } + int is_labeled() const { return state & ST_LABEL; } int is_busy() const; /* either reading or writing */ - int at_eof() const; - int at_eom() const; - int at_eot() const; - int can_append() const; - int can_read() const; + int at_eof() const { return state & ST_EOF; } + int at_eot() const { return state & ST_EOT; } + int at_weot() const { return state & ST_WEOT; } + int can_append() const { return state & ST_APPEND; } + int can_read() const { return state & ST_READ; } bool can_steal_lock() const { return dev_blocked && (dev_blocked == BST_UNMOUNTED || dev_blocked == BST_WAITING_FOR_SYSOP || @@ -293,18 +298,7 @@ public: }; /* Note, these return int not bool! */ -inline int DEVICE::is_tape() const { return state & ST_TAPE; } -inline int DEVICE::is_file() const { return state & ST_FILE; } -inline int DEVICE::is_fifo() const { return state & ST_FIFO; } -inline int DEVICE::is_dvd() const { return state & ST_DVD; } -inline int DEVICE::is_open() const { return state & ST_OPENED; } -inline int DEVICE::is_offline() const { return state & ST_OFFLINE; } -inline int DEVICE::is_labeled() const { return state & ST_LABEL; } inline int DEVICE::is_busy() const { return state & ST_READ || num_writers || reserved_device; } -inline int DEVICE::at_eof() const { return state & ST_EOF; } -inline int DEVICE::at_eot() const { return state & ST_EOT; } -inline int DEVICE::can_append() const { return state & ST_APPEND; } -inline int DEVICE::can_read() const { return state & ST_READ; } inline const char *DEVICE::strerror() const { return errmsg; } inline const char *DEVICE::archive_name() const { return dev_name; } inline const char *DEVICE::print_name() const { return prt_name; } diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 436c1bd926..14715689bf 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -100,18 +100,6 @@ bool fixup_device_block_write_error(DCR *dcr) /* Unlock, but leave BLOCKED */ unlock_device(dev); - bstrncpy(dev->VolCatInfo.VolCatStatus, "Full", sizeof(dev->VolCatInfo.VolCatStatus)); - Dmsg2(100, "Call update_vol_info Stat=%s Vol=%s\n", - dev->VolCatInfo.VolCatStatus, dev->VolCatInfo.VolCatName); - dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ - dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */ - if (!dir_update_volume_info(dcr, false)) { /* send Volume info to Director */ - P(dev->mutex); - unblock_device(dev); - return false; /* device locked */ - } - Dmsg0(100, "Back from update_vol_info\n"); - bstrncpy(PrevVolName, dev->VolCatInfo.VolCatName, sizeof(PrevVolName)); bstrncpy(dev->VolHdr.PrevVolName, PrevVolName, sizeof(dev->VolHdr.PrevVolName)); @@ -284,14 +272,16 @@ bool first_open_device(DEVICE *dev) mode = OPEN_READ_WRITE; } Dmsg0(129, "Opening device.\n"); + dev->open_nowait = true; if (open_dev(dev, NULL, mode) < 0) { Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg); + dev->open_nowait = false; unlock_device(dev); return false; } } Dmsg1(129, "open_dev %s OK\n", dev->print_name()); - + dev->open_nowait = false; unlock_device(dev); return true; } diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 390297d56b..763f47fa4c 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -7,9 +7,9 @@ * in job.c. * * N.B. in this file, in general we must use P(dev->mutex) rather - * than lock_device(dev) so that we can examine the blocked + * than lock_device(dev) so that we can examine the blocked * state rather than blocking ourselves. In some "safe" cases, - * we can do things to a blocked device. CAREFUL!!!! + * we can do things to a blocked device. CAREFUL!!!! * * File daemon commands are handled in fdcmd.c * @@ -79,8 +79,8 @@ static bool do_label(JCR *jcr, int relabel); static DEVICE *find_device(JCR *jcr, POOL_MEM &dev_name); static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot); static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, - char *newname, char *poolname, - int Slot, int relabel); + char *newname, char *poolname, + int Slot, int relabel); static bool try_autoload_device(JCR *jcr, int slot, const char *VolName); static void send_dir_busy_message(BSOCK *dir, DEVICE *dev); @@ -107,10 +107,10 @@ static struct s_cmds cmds[] = { {"status", status_cmd, 1}, {".status", qstatus_cmd, 1}, {"unmount", unmount_cmd, 0}, - {"use storage", use_cmd, 0}, + {"use storage=", use_cmd, 0}, {"run", run_cmd, 0}, // {"query", query_cmd, 0}, - {NULL, NULL} /* list terminator */ + {NULL, NULL} /* list terminator */ }; @@ -155,7 +155,7 @@ void *handle_connection_request(void *arg) } /* * See if this is a File daemon connection. If so - * call FD handler. + * call FD handler. */ Dmsg1(110, "Conn: %s", bs->msg); if (sscanf(bs->msg, "Hello Start Job %127s", name) == 1) { @@ -168,7 +168,7 @@ void *handle_connection_request(void *arg) */ Dmsg0(110, "Start Dir Job\n"); jcr = new_jcr(sizeof(JCR), stored_free_jcr); /* create Job Control Record */ - jcr->dir_bsock = bs; /* save Director bsock */ + jcr->dir_bsock = bs; /* save Director bsock */ jcr->dir_bsock->jcr = jcr; jcr->dcrs = New(alist(10, not_owned_by_alist)); /* Initialize FD start condition variable */ @@ -192,34 +192,34 @@ void *handle_connection_request(void *arg) for (quit=false; !quit;) { /* Read command */ if ((bnet_stat = bnet_recv(bs)) <= 0) { - break; /* connection terminated */ + break; /* connection terminated */ } Dmsg1(199, "msg); found = false; for (i=0; cmds[i].cmd; i++) { - if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) { - if ((!cmds[i].monitoraccess) && (jcr->director->monitor)) { + if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) { + if ((!cmds[i].monitoraccess) && (jcr->director->monitor)) { Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd); - bnet_fsend(bs, illegal_cmd); - bnet_sig(bs, BNET_EOD); - break; - } + bnet_fsend(bs, illegal_cmd); + bnet_sig(bs, BNET_EOD); + break; + } Dmsg1(200, "Do command: %s\n", cmds[i].cmd); - if (!cmds[i].func(jcr)) { /* do command */ - quit = true; /* error, get out */ + if (!cmds[i].func(jcr)) { /* do command */ + quit = true; /* error, get out */ Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd); - } - found = true; /* indicate command found */ - break; - } + } + found = true; /* indicate command found */ + break; + } } - if (!found) { /* command not found */ - bnet_fsend(bs, derrmsg); - break; + if (!found) { /* command not found */ + bnet_fsend(bs, derrmsg); + break; } } bail_out: - dequeue_messages(jcr); /* send any queued messages */ + dequeue_messages(jcr); /* send any queued messages */ bnet_sig(bs, BNET_TERMINATE); free_jcr(jcr); return NULL; @@ -259,23 +259,23 @@ static bool cancel_cmd(JCR *cjcr) if (!(jcr=get_jcr_by_full_name(Job))) { bnet_fsend(dir, _("3992 Job %s not found.\n"), Job); } else { - P(jcr->mutex); - oldStatus = jcr->JobStatus; - set_jcr_job_status(jcr, JS_Canceled); - if (!jcr->authenticated && oldStatus == JS_WaitFD) { - pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */ - } - V(jcr->mutex); - if (jcr->file_bsock) { - bnet_sig(jcr->file_bsock, BNET_TERMINATE); - } - /* If thread waiting on mount, wake him */ - if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) { - pthread_cond_signal(&jcr->dcr->dev->wait_next_vol); - pthread_cond_broadcast(&wait_device_release); - } + P(jcr->mutex); + oldStatus = jcr->JobStatus; + set_jcr_job_status(jcr, JS_Canceled); + if (!jcr->authenticated && oldStatus == JS_WaitFD) { + pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */ + } + V(jcr->mutex); + if (jcr->file_bsock) { + bnet_sig(jcr->file_bsock, BNET_TERMINATE); + } + /* If thread waiting on mount, wake him */ + if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) { + pthread_cond_signal(&jcr->dcr->dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); + } bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job); - free_jcr(jcr); + free_jcr(jcr); } } else { bnet_fsend(dir, _("3993 Error scanning cancel command.\n")); @@ -313,14 +313,14 @@ static bool do_label(JCR *jcr, int relabel) mtype = get_memory(dir->msglen+1); if (relabel) { if (sscanf(dir->msg, "relabel %127s OldName=%127s NewName=%127s PoolName=%127s MediaType=%127s Slot=%d", - dev_name.c_str(), oldname, newname, poolname, mtype, &slot) == 6) { - ok = true; + dev_name.c_str(), oldname, newname, poolname, mtype, &slot) == 6) { + ok = true; } } else { *oldname = 0; if (sscanf(dir->msg, "label %127s VolumeName=%127s PoolName=%127s MediaType=%127s Slot=%d", - dev_name.c_str(), newname, poolname, mtype, &slot) == 5) { - ok = true; + dev_name.c_str(), newname, poolname, mtype, &slot) == 5) { + ok = true; } } if (ok) { @@ -330,20 +330,20 @@ static bool do_label(JCR *jcr, int relabel) unbash_spaces(mtype); dev = find_device(jcr, dev_name); if (dev) { - /******FIXME**** compare MediaTypes */ - P(dev->mutex); /* Use P to avoid indefinite block */ - if (!dev->is_open()) { - label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); - force_close_dev(dev); + /******FIXME**** compare MediaTypes */ + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!dev->is_open()) { + label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); + force_close_dev(dev); /* Under certain "safe" conditions, we can steal the lock */ - } else if (dev->can_steal_lock()) { - label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); - } else if (dev->is_busy()) { - send_dir_busy_message(dir, dev); - } else { /* device not being used */ - label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); - } - V(dev->mutex); + } else if (dev->can_steal_lock()) { + label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); + } else if (dev->is_busy()) { + send_dir_busy_message(dir, dev); + } else { /* device not being used */ + label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); + } + V(dev->mutex); } else { bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dev_name.c_str()); } @@ -367,8 +367,8 @@ static bool do_label(JCR *jcr, int relabel) * Enter with the mutex set */ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, - char *newname, char *poolname, - int slot, int relabel) + char *newname, char *poolname, + int slot, int relabel) { BSOCK *dir = jcr->dir_bsock; bsteal_lock_t hold; @@ -379,7 +379,7 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, steal_device_lock(dev, &hold, BST_WRITING_LABEL); if (!try_autoload_device(jcr, slot, newname)) { - goto bail_out; /* error */ + goto bail_out; /* error */ } /* See what we have for a Volume */ @@ -395,31 +395,31 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, case VOL_LABEL_ERROR: case VOL_OK: if (!relabel) { - bnet_fsend(dir, _( + bnet_fsend(dir, _( "3920 Cannot label Volume because it is already labeled: \"%s\"\n"), - dev->VolHdr.VolName); - break; + dev->VolHdr.VolName); + break; } /* Relabel request. If oldname matches, continue */ if (strcmp(oldname, dev->VolHdr.VolName) != 0) { bnet_fsend(dir, _("3921 Wrong volume mounted.\n")); - break; + break; } if (dev->label_type != B_BACULA_LABEL) { bnet_fsend(dir, _("3922 Cannot relabel an ANSI/IBM labeled Volume.\n")); - break; + break; } /* Fall through wanted! */ case VOL_IO_ERROR: case VOL_NO_LABEL: if (!write_new_volume_label_to_dev(dcr, newname, poolname)) { bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev)); - break; + break; } bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName)); /* The following 3000 OK label. string is scanned in ua_label.c */ bnet_fsend(dir, "3000 OK label. Volume=%s Device=%s\n", - newname, dev->print_name()); + newname, dev->print_name()); break; case VOL_NO_MEDIA: bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev)); @@ -452,7 +452,7 @@ static bool read_label(DCR *dcr) steal_device_lock(dev, &hold, BST_DOING_ACQUIRE); dcr->VolumeName[0] = 0; - dev->clear_labeled(); /* force read of label */ + dev->clear_labeled(); /* force read of label */ switch (read_dev_volume_label(dcr)) { case VOL_OK: bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName); @@ -460,7 +460,7 @@ static bool read_label(DCR *dcr) break; default: bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device %s because:\n%s"), - dev->print_name(), jcr->errmsg); + dev->print_name(), jcr->errmsg); ok = false; break; } @@ -479,44 +479,44 @@ static DEVICE *find_device(JCR *jcr, POOL_MEM &devname) foreach_res(device, R_DEVICE) { /* Find resource, and make sure we were able to open it */ if (fnmatch(device->hdr.name, devname.c_str(), 0) == 0) { - if (!device->dev) { - device->dev = init_dev(jcr, NULL, device); - } - if (!device->dev) { + if (!device->dev) { + device->dev = init_dev(jcr, NULL, device); + } + if (!device->dev) { Jmsg(jcr, M_WARNING, 0, _("\n" " Device \"%s\" requested by DIR could not be opened or does not exist.\n"), - devname.c_str()); - continue; - } + devname.c_str()); + continue; + } Dmsg1(20, "Found device %s\n", device->hdr.name); - found = true; - break; + found = true; + break; } } foreach_res(changer, R_AUTOCHANGER) { /* Find resource, and make sure we were able to open it */ if (fnmatch(devname.c_str(), changer->hdr.name, 0) == 0) { - /* Try each device in this AutoChanger */ - foreach_alist(device, changer->device) { + /* Try each device in this AutoChanger */ + foreach_alist(device, changer->device) { Dmsg1(100, "Try changer device %s\n", device->hdr.name); - if (!device->dev) { - device->dev = init_dev(jcr, NULL, device); - } - if (!device->dev) { + if (!device->dev) { + device->dev = init_dev(jcr, NULL, device); + } + if (!device->dev) { Dmsg1(100, "Device %s could not be opened. Skipped\n", devname.c_str()); Jmsg(jcr, M_WARNING, 0, _("\n" " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"), - device->hdr.name, devname.c_str()); - continue; - } - if (!device->dev->autoselect) { - continue; /* device is not available */ - } + device->hdr.name, devname.c_str()); + continue; + } + if (!device->dev->autoselect) { + continue; /* device is not available */ + } Dmsg1(20, "Found changer device %s\n", device->hdr.name); - found = true; - break; - } - break; /* we found it but could not open a device */ + found = true; + break; + } + break; /* we found it but could not open a device */ } } @@ -545,96 +545,96 @@ static bool mount_cmd(JCR *jcr) dev = find_device(jcr, devname); dcr = jcr->dcr; if (dev) { - P(dev->mutex); /* Use P to avoid indefinite block */ - switch (dev->dev_blocked) { /* device blocked? */ - case BST_WAITING_FOR_SYSOP: - /* Someone is waiting, wake him */ + P(dev->mutex); /* Use P to avoid indefinite block */ + switch (dev->dev_blocked) { /* device blocked? */ + case BST_WAITING_FOR_SYSOP: + /* Someone is waiting, wake him */ Dmsg0(100, "Waiting for mount. Attempting to wake thread\n"); - dev->dev_blocked = BST_MOUNT; + dev->dev_blocked = BST_MOUNT; bnet_fsend(dir, "3001 OK mount. Device=%s\n", - dev->print_name()); - pthread_cond_signal(&dev->wait_next_vol); - pthread_cond_broadcast(&wait_device_release); - break; - - /* In both of these two cases, we (the user) unmounted the Volume */ - case BST_UNMOUNTED_WAITING_FOR_SYSOP: - case BST_UNMOUNTED: - /* We freed the device, so reopen it and wake any waiting threads */ - if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { + dev->print_name()); + pthread_cond_broadcast(&dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); + break; + + /* In both of these two cases, we (the user) unmounted the Volume */ + case BST_UNMOUNTED_WAITING_FOR_SYSOP: + case BST_UNMOUNTED: + /* We freed the device, so reopen it and wake any waiting threads */ + if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), - strerror_dev(dev)); - break; - } - read_dev_volume_label(dcr); - if (dev->dev_blocked == BST_UNMOUNTED) { - /* We blocked the device, so unblock it */ + strerror_dev(dev)); + break; + } + read_dev_volume_label(dcr); + if (dev->dev_blocked == BST_UNMOUNTED) { + /* We blocked the device, so unblock it */ Dmsg0(100, "Unmounted. Unblocking device\n"); - read_label(dcr); /* this should not be necessary */ - unblock_device(dev); - } else { + read_label(dcr); /* this should not be necessary */ + unblock_device(dev); + } else { Dmsg0(100, "Unmounted waiting for mount. Attempting to wake thread\n"); - dev->dev_blocked = BST_MOUNT; - } - if (dev->is_labeled()) { + dev->dev_blocked = BST_MOUNT; + } + if (dev->is_labeled()) { bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"), - dev->print_name(), dev->VolHdr.VolName); - } else { + dev->print_name(), dev->VolHdr.VolName); + } else { bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" "If this is not a blank tape, try unmounting and remounting the Volume.\n"), - dev->print_name()); - } - pthread_cond_signal(&dev->wait_next_vol); - pthread_cond_broadcast(&wait_device_release); - break; + dev->print_name()); + } + pthread_cond_broadcast(&dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); + break; - case BST_DOING_ACQUIRE: + case BST_DOING_ACQUIRE: bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), - dev->print_name()); - break; + dev->print_name()); + break; - case BST_WRITING_LABEL: + case BST_WRITING_LABEL: bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), - dev->print_name()); - break; + dev->print_name()); + break; - case BST_NOT_BLOCKED: - if (dev->is_open()) { - if (dev->is_labeled()) { + case BST_NOT_BLOCKED: + if (dev->is_open()) { + if (dev->is_labeled()) { bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"), - dev->print_name(), dev->VolHdr.VolName); - } else { + dev->print_name(), dev->VolHdr.VolName); + } else { bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" "If this is not a blank tape, try unmounting and remounting the Volume.\n"), - dev->print_name()); - } - } else { - if (!dev_is_tape(dev)) { + dev->print_name()); + } + } else { + if (!dev_is_tape(dev)) { bnet_fsend(dir, _("3906 cannot mount non-tape.\n")); - break; - } - if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { + break; + } + if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), - strerror_dev(dev)); - break; - } - read_label(dcr); - if (dev->is_labeled()) { + strerror_dev(dev)); + break; + } + read_label(dcr); + if (dev->is_labeled()) { bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"), - dev->print_name(), dev->VolHdr.VolName); - } else { + dev->print_name(), dev->VolHdr.VolName); + } else { bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" "If this is not a blank tape, try unmounting and remounting the Volume.\n"), - dev->print_name()); - } - } - break; + dev->print_name()); + } + } + break; - default: + default: bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked); - break; - } - V(dev->mutex); + break; + } + V(dev->mutex); } else { bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str()); } @@ -658,49 +658,49 @@ static bool unmount_cmd(JCR *jcr) if (sscanf(dir->msg, "unmount %127s", devname.c_str()) == 1) { dev = find_device(jcr, devname); if (dev) { - P(dev->mutex); /* Use P to avoid indefinite block */ - if (!dev->is_open()) { + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!dev->is_open()) { Dmsg0(90, "Device already unmounted\n"); bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) { + } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) { Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, - dev->dev_blocked); - open_dev(dev, NULL, 0); /* fake open for close */ - offline_or_rewind_dev(dev); - force_close_dev(dev); - dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP; + dev->dev_blocked); + open_dev(dev, NULL, 0); /* fake open for close */ + offline_or_rewind_dev(dev); + force_close_dev(dev); + dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP; bnet_fsend(dir, _("3001 Device %s unmounted.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { + } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->dev_blocked == BST_WRITING_LABEL) { + } else if (dev->dev_blocked == BST_WRITING_LABEL) { bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->is_busy()) { - send_dir_busy_message(dir, dev); - } else { /* device not being used */ + } else if (dev->is_busy()) { + send_dir_busy_message(dir, dev); + } else { /* device not being used */ Dmsg0(90, "Device not in use, unmounting\n"); - /* On FreeBSD, I am having ASSERT() failures in block_device() - * and I can only imagine that the thread id that we are - * leaving in no_wait_id is being re-used. So here, - * we simply do it by hand. Gross, but a solution. - */ - /* block_device(dev, BST_UNMOUNTED); replace with 2 lines below */ - dev->dev_blocked = BST_UNMOUNTED; - dev->no_wait_id = 0; - open_dev(dev, NULL, 0); /* fake open for close */ - offline_or_rewind_dev(dev); - force_close_dev(dev); + /* On FreeBSD, I am having ASSERT() failures in block_device() + * and I can only imagine that the thread id that we are + * leaving in no_wait_id is being re-used. So here, + * we simply do it by hand. Gross, but a solution. + */ + /* block_device(dev, BST_UNMOUNTED); replace with 2 lines below */ + dev->dev_blocked = BST_UNMOUNTED; + dev->no_wait_id = 0; + open_dev(dev, NULL, 0); /* fake open for close */ + offline_or_rewind_dev(dev); + force_close_dev(dev); bnet_fsend(dir, _("3002 Device %s unmounted.\n"), - dev->print_name()); - } - V(dev->mutex); + dev->print_name()); + } + V(dev->mutex); } else { bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str()); } @@ -729,36 +729,36 @@ static bool release_cmd(JCR *jcr) if (sscanf(dir->msg, "release %127s", devname.c_str()) == 1) { dev = find_device(jcr, devname); if (dev) { - P(dev->mutex); /* Use P to avoid indefinite block */ - if (!dev->is_open()) { + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!dev->is_open()) { Dmsg0(90, "Device already released\n"); bnet_fsend(dir, _("3911 Device %s already released.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP || - dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) { + } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP || + dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) { Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, - dev->dev_blocked); + dev->dev_blocked); bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { + } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->dev_blocked == BST_WRITING_LABEL) { + } else if (dev->dev_blocked == BST_WRITING_LABEL) { bnet_fsend(dir, _("3914 Device %s is being labeled.\n"), - dev->print_name()); + dev->print_name()); - } else if (dev->is_busy()) { - send_dir_busy_message(dir, dev); - } else { /* device not being used */ + } else if (dev->is_busy()) { + send_dir_busy_message(dir, dev); + } else { /* device not being used */ Dmsg0(90, "Device not in use, unmounting\n"); - release_volume(jcr->dcr); + release_volume(jcr->dcr); bnet_fsend(dir, _("3012 Device %s released.\n"), - dev->print_name()); - } - V(dev->mutex); + dev->print_name()); + } + V(dev->mutex); } else { bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str()); } @@ -796,28 +796,28 @@ static bool autochanger_cmd(JCR *jcr) dev = find_device(jcr, devname); dcr = jcr->dcr; if (dev) { - P(dev->mutex); /* Use P to avoid indefinite block */ - if (!dev_is_tape(dev)) { + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!dev_is_tape(dev)) { bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), - dev->print_name()); - } else if (!dev->is_open()) { - autochanger_cmd(dcr, dir, cmd); + dev->print_name()); + } else if (!dev->is_open()) { + autochanger_cmd(dcr, dir, cmd); /* Under certain "safe" conditions, we can steal the lock */ - } else if (dev->can_steal_lock()) { - autochanger_cmd(dcr, dir, cmd); - } else if (dev->is_busy()) { - send_dir_busy_message(dir, dev); - } else { /* device not being used */ - autochanger_cmd(dcr, dir, cmd); - } - V(dev->mutex); + } else if (dev->can_steal_lock()) { + autochanger_cmd(dcr, dir, cmd); + } else if (dev->is_busy()) { + send_dir_busy_message(dir, dev); + } else { /* device not being used */ + autochanger_cmd(dcr, dir, cmd); + } + V(dev->mutex); } else { bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str()); } } else { /* error on scanf */ pm_strcpy(jcr->errmsg, dir->msg); bnet_fsend(dir, _("3908 Error scanning autocharger list/slots command: %s\n"), - jcr->errmsg); + jcr->errmsg); } bnet_sig(dir, BNET_EOD); return true; @@ -836,19 +836,19 @@ static bool readlabel_cmd(JCR *jcr) if (sscanf(dir->msg, "readlabel %127s Slot=%d", devname.c_str(), &Slot) == 2) { dev = find_device(jcr, devname); if (dev) { - P(dev->mutex); /* Use P to avoid indefinite block */ - if (!dev->is_open()) { - read_volume_label(jcr, dev, Slot); - force_close_dev(dev); + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!dev->is_open()) { + read_volume_label(jcr, dev, Slot); + force_close_dev(dev); /* Under certain "safe" conditions, we can steal the lock */ - } else if (dev->can_steal_lock()) { - read_volume_label(jcr, dev, Slot); - } else if (dev->is_busy()) { - send_dir_busy_message(dir, dev); - } else { /* device not being used */ - read_volume_label(jcr, dev, Slot); - } - V(dev->mutex); + } else if (dev->can_steal_lock()) { + read_volume_label(jcr, dev, Slot); + } else if (dev->is_busy()) { + send_dir_busy_message(dir, dev); + } else { /* device not being used */ + read_volume_label(jcr, dev, Slot); + } + V(dev->mutex); } else { bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), devname.c_str()); } @@ -875,10 +875,10 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot) steal_device_lock(dev, &hold, BST_WRITING_LABEL); if (!try_autoload_device(jcr, Slot, "")) { - goto bail_out; /* error */ + goto bail_out; /* error */ } - dev->clear_labeled(); /* force read of label */ + dev->clear_labeled(); /* force read of label */ switch (read_dev_volume_label(dcr)) { case VOL_OK: /* DO NOT add quotes around the Volume name. It is scanned in the DIR */ @@ -887,7 +887,7 @@ static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot) break; default: bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device %s because:\n%s"), - dev->print_name(), jcr->errmsg); + dev->print_name(), jcr->errmsg); break; } @@ -913,8 +913,8 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName) for ( ; !dev->is_open(); ) { if (open_dev(dev, dcr->VolumeName, OPEN_READ_WRITE) < 0) { bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"), - dev->print_name(), dev->strerror()); - return false; + dev->print_name(), dev->strerror()); + return false; } } return true; @@ -924,9 +924,9 @@ static void send_dir_busy_message(BSOCK *dir, DEVICE *dev) { if (dev->can_read()) { bnet_fsend(dir, _("3911 Device %s is busy reading.\n"), - dev->print_name());; + dev->print_name());; } else { bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"), - dev->print_name(), dev->num_writers); + dev->print_name(), dev->num_writers); } } diff --git a/bacula/src/stored/dvd.c b/bacula/src/stored/dvd.c index 495ecefa89..47a7ba2bb9 100644 --- a/bacula/src/stored/dvd.c +++ b/bacula/src/stored/dvd.c @@ -1,7 +1,7 @@ /* * * dvd.c -- Routines specific to DVD devices (and - * possibly other removable hard media). + * possibly other removable hard media). * * Nicolas Boichat, MMV * @@ -38,7 +38,7 @@ void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name); /* Forward referenced functions */ static char *edit_device_codes_dev(DEVICE *dev, char *omsg, const char *imsg); static int do_mount_dev(DEVICE* dev, int mount, int dotimeout); -static int write_part(DEVICE *dev); +static int dvd_write_part(DEVICE *dev); /* @@ -49,17 +49,17 @@ void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name) char partnumber[20]; if (dev->is_dvd()) { - /* If we try to open the last part, just open it from disk, - * otherwise, open it from the spooling directory */ + /* If we try to open the last part, just open it from disk, + * otherwise, open it from the spooling directory */ if (dev->part < dev->num_parts) { - pm_strcpy(archive_name, dev->device->mount_point); + pm_strcpy(archive_name, dev->device->mount_point); } else { - /* Use the working directory if spool directory is not defined */ - if (dev->device->spool_directory) { - pm_strcpy(archive_name, dev->device->spool_directory); - } else { - pm_strcpy(archive_name, working_directory); - } + /* Use the working directory if spool directory is not defined */ + if (dev->device->spool_directory) { + pm_strcpy(archive_name, dev->device->spool_directory); + } else { + pm_strcpy(archive_name, working_directory); + } } } else { pm_strcpy(archive_name, dev->dev_name); @@ -88,7 +88,7 @@ int mount_dev(DEVICE* dev, int timeout) return 0; } else if (dev_cap(dev, CAP_REQMOUNT)) { return do_mount_dev(dev, 1, timeout); - } + } return 0; } @@ -135,14 +135,14 @@ static int do_mount_dev(DEVICE* dev, int mount, int dotimeout) { while ((status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results)) != 0) { if (--timeout > 0) { Dmsg2(40, "Device %s cannot be (un)mounted. Retrying... ERR=%s\n", dev->dev_name, results); - /* Sometimes the device cannot be mounted because it is already mounted. - * Try to unmount it, then remount it */ - if (mount) { + /* Sometimes the device cannot be mounted because it is already mounted. + * Try to unmount it, then remount it */ + if (mount) { Dmsg1(40, "Trying to unmount the device %s...\n", dev->dev_name); - do_mount_dev(dev, 0, 0); - } - bmicrosleep(1, 0); - continue; + do_mount_dev(dev, 0, 0); + } + bmicrosleep(1, 0); + continue; } free_pool_memory(results); Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->dev_name, results); @@ -207,11 +207,11 @@ int open_guess_name_dev(DEVICE *dev) /* If the device cannot be mounted, check if it is writable */ if (dev->free_space_errno >= 0) { Dmsg1(100, "open_guess_name_dev: device cannot be mounted, but it seems to be writable, returning 0. dev=%s\n", dev->dev_name); - return 0; + return 0; } else { Dmsg1(100, "open_guess_name_dev: device cannot be mounted, and is not writable, returning 0. dev=%s\n", dev->dev_name); - /* read_dev_volume_label_guess must now check dev->free_space_errno to understand that the media is not writable. */ - return 0; + /* read_dev_volume_label_guess must now check dev->free_space_errno to understand that the media is not writable. */ + return 0; } } @@ -230,16 +230,16 @@ int open_guess_name_dev(DEVICE *dev) entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100); while (1) { if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) { - dev->dev_errno = ENOENT; + dev->dev_errno = ENOENT; Dmsg2(29, "open_guess_name_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name); - closedir(dp); - return -1; + closedir(dp); + return -1; } ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry)); if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; + continue; } pm_strcpy(guessedname, dev->device->mount_point); @@ -249,16 +249,16 @@ int open_guess_name_dev(DEVICE *dev) pm_strcat(guessedname, entry->d_name); if (stat(guessedname.c_str(), &statp) < 0) { - berrno be; + berrno be; Dmsg3(29, "open_guess_name_dev: failed to stat %s (dev=%s), ERR=%s\n", - guessedname.c_str(), dev->dev_name, be.strerror()); - continue; + guessedname.c_str(), dev->dev_name, be.strerror()); + continue; } if (!S_ISREG(statp.st_mode) || (statp.st_size < 500)) { Dmsg2(100, "open_guess_name_dev: %s is not a regular file, or less than 500 bytes (dev=%s)\n", - guessedname.c_str(), dev->dev_name); - continue; + guessedname.c_str(), dev->dev_name); + continue; } /* Ok, we found a good file, remove the part extension if possible. */ @@ -266,25 +266,25 @@ int open_guess_name_dev(DEVICE *dev) if ((guessedname.c_str()[index] == '/') || (guessedname.c_str()[index] < '0') || (guessedname.c_str()[index] > '9')) { - break; - } + break; + } if (guessedname.c_str()[index] == '.') { guessedname.c_str()[index] = '\0'; - break; - } + break; + } } if ((stat(guessedname.c_str(), &statp) < 0) || (statp.st_size < 500)) { - /* The file with extension truncated does not exists or is too small, so use it with its extension. */ - berrno be; + /* The file with extension truncated does not exists or is too small, so use it with its extension. */ + berrno be; Dmsg3(100, "open_guess_name_dev: failed to stat %s (dev=%s), using the file with its extension, ERR=%s\n", - guessedname.c_str(), dev->dev_name, be.strerror()); - pm_strcpy(guessedname, dev->device->mount_point); + guessedname.c_str(), dev->dev_name, be.strerror()); + pm_strcpy(guessedname, dev->device->mount_point); if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') { pm_strcat(guessedname, "/"); - } - pm_strcat(guessedname, entry->d_name); - continue; + } + pm_strcat(guessedname, entry->d_name); + continue; } break; } @@ -299,12 +299,12 @@ int open_guess_name_dev(DEVICE *dev) berrno be; dev->dev_errno = errno; Dmsg3(29, "open_guess_name_dev: failed to open %s (dev=%s), ERR=%s\n", - guessedname.c_str(), dev->dev_name, be.strerror()); + guessedname.c_str(), dev->dev_name, be.strerror()); if (open_first_part(dev) < 0) { - berrno be; - dev->dev_errno = errno; + berrno be; + dev->dev_errno = errno; Mmsg1(&dev->errmsg, _("Could not open_first_part, ERR=%s\n"), be.strerror()); - Emsg0(M_FATAL, 0, dev->errmsg); + Emsg0(M_FATAL, 0, dev->errmsg); } return -1; } @@ -351,13 +351,13 @@ void update_free_space_dev(DEVICE* dev) char ed1[50]; if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) { Dmsg1(100, "Free space program run : %s\n", results); - free = str_to_int64(results); - if (free >= 0) { - dev->free_space = free; - dev->free_space_errno = 1; + free = str_to_int64(results); + if (free >= 0) { + dev->free_space = free; + dev->free_space_errno = 1; Mmsg0(dev->errmsg, ""); - break; - } + break; + } } dev->free_space = 0; dev->free_space_errno = -EPIPE; @@ -366,17 +366,17 @@ void update_free_space_dev(DEVICE* dev) if (--timeout > 0) { Dmsg4(40, "Cannot get free space on device %s. free_space=%s, " "free_space_errno=%d ERR=%s\n", dev->dev_name, - edit_uint64(dev->free_space, ed1), dev->free_space_errno, - dev->errmsg); - bmicrosleep(1, 0); - continue; + edit_uint64(dev->free_space, ed1), dev->free_space_errno, + dev->errmsg); + bmicrosleep(1, 0); + continue; } dev->dev_errno = -dev->free_space_errno; Dmsg4(40, "Cannot get free space on device %s. free_space=%s, " "free_space_errno=%d ERR=%s\n", - dev->dev_name, edit_uint64(dev->free_space, ed1), - dev->free_space_errno, dev->errmsg); + dev->dev_name, edit_uint64(dev->free_space, ed1), + dev->free_space_errno, dev->errmsg); break; } @@ -385,12 +385,12 @@ void update_free_space_dev(DEVICE* dev) return; } -static int write_part(DEVICE *dev) +static int dvd_write_part(DEVICE *dev) { - Dmsg1(29, "write_part: device is %s\n", dev->dev_name); + Dmsg1(29, "dvd_write_part: device is %s\n", dev->dev_name); if (unmount_dev(dev, 1) < 0) { - Dmsg0(29, "write_part: unable to unmount the device\n"); + Dmsg0(29, "dvd_write_part: unable to unmount the device\n"); } POOL_MEM ocmd(PM_FNAME); @@ -409,7 +409,7 @@ static int write_part(DEVICE *dev) */ timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2)); - Dmsg2(29, "write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout); + Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout); status = run_program_full_output(ocmd.c_str(), timeout, results); if (status != 0) { @@ -419,7 +419,7 @@ static int write_part(DEVICE *dev) return -1; } else { - Dmsg1(29, "write_part: command output=%s\n", results); + Dmsg1(29, "dvd_write_part: command output=%s\n", results); POOL_MEM archive_name(PM_FNAME); get_filename(dev, dev->VolCatInfo.VolCatName, archive_name); unlink(archive_name.c_str()); @@ -454,8 +454,8 @@ int open_next_part(DEVICE *dev) { dev->state &= ~ST_OPENED; if (dev->is_dvd() && (dev->part == dev->num_parts) && dev->can_append()) { - if (write_part(dev) < 0) { - return -1; + if (dvd_write_part(dev) < 0) { + return -1; } } @@ -476,25 +476,25 @@ int open_next_part(DEVICE *dev) { /* Check if the next part exists. */ if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) { Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str()); - pm_strcpy(archive_bkp_name, archive_name.c_str()); + pm_strcpy(archive_bkp_name, archive_name.c_str()); pm_strcat(archive_bkp_name, ".bak"); - unlink(archive_bkp_name.c_str()); - - /* First try to rename it */ - if (rename(archive_name.c_str(), archive_bkp_name.c_str()) < 0) { - berrno be; + unlink(archive_bkp_name.c_str()); + + /* First try to rename it */ + if (rename(archive_name.c_str(), archive_bkp_name.c_str()) < 0) { + berrno be; Dmsg3(29, "open_next_part can't rename %s to %s, ERR=%s\n", - archive_name.c_str(), archive_bkp_name.c_str(), be.strerror()); - /* Then try to unlink it */ - if (unlink(archive_name.c_str()) < 0) { - berrno be; - dev->dev_errno = errno; + archive_name.c_str(), archive_bkp_name.c_str(), be.strerror()); + /* Then try to unlink it */ + if (unlink(archive_name.c_str()) < 0) { + berrno be; + dev->dev_errno = errno; Mmsg2(&dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), - archive_name.c_str(), be.strerror()); - Emsg0(M_FATAL, 0, dev->errmsg); - return -1; - } - } + archive_name.c_str(), be.strerror()); + Emsg0(M_FATAL, 0, dev->errmsg); + return -1; + } + } } } @@ -547,84 +547,84 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) case SEEK_SET: Dmsg1(100, "lseek_dev SEEK_SET called %d\n", offset); if ((uint64_t)offset >= dev->part_start) { - if ((uint64_t)(offset - dev->part_start) < dev->part_size) { - /* We are staying in the current part, just seek */ - if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) { - return pos; - } else { - return pos + dev->part_start; - } - } else { - /* Load next part, and start again */ - if (open_next_part(dev) < 0) { + if ((uint64_t)(offset - dev->part_start) < dev->part_size) { + /* We are staying in the current part, just seek */ + if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) { + return pos; + } else { + return pos + dev->part_start; + } + } else { + /* Load next part, and start again */ + if (open_next_part(dev) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); - return -1; - } - return lseek_dev(dev, offset, SEEK_SET); - } + return -1; + } + return lseek_dev(dev, offset, SEEK_SET); + } } else { - /* pos < dev->part_start : - * We need to access a previous part, - * so just load the first one, and seek again - * until the right one is loaded */ - if (open_first_part(dev) < 0) { + /* pos < dev->part_start : + * We need to access a previous part, + * so just load the first one, and seek again + * until the right one is loaded */ + if (open_first_part(dev) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the first part\n"); - return -1; - } - return lseek_dev(dev, offset, SEEK_SET); + return -1; + } + return lseek_dev(dev, offset, SEEK_SET); } break; case SEEK_CUR: Dmsg1(100, "lseek_dev SEEK_CUR called %d\n", offset); if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) { - return pos; + return pos; } pos += dev->part_start; if (offset == 0) { - return pos; + return pos; } else { /* Not used in Bacula, but should work */ - return lseek_dev(dev, pos, SEEK_SET); + return lseek_dev(dev, pos, SEEK_SET); } break; case SEEK_END: Dmsg1(100, "lseek_dev SEEK_END called %d\n", offset); if (offset > 0) { /* Not used by bacula */ Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", offset); - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } if (dev->part == dev->num_parts) { /* The right part is already loaded */ - if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) { - return pos; - } else { - return pos + dev->part_start; - } + if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) { + return pos; + } else { + return pos + dev->part_start; + } } else { - /* Load the first part, then load the next until we reach the last one. - * This is the only way to be sure we compute the right file address. */ - /* Save previous openmode, and open all but last part read-only (useful for DVDs) */ - openmode = dev->openmode; - dev->openmode = OPEN_READ_ONLY; - - /* Works because num_parts > 0. */ - if (open_first_part(dev) < 0) { + /* Load the first part, then load the next until we reach the last one. + * This is the only way to be sure we compute the right file address. */ + /* Save previous openmode, and open all but last part read-only (useful for DVDs) */ + openmode = dev->openmode; + dev->openmode = OPEN_READ_ONLY; + + /* Works because num_parts > 0. */ + if (open_first_part(dev) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the first part\n"); - return -1; - } - while (dev->part < (dev->num_parts-1)) { - if (open_next_part(dev) < 0) { + return -1; + } + while (dev->part < (dev->num_parts-1)) { + if (open_next_part(dev) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); - return -1; - } - } - dev->openmode = openmode; - if (open_next_part(dev) < 0) { + return -1; + } + } + dev->openmode = openmode; + if (open_next_part(dev) < 0) { Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); - return -1; - } - return lseek_dev(dev, 0, SEEK_END); + return -1; + } + return lseek_dev(dev, 0, SEEK_END); } break; default: @@ -633,6 +633,37 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence) } } +bool dvd_close_job(DCR *dcr) +{ + DEVICE *dev = dcr->dev; + JCR *jcr = dcr->jcr; + bool ok = true; + + /* If the device is a dvd and WritePartAfterJob + * is set to yes, open the next part, so, in case of a device + * that requires mount, it will be written to the device. + */ + if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) { + Dmsg0(100, "Writing last part because write_part_after_job is set.\n"); + if (dev->part < dev->num_parts) { + Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), + dev->part, dev->num_parts, dev->print_name()); + dev->dev_errno = EIO; + ok = false; + } + + if (ok && (open_next_part(dev) < 0)) { + Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"), + dev->print_name(), strerror_dev(dev)); + dev->dev_errno = EIO; + ok = false; + } + + dev->VolCatInfo.VolCatParts = dev->num_parts; + } + return ok; +} + /* * Edit codes into (Un)MountCommand, Write(First)PartCommand @@ -658,34 +689,34 @@ static char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg) Dmsg1(800, "edit_device_codes: %s\n", imsg); for (p=imsg; *p; p++) { if (*p == '%') { - switch (*++p) { + switch (*++p) { case '%': str = "%"; - break; + break; case 'n': bsnprintf(add, sizeof(add), "%d", dev->part); - str = add; - break; + str = add; + break; case 'a': - str = dev->dev_name; - break; + str = dev->dev_name; + break; case 'm': - str = dev->device->mount_point; - break; + str = dev->device->mount_point; + break; case 'v': - str = archive_name.c_str(); - break; - default: + str = archive_name.c_str(); + break; + default: add[0] = '%'; - add[1] = *p; - add[2] = 0; - str = add; - break; - } + add[1] = *p; + add[2] = 0; + str = add; + break; + } } else { - add[0] = *p; - add[1] = 0; - str = add; + add[0] = *p; + add[1] = 0; + str = add; } Dmsg1(900, "add_str %s\n", str); pm_strcat(&omsg, (char *)str); diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index 8d6ab2e414..4dc568b35e 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -42,7 +42,7 @@ static bool use_storage_cmd(JCR *jcr); static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s " "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " "SpoolData=%d WritePartAfterJob=%d NewVol=%d\n"; -static char use_storage[] = "use storage media_type=%127s " +static char use_storage[] = "use storage=%127s media_type=%127s " "pool_name=%127s pool_type=%127s append=%d\n"; static char use_device[] = "use device=%127s\n"; //static char query_device[] = "query device=%127s"; @@ -261,9 +261,22 @@ void handle_filed_connection(BSOCK *fd, char *job_name) * Ensure that the device exists and is opened, then store * the media and pool info in the JCR. */ +class DIRSTORE { +public: + alist *device; + char name[MAX_NAME_LENGTH]; + char media_type[MAX_NAME_LENGTH]; + char pool_name[MAX_NAME_LENGTH]; + char pool_type[MAX_NAME_LENGTH]; +}; + +class DIRDEVICE { + alist *device; +}; + static bool use_storage_cmd(JCR *jcr) { - POOL_MEM dev_name, media_type, pool_name, pool_type; + POOL_MEM store_name, dev_name, media_type, pool_name, pool_type; BSOCK *dir = jcr->dir_bsock; DEVRES *device; AUTOCHANGER *changer; @@ -275,9 +288,11 @@ static bool use_storage_cmd(JCR *jcr) * use_device for each device that it wants to use. */ Dmsg1(100, "msg); - ok = sscanf(dir->msg, use_storage, media_type.c_str(), - pool_name.c_str(), pool_type.c_str(), &append) == 4; + ok = sscanf(dir->msg, use_storage, store_name.c_str(), + media_type.c_str(), pool_name.c_str(), + pool_type.c_str(), &append) == 5; if (ok) { + unbash_spaces(store_name); unbash_spaces(media_type); unbash_spaces(pool_name); unbash_spaces(pool_type); diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 4e64cc54c7..784923a899 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -127,6 +127,10 @@ uint32_t dev_block(DEVICE *dev); uint32_t dev_file(DEVICE *dev); bool dev_is_tape(DEVICE *dev); +/* From dvd.c */ +bool dvd_close_job(DCR *dcr); + + /* From device.c */ bool open_device(DCR *dcr); bool first_open_device(DEVICE *dev); diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 818cfe9a70..e6149b4a49 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -39,15 +39,15 @@ void terminate_stored(int sig); static void check_config(); -extern "C" void *device_allocation(void *arg); +extern "C" void *device_initialization(void *arg); #define CONFIG_FILE "bacula-sd.conf" /* Default config file */ /* Global variables exported */ char OK_msg[] = "3000 OK\n"; char TERM_msg[] = "3999 Terminate\n"; -STORES *me = NULL; /* our Global resource */ -bool forge_on = false; /* proceed inspite of I/O errors */ +STORES *me = NULL; /* our Global resource */ +bool forge_on = false; /* proceed inspite of I/O errors */ pthread_mutex_t device_release_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t wait_device_release = PTHREAD_COND_INITIALIZER; @@ -59,7 +59,7 @@ char *configfile; /* Global static variables */ static int foreground = 0; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static workq_t dird_workq; /* queue for processing connections */ +static workq_t dird_workq; /* queue for processing connections */ static void usage() @@ -105,7 +105,7 @@ int main (int argc, char *argv[]) /* Sanity checks */ if (TAPE_BSIZE % B_DEV_BSIZE != 0 || TAPE_BSIZE / B_DEV_BSIZE == 0) { Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n", - TAPE_BSIZE, B_DEV_BSIZE); + TAPE_BSIZE, B_DEV_BSIZE); } if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) { Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE); @@ -114,51 +114,51 @@ int main (int argc, char *argv[]) while ((ch = getopt(argc, argv, "c:d:fg:pstu:v?")) != -1) { switch (ch) { case 'c': /* configuration 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; + debug_level = atoi(optarg); + if (debug_level <= 0) { + debug_level = 1; + } + break; case 'f': /* run in foreground */ - foreground = TRUE; - break; + foreground = TRUE; + break; case 'g': /* set group id */ - gid = optarg; - break; + gid = optarg; + break; case 'p': /* proceed in spite of I/O errors */ - forge_on = true; - break; + forge_on = true; + break; case 's': /* no signals */ - no_signals = TRUE; - break; + no_signals = TRUE; + break; case 't': - test_config = TRUE; - break; + test_config = TRUE; + break; case 'u': /* set uid */ - uid = optarg; - break; + uid = optarg; + break; case 'v': /* verbose */ - verbose++; - break; + verbose++; + break; case '?': default: - usage(); - break; + usage(); + break; } } argc -= optind; @@ -166,7 +166,7 @@ int main (int argc, char *argv[]) if (argc) { if (configfile != NULL) { - free(configfile); + free(configfile); } configfile = bstrdup(*argv); argc--; @@ -191,8 +191,8 @@ int main (int argc, char *argv[]) } if (!foreground) { - daemon_start(); /* become daemon */ - init_stack_dump(); /* pick up new pid */ + daemon_start(); /* become daemon */ + init_stack_dump(); /* pick up new pid */ } create_pid_file(me->pid_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs)); @@ -217,13 +217,13 @@ int main (int argc, char *argv[]) /* * Start the device allocation thread */ - if (pthread_create(&thid, NULL, device_allocation, NULL) != 0) { + if (pthread_create(&thid, NULL, device_initialization, NULL) != 0) { Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), strerror(errno)); } - start_watchdog(); /* start watchdog thread */ + start_watchdog(); /* start watchdog thread */ - init_jcr_subsystem(); /* start JCR watchdogs etc. */ + init_jcr_subsystem(); /* start JCR watchdogs etc. */ /* * Sleep a bit to give device thread a chance to lock the resource @@ -233,8 +233,8 @@ int main (int argc, char *argv[]) /* Single server used for Director and File daemon */ bnet_thread_server(me->sdaddrs, me->max_concurrent_jobs * 2 + 1, - &dird_workq, handle_connection_request); - exit(1); /* to keep compiler quiet */ + &dird_workq, handle_connection_request); + exit(1); /* to keep compiler quiet */ } /* Return a new Session Id */ @@ -259,39 +259,39 @@ static void check_config() if (!me) { UnlockRes(); Jmsg1(NULL, M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"), - configfile); + configfile); } - my_name_is(0, (char **)NULL, me->hdr.name); /* Set our real name */ + my_name_is(0, (char **)NULL, me->hdr.name); /* Set our real name */ if (GetNextRes(R_STORAGE, (RES *)me) != NULL) { UnlockRes(); Jmsg1(NULL, M_ERROR_TERM, 0, _("Only one Storage resource permitted in %s\n"), - configfile); + configfile); } if (GetNextRes(R_DIRECTOR, NULL) == NULL) { UnlockRes(); Jmsg1(NULL, M_ERROR_TERM, 0, _("No Director resource defined in %s. Cannot continue.\n"), - configfile); + configfile); } if (GetNextRes(R_DEVICE, NULL) == NULL){ UnlockRes(); Jmsg1(NULL, M_ERROR_TERM, 0, _("No Device resource defined in %s. Cannot continue.\n"), - configfile); + configfile); } if (!me->messages) { me->messages = (MSGS *)GetNextRes(R_MSGS, NULL); if (!me->messages) { Jmsg1(NULL, M_ERROR_TERM, 0, _("No Messages resource defined in %s. Cannot continue.\n"), - configfile); + configfile); } } - close_msg(NULL); /* close temp message handler */ + close_msg(NULL); /* close temp message handler */ init_msg(NULL, me->messages); /* open daemon message handler */ if (!me->working_directory) { Jmsg1(NULL, M_ERROR_TERM, 0, _("No Working Directory defined in %s. Cannot continue.\n"), - configfile); + configfile); } set_working_directory(me->working_directory); @@ -300,25 +300,25 @@ static void check_config() DEVRES *device; char *media_type = NULL; foreach_alist(device, changer->device) { - if (media_type == NULL) { - media_type = device->media_type; - continue; - } - if (strcmp(media_type, device->media_type) != 0) { - Jmsg(NULL, M_ERROR_TERM, 0, + if (media_type == NULL) { + media_type = device->media_type; + continue; + } + if (strcmp(media_type, device->media_type) != 0) { + Jmsg(NULL, M_ERROR_TERM, 0, _("Media Type not the same for all devices in changer %s. Cannot continue.\n"), - changer->hdr.name); - } - /* - * If the device does not have a changer name or changer command - * defined, used the one from the Autochanger resource - */ - if (!device->changer_name) { - device->changer_name = bstrdup(changer->changer_name); - } - if (!device->changer_command) { - device->changer_command = bstrdup(changer->changer_command); - } + changer->hdr.name); + } + /* + * If the device does not have a changer name or changer command + * defined, used the one from the Autochanger resource + */ + if (!device->changer_name) { + device->changer_name = bstrdup(changer->changer_name); + } + if (!device->changer_command) { + device->changer_command = bstrdup(changer->changer_command); + } } } UnlockRes(); @@ -329,7 +329,7 @@ static void check_config() * once at startup in a separate thread. */ extern "C" -void *device_allocation(void *arg) +void *device_initialization(void *arg) { DEVRES *device; @@ -342,36 +342,36 @@ void *device_allocation(void *arg) Dmsg1(10, "SD init done %s\n", device->device_name); if (!device->dev) { Jmsg1(NULL, M_ERROR, 0, _("Could not initialize %s\n"), device->device_name); - continue; + continue; } if (device->cap_bits & CAP_ALWAYSOPEN) { Dmsg1(20, "calling first_open_device %s\n", device->device_name); - if (!first_open_device(device->dev)) { + if (!first_open_device(device->dev)) { Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), device->device_name); - } + } } if (device->cap_bits & CAP_AUTOMOUNT && device->dev && - device->dev->is_open()) { - JCR *jcr; - DCR *dcr; - jcr = new_jcr(sizeof(JCR), stored_free_jcr); - jcr->JobType = JT_SYSTEM; - /* Initialize FD start condition variable */ - int errstat = pthread_cond_init(&jcr->job_start_wait, NULL); - if (errstat != 0) { + device->dev->is_open()) { + JCR *jcr; + DCR *dcr; + jcr = new_jcr(sizeof(JCR), stored_free_jcr); + jcr->JobType = JT_SYSTEM; + /* Initialize FD start condition variable */ + int errstat = pthread_cond_init(&jcr->job_start_wait, NULL); + if (errstat != 0) { Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat)); - } - dcr = new_dcr(jcr, device->dev); - switch (read_dev_volume_label(dcr)) { - case VOL_OK: - memcpy(&dcr->dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dcr->dev->VolCatInfo)); - break; - default: + } + dcr = new_dcr(jcr, device->dev); + switch (read_dev_volume_label(dcr)) { + case VOL_OK: + memcpy(&dcr->dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dcr->dev->VolCatInfo)); + break; + default: Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"), device->device_name); - break; - } - free_jcr(jcr); + break; + } + free_jcr(jcr); } } UnlockRes(); @@ -386,12 +386,12 @@ void terminate_stored(int sig) DEVRES *device; JCR *jcr; - if (in_here) { /* prevent loops */ + if (in_here) { /* prevent loops */ exit(1); } in_here = true; - if (sig == SIGTERM) { /* normal shutdown request? */ + if (sig == SIGTERM) { /* normal shutdown request? */ /* * This is a normal shutdown request. We wiffle through * all open jobs canceling them and trying to wake @@ -400,27 +400,27 @@ void terminate_stored(int sig) */ lock_jcr_chain(); foreach_jcr(jcr) { - BSOCK *fd; - free_locked_jcr(jcr); - if (jcr->JobId == 0) { - continue; /* ignore console */ - } - set_jcr_job_status(jcr, JS_Canceled); - fd = jcr->file_bsock; - if (fd) { - fd->timed_out = true; + BSOCK *fd; + free_locked_jcr(jcr); + if (jcr->JobId == 0) { + continue; /* ignore console */ + } + set_jcr_job_status(jcr, JS_Canceled); + fd = jcr->file_bsock; + if (fd) { + fd->timed_out = true; Dmsg1(100, "term_stored killing JobId=%d\n", jcr->JobId); - pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL); - /* ***FIXME*** wiffle through all dcrs */ - if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->dev_blocked) { - pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol); - pthread_cond_broadcast(&wait_device_release); - } - bmicrosleep(0, 50000); - } + pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL); + /* ***FIXME*** wiffle through all dcrs */ + if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->dev_blocked) { + pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol); + pthread_cond_broadcast(&wait_device_release); + } + bmicrosleep(0, 50000); + } } unlock_jcr_chain(); - bmicrosleep(0, 500000); /* give them 1/2 sec to clean up */ + bmicrosleep(0, 500000); /* give them 1/2 sec to clean up */ } write_state_file(me->working_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs)); @@ -431,7 +431,7 @@ void terminate_stored(int sig) LockRes(); foreach_res(device, R_DEVICE) { if (device->dev) { - term_dev(device->dev); + term_dev(device->dev); } } UnlockRes(); @@ -447,6 +447,6 @@ void terminate_stored(int sig) stop_watchdog(); close_memory_pool(); - sm_dump(false); /* dump orphaned buffers */ + sm_dump(false); /* dump orphaned buffers */ exit(sig); } diff --git a/bacula/src/version.h b/bacula/src/version.h index 67af8ce40d..df1bd94f5a 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #undef VERSION -#define VERSION "1.37.10" -#define BDATE "28 March 2005" -#define LSMDATE "29Mar05" +#define VERSION "1.37.11" +#define BDATE "31 March 2005" +#define LSMDATE "31Mar05" /* Debug flags */ #undef DEBUG