From 60603562ad67562d38e750987a1d59234b40d50c Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 17 Jul 2002 16:42:02 +0000 Subject: [PATCH] Add auto-changer support -- kes17Jul02 git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@58 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/cats/make_mysql_tables.in | 2 +- bacula/src/cats/sql_find.c | 3 +- bacula/src/cats/sql_get.c | 5 +- bacula/src/dird/catreq.c | 2 +- bacula/src/dird/ua_cmds.c | 41 +++++++-- bacula/src/lib/protos.h | 1 + bacula/src/lib/util.c | 131 +++++++++++++++++++++++++++ bacula/src/stored/askdir.c | 3 +- bacula/src/stored/dev.c | 2 +- bacula/src/stored/device.c | 95 +++++++++++++++---- bacula/src/stored/stored_conf.c | 4 + bacula/src/stored/stored_conf.h | 2 + bacula/src/version.h | 4 +- 13 files changed, 263 insertions(+), 32 deletions(-) diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index d02c9e128a..22acc913f7 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -89,7 +89,7 @@ CREATE TABLE JobMedia ( CREATE TABLE Media ( MediaId INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, VolumeName TINYBLOB NOT NULL, - Slot INTEGER NOT NULL, + Slot INTEGER NOT NULL DEFAULT 0, PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool, MediaType TINYBLOB NOT NULL, FirstWritten DATETIME NOT NULL, diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 7da8ecd7b7..45d75e14a3 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -204,7 +204,7 @@ db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr) db_lock(mdb); Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\ -VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes \ +VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,Slot \ FROM Media WHERE PoolId=%d AND MediaType=\"%s\" AND VolStatus=\"%s\" \ ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); @@ -245,6 +245,7 @@ ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); mr->VolWrites = atoi(row[8]); mr->VolMaxBytes = (uint64_t)strtod(row[9], NULL); mr->VolCapacityBytes = (uint64_t)strtod(row[10], NULL); + mr->Slot = atoi(row[11]); sql_free_result(mdb); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 8d26335ffa..2a7e46225b 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -584,12 +584,12 @@ int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr) if (mr->MediaId != 0) { /* find by id */ Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\ VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\ -MediaType,VolStatus,PoolId,VolRetention,Recycle \ +MediaType,VolStatus,PoolId,VolRetention,Recycle,Slot \ FROM Media WHERE MediaId=%d", mr->MediaId); } else { /* find by name */ Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\ VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\ -MediaType,VolStatus,PoolId,VolRetention,Recycle \ +MediaType,VolStatus,PoolId,VolRetention,Recycle,Slot \ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); } @@ -620,6 +620,7 @@ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); mr->PoolId = atoi(row[13]); mr->VolRetention = (btime_t)strtod(row[14], NULL); mr->Recycle = atoi(row[15]); + mr->Slot = atoi(row[16]); stat = mr->MediaId; } } else { diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 2a249361e1..cf4d2dc854 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -147,7 +147,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) bnet_fsend(bs, OK_media, mr.VolumeName, mr.VolJobs, mr.VolFiles, mr.VolBlocks, mr.VolBytes, mr.VolMounts, mr.VolErrors, mr.VolWrites, mr.VolMaxBytes, mr.VolCapacityBytes, - mr.VolStatus); + mr.VolStatus, mr.Slot); } else { Dmsg4(100, "get_media_record PoolId=%d wanted %d, Status=%s, \ MediaType=%s\n", mr.PoolId, jcr->PoolId, mr.VolStatus, mr.MediaType); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 6b4e399eaf..83228fff2b 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -592,17 +592,18 @@ static int update_volume(UAContext *ua) } strcpy(mr.VolumeName, ua->cmd); } - mr.MediaId = 0; - if (!db_get_media_record(ua->db, &mr)) { - bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName); - return 0; - } for (int done=0; !done; ) { + mr.MediaId = 0; + if (!db_get_media_record(ua->db, &mr)) { + bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName); + return 0; + } start_prompt(ua, _("Parameters to modify:\n")); add_prompt(ua, _("Volume Status")); add_prompt(ua, _("Volume Retention Period")); add_prompt(ua, _("Recycle Flag")); + add_prompt(ua, _("Slot")); add_prompt(ua, _("Done")); switch (do_prompt(ua, _("Select paramter to modify"), NULL)) { case 0: /* Volume Status */ @@ -670,9 +671,37 @@ static int update_volume(UAContext *ua) } free_pool_memory(query); break; + + case 3: /* Slot */ + int slot; + bsendmsg(ua, _("Current value is: %d\n"), mr.Slot); + if (!get_cmd(ua, _("Enter new Slot: "))) { + return 0; + } + slot = atoi(ua->cmd); + if (slot < 0) { + bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n")); + break; + } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) { + bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"), + pr.MaxVols); + break; + } + query = get_pool_memory(PM_MESSAGE); + Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%d", + slot, mr.MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, "New value is: %d\n", slot); + } + free_pool_memory(query); + break; + default: /* Done or error */ - return 0; + bsendmsg(ua, "Selection done.\n"); + return 1; } } return 1; diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 65b2d8247e..c461784ce1 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -151,6 +151,7 @@ int string_to_btime (char *str, btime_t *value); char *edit_btime (btime_t val, char *buf); void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); void add_str_to_pool_mem (POOLMEM **base, char **msg, char *str); +int run_program (char *prog, int wait, POOLMEM *results); /* diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index 0d467d7c54..44f4e026a8 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -547,3 +547,134 @@ int do_shell_expansion(char *name) #endif } + +#define MAX_ARGV 100 +static char *bargv[MAX_ARGV]; +static int bargc; +static void build_argc_argv(char *cmd); + +int run_program(char *prog, int wait, POOLMEM *results) +{ + int stat = ETIME; + int chldstatus = 0; + pid_t pid1, pid2; + int pfd[2]; + int i; + + + build_argc_argv(prog); +#ifdef lots_of_debug + printf("argc=%d\n", bargc); + for (i=0; iVolCatName); strcpy(jcr->VolumeName, vol->VolCatName); /* set desired VolumeName */ - Dmsg1(200, "Got Volume=%s\n", vol->VolCatName); + Dmsg2(030, "do_reqest_vol_info got slot=%d Volume=%s\n", + vol->Slot, vol->VolCatName); return 1; } diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 207637983a..286de5a63e 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -579,7 +579,7 @@ int offline_dev(DEVICE *dev) dev->dev_name, strerror(dev->dev_errno)); return 0; } - Dmsg1(000, "Offlined device %s\n", dev->dev_name); + Dmsg1(100, "Offlined device %s\n", dev->dev_name); return 1; } diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 20abc6c493..118862f448 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -53,6 +53,7 @@ /* Forward referenced functions */ static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *label_blk, int release); +static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd); extern char my_name[]; extern int debug_level; @@ -178,7 +179,7 @@ int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) if (!dev_is_tape(dev)) { close_dev(dev); } - /******FIXME**** send read volume info to director */ + /******FIXME**** send read volume usage statistics to director */ } else if (dev->num_writers > 0) { dev->num_writers--; @@ -220,11 +221,15 @@ int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) */ static int mount_next_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release) { - int recycle, ask; + int recycle, ask, retry = 0; Dmsg0(90, "Enter mount_next_volume()\n"); mount_next_vol: + if (retry++ > 5) { + Mmsg0(&dev->errmsg, _("Too many retries.\n")); + return 0; + } if (job_cancelled(jcr)) { Mmsg0(&dev->errmsg, _("Job cancelled.\n")); return 0; @@ -281,17 +286,72 @@ mount_next_vol: jcr->VolFirstFile = 0; /* first update of Vol FileIndex */ for ( ;; ) { + int slot = jcr->VolCatInfo.Slot; + + /* + * Handle autoloaders here. If we cannot autoload it, we + * will fall through to ask the sysop. + */ + if (dev->capabilities && CAP_AUTOCHANGER && slot <= 0) { + if (dir_find_next_appendable_volume(jcr)) { + slot = jcr->VolCatInfo.Slot; + } + } + Dmsg1(100, "Want changer slot=%d\n", slot); + + if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) { + uint32_t timeout = jcr->device->changer_timeout; + POOLMEM *changer, *results; + int status, loaded; + + results = get_pool_memory(PM_MESSAGE); + changer = get_pool_memory(PM_FNAME); + /* Find out what is loaded */ + changer = edit_device_codes(jcr, changer, jcr->device->changer_command, + "loaded"); + status = run_program(changer, timeout, results); + if (status == 0) { + loaded = atoi(results); + } else { + loaded = -1; /* force unload */ + } + Dmsg1(100, "loaded=%s\n", results); - Dmsg1(000, "Have changer. Dev=%s\n", NPRT(jcr->device->changer_name)); - if (ask) { - if (dev->capabilities && CAP_AUTOCHANGER) { - Dmsg1(000, "Have changer. Dev=%s\n", NPRT(jcr->device->changer_name)); - /*** ****FIXME**** add changer code here */ + /* If bad status or tape we want is not loaded, load it. */ + if (status != 0 || loaded != slot) { + if (dev->capabilities & CAP_OFFLINEUNMOUNT) { + offline_dev(dev); + } + /* We are going to load a new tape, so close the device */ + force_close_dev(dev); + if (loaded != 0) { /* must unload drive */ + Dmsg0(100, "Doing changer unload.\n"); + changer = edit_device_codes(jcr, changer, + jcr->device->changer_command, "unload"); + status = run_program(changer, timeout, NULL); + Dmsg1(100, "unload status=%d\n", status); + } + /* + * Load the desired cassette + */ + Dmsg1(100, "Doing changer load slot %d\n", slot); + changer = edit_device_codes(jcr, changer, + jcr->device->changer_command, "load"); + status = run_program(changer, timeout, NULL); + Dmsg2(100, "load slot %d status=%d\n", slot, status); } - if (!dir_ask_sysop_to_mount_next_volume(jcr, dev)) { - return 0; /* error return */ + free_pool_memory(changer); + free_pool_memory(results); + Dmsg1(100, "After changer, status=%d\n", status); + if (status == 0) { /* did we succeed? */ + ask = 0; /* yes, got vol, no need to ask sysop */ } } + + + if (ask && !dir_ask_sysop_to_mount_next_volume(jcr, dev)) { + return 0; /* error return */ + } Dmsg1(200, "want vol=%s\n", jcr->VolumeName); /* Open device */ @@ -732,7 +792,7 @@ void unblock_device(DEVICE *dev) /* - * Edit codes into ChangerDevice + * Edit codes into ChangerCommand * %% = % * %a = archive device name * %c = changer device name @@ -749,9 +809,10 @@ void unblock_device(DEVICE *dev) * cmd = command string (load, unload, ...) * */ -char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) +static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) { - char *p, *o, *str; + char *p, *o; + const char *str; char add[20]; Dmsg1(200, "edit_job_codes: %s\n", imsg); @@ -769,17 +830,17 @@ char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) str = jcr->device->dev->dev_name; break; case 'c': - str = jcr->device->changer_name; + str = NPRT(jcr->device->changer_name); break; case 'o': - str = cmd; + str = NPRT(cmd); break; case 's': - sprintf(add, "%d", jcr->device->dev->VolCatInfo.Slot - 1); + sprintf(add, "%d", jcr->VolCatInfo.Slot - 1); str = add; break; case 'S': - sprintf(add, "%d", jcr->device->dev->VolCatInfo.Slot); + sprintf(add, "%d", jcr->VolCatInfo.Slot); str = add; break; case 'j': /* Job name */ @@ -810,7 +871,7 @@ char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) str = add; } Dmsg1(200, "add_str %s\n", str); - add_str_to_pool_mem(&omsg, &o, str); + add_str_to_pool_mem(&omsg, &o, (char *)str); *o = 0; Dmsg1(200, "omsg=%s\n", omsg); } diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 36acfce9bb..1e2f58117f 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -95,6 +95,8 @@ static struct res_items dev_items[] = { {"alwaysopen", store_yesno, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1}, {"autochanger", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0}, {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0}, + {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0}, + {"changertimeout", store_pint, ITEM(res_dev.changer_timeout), 0, ITEM_DEFAULT, 60}, {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 1}, {"maximumrewindwait", store_pint, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60}, {"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0}, @@ -259,6 +261,8 @@ void free_resource(int type) free(res->res_dev.device_name); if (res->res_dev.changer_name) free(res->res_dev.changer_name); + if (res->res_dev.changer_command) + free(res->res_dev.changer_command); break; case R_MSGS: if (res->res_msgs.mail_cmd) diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 8983a82036..8e8c9cca54 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -73,7 +73,9 @@ struct s_res_dev { char *media_type; /* User assigned media type */ char *device_name; /* Archive device name */ char *changer_name; /* Changer device name */ + char *changer_command; /* Changer command -- external program */ int cap_bits; /* Capabilities of this device */ + uint32_t changer_timeout; /* Changer timeout */ uint32_t max_rewind_wait; /* maximum secs to wait for rewind */ uint32_t min_block_size; /* min block size */ uint32_t max_block_size; /* max block size */ diff --git a/bacula/src/version.h b/bacula/src/version.h index f2cb7d0f1b..5a6f3c2df8 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.23" #define VSTRING "1" -#define DATE "15 July 2002" -#define LSMDATE "15Jul02" +#define DATE "16 July 2002" +#define LSMDATE "16Jul02" /* Debug flags */ #define DEBUG 1 -- 2.39.5