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
- 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.
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
- 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.
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;
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 {
db_unlock(mdb);
return 0;
}
- pr->PoolId = atoi(row[0]);
+ pr->PoolId = str_to_int64(row[0]);
sql_free_result(mdb);
}
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);
/*
* 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
*
/* 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"
* (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)
{
/*
* Get a File record
* Returns: 0 on failure
- * 1 on success
+ * 1 on success
*
* DO NOT use Jmsg in this routine.
*
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 {
/* 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)
*/
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);
}
/* 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)
*/
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);
}
/*
* 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)
{
"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]);
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));
/*
* 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
*/
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 {
/*
* 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
*/
"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)) {
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);
}
* 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)
{
* 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[])
{
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;
* 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[])
{
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;
* 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)
{
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"));
}
} 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;
}
* 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)
{
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);
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"));
}
* 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)
{
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 {
* 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)
{
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);
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 {
* 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)
{
* 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[])
{
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;
/* 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)
{
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,"
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;
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
*/
} else {
bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
+ Dmsg1(400, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
}
/*
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));
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();
* 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))
{
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));
* Destroy the job queue
*
* Returns: 0 on success
- * errno on failure
+ * errno on failure
*/
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
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) {
/* 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;
}
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;
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;
/* 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);
}
}
foreach_dlist(item, jq->waiting_jobs) {
if (jcr == item->jcr) {
- found = true;
- break;
+ found = true;
+ break;
}
}
if (!found) {
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;
{
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;
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,
*/
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 */
* 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 */
* 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)
{
* 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) {
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";
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;
*/
// 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 */
#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)
{
/* 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;
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:
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];
}
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;
}
* 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;
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) {
}
}
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 {
*/
/*
- 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
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) {
return 0;
}
}
- Dmsg1(800, "Using catalog=%s\n", catalog_name);
+ Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
if (job_name) {
/* Find Job */
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);
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) {
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");
count++;
}
}
+ ff->linklist = NULL;
return count;
}
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
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
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);
}
-/* #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,
*/
/*
- 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
EVENT_HANDLER *generate_event;
#ifdef HAVE_PYTHON
+
#undef _POSIX_C_SOURCE
#include <Python.h>
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;
{
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);
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: */
} 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 */
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;
}
--- /dev/null
+/*
+ * 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
+};
* Initialize a read/write lock
*
* Returns: 0 on success
- * errno on failure
+ * errno on failure
*/
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)
{
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));
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;
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);
}
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);
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);
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);
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);
* 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;
}
* 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));
+ }
}
/*
* 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;
}
#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];
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;
}
* 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");
}
/*
* 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;
* 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))
{
}
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;
}
* Destroy a work queue
*
* Returns: 0 on success
- * errno on failure
+ * errno on failure
*/
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
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));
* 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)
{
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;
}
/* 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++;
}
for (prev=item=wq->first; item; item=item->next) {
if (item == work_item) {
- found = 1;
- break;
+ found = 1;
+ break;
}
prev = 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;
/* 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++;
}
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");
/*
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 */
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;
}
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;
+ }
+ }
}
}
}
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) {
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);
}
* 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)
{
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;
}
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;
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
*/
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;
}
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);
}
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;
}
/*
* 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)
{
*/
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 */
}
/*
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 */
}
/*
* 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.
*/
*/
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 */
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;
}
*/
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");
}
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.
*/
}
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);
*/
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;
}
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.
* 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;
}
/*
*/
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, "<filed: Header FilInx=%d stream=%d\n", file_index, stream);
if (!(file_index > 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;
}
}
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");
/* 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) {
} 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;
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
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 */
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;
}
}
#endif
+ /*
+ * Do write here
+ */
stat = write(dev->fd, block->buf, (size_t)wlen);
#ifdef DEBUG_BLOCK_ZEROING
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;
}
block->BlockNumber++;
/* Update dcr values */
- if (dev_state(dev, ST_TAPE)) {
+ if (dev->is_tape()) {
dcr->EndBlock = dev->EndBlock;
dcr->EndFile = dev->EndFile;
} else {
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;
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);
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;
}
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));
dev->block_num++;
/* Update dcr values */
- if (dev->state & ST_TAPE) {
+ if (dev->is_tape()) {
dcr->EndBlock = dev->EndBlock;
dcr->EndFile = dev->EndFile;
} else {
#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);
/* 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
}
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),
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
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 */
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 */
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 ||
};
/* 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; }
/* 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));
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;
}
* 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
*
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);
{"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 */
};
}
/*
* 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) {
*/
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 */
for (quit=false; !quit;) {
/* Read command */
if ((bnet_stat = bnet_recv(bs)) <= 0) {
- break; /* connection terminated */
+ break; /* connection terminated */
}
Dmsg1(199, "<dird: %s\n", bs->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;
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"));
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) {
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());
}
* 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;
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 */
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));
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);
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;
}
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 */
}
}
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());
}
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());
}
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());
}
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;
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());
}
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 */
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;
}
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;
{
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);
}
}
/*
*
* dvd.c -- Routines specific to DVD devices (and
- * possibly other removable hard media).
+ * possibly other removable hard media).
*
* Nicolas Boichat, MMV
*
/* 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);
/*
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);
return 0;
} else if (dev_cap(dev, CAP_REQMOUNT)) {
return do_mount_dev(dev, 1, timeout);
- }
+ }
return 0;
}
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);
/* 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;
}
}
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);
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. */
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;
}
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;
}
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;
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;
}
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);
*/
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) {
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());
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;
}
}
/* 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;
+ }
+ }
}
}
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:
}
}
+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
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);
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";
* 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;
* use_device for each device that it wants to use.
*/
Dmsg1(100, "<dird: %s", dir->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);
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);
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;
/* 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()
/* 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);
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;
if (argc) {
if (configfile != NULL) {
- free(configfile);
+ free(configfile);
}
configfile = bstrdup(*argv);
argc--;
}
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));
/*
* 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
/* 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 */
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);
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();
* once at startup in a separate thread.
*/
extern "C"
-void *device_allocation(void *arg)
+void *device_initialization(void *arg)
{
DEVRES *device;
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();
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
*/
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));
LockRes();
foreach_res(device, R_DEVICE) {
if (device->dev) {
- term_dev(device->dev);
+ term_dev(device->dev);
}
}
UnlockRes();
stop_watchdog();
close_memory_pool();
- sm_dump(false); /* dump orphaned buffers */
+ sm_dump(false); /* dump orphaned buffers */
exit(sig);
}
/* */
#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