X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fdircmd.c;h=e339602cf176613ffed70f5e62eea8e889363b32;hb=1a5f3848bea19e7965f9794d1330914ebfed790a;hp=47370524a1296ab52f3e7e06913d45cba8df1c5d;hpb=8fa2d4cce592cd35a0c9bccc7c99b3c8ce0f19a6;p=bacula%2Fbacula diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 47370524a1..e339602cf1 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -1,12 +1,12 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2001-2008 Free Software Foundation Europe e.V. + Copyright (C) 2001-2010 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public + modify it under the terms of version three of the GNU Affero General Public License as published by the Free Software Foundation and included in the file LICENSE. @@ -15,7 +15,7 @@ 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 + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -43,8 +43,6 @@ * * Kern Sibbald, May MMI * - * Version $Id$ - * */ #include "bacula.h" @@ -58,9 +56,11 @@ extern struct s_last_job last_job; extern bool init_done; /* Static variables */ -static char derrmsg[] = "3900 Invalid command\n"; +static char derrmsg[] = "3900 Invalid command:"; static char OKsetdebug[] = "3000 OK setdebug=%d\n"; static char invalid_cmd[] = "3997 Invalid command for a Director with Monitor directive enabled.\n"; +static char OK_bootstrap[] = "3000 OK bootstrap\n"; +static char ERROR_bootstrap[] = "3904 Error bootstrap\n"; /* Imported functions */ extern void terminate_child(); @@ -81,6 +81,7 @@ static bool setdebug_cmd(JCR *jcr); static bool cancel_cmd(JCR *cjcr); static bool mount_cmd(JCR *jcr); static bool unmount_cmd(JCR *jcr); +//static bool action_on_purge_cmd(JCR *jcr); static bool bootstrap_cmd(JCR *jcr); static bool changer_cmd(JCR *sjcr); static bool do_label(JCR *jcr, int relabel); @@ -116,6 +117,7 @@ static struct s_cmds cmds[] = { {"status", status_cmd, 1}, {".status", qstatus_cmd, 1}, {"unmount", unmount_cmd, 0}, +// {"action_on_purge", action_on_purge_cmd, 0}, {"use storage=", use_cmd, 0}, {"run", run_cmd, 0}, // {"query", query_cmd, 0}, @@ -150,7 +152,7 @@ void *handle_connection_request(void *arg) char tbuf[100]; if (bs->recv() <= 0) { - Emsg0(M_ERROR, 0, _("Connection request failed.\n")); + Emsg1(M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who()); bs->close(); return NULL; } @@ -160,7 +162,7 @@ void *handle_connection_request(void *arg) */ if (bs->msglen < 25 || bs->msglen > (int)sizeof(name)) { Dmsg1(000, "msg); - Emsg1(M_ERROR, 0, _("Invalid connection. Len=%d\n"), bs->msglen); + Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), bs->who(), bs->msglen); bs->close(); return NULL; } @@ -230,14 +232,16 @@ void *handle_connection_request(void *arg) Dmsg1(200, "Do command: %s\n", cmds[i].cmd); if (!cmds[i].func(jcr)) { /* do command */ quit = true; /* error, get out */ - Dmsg1(190, "Command %s reqeusts quit\n", cmds[i].cmd); + Dmsg1(190, "Command %s requests quit\n", cmds[i].cmd); } found = true; /* indicate command found */ break; } } if (!found) { /* command not found */ - bs->fsend(derrmsg); + POOL_MEM err_msg; + Mmsg(err_msg, "%s %s\n", derrmsg, bs->msg); + bs->fsend(err_msg.c_str()); break; } } @@ -303,14 +307,18 @@ static bool cancel_cmd(JCR *cjcr) } else { oldStatus = jcr->JobStatus; set_jcr_job_status(jcr, JS_Canceled); + Dmsg2(800, "Cancel JobId=%d %p\n", jcr->JobId, jcr); if (!jcr->authenticated && oldStatus == JS_WaitFD) { pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */ } if (jcr->file_bsock) { - bnet_sig(jcr->file_bsock, BNET_TERMINATE); + jcr->file_bsock->signal(BNET_TERMINATE); + jcr->file_bsock->set_terminated(); + Dmsg2(800, "Term bsock jid=%d %p\n", jcr->JobId, jcr); } else { /* Still waiting for FD to connect, release it */ pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */ + Dmsg2(800, "Signal FD connect jid=%d %p\n", jcr->JobId, jcr); } /* If thread waiting on mount, wake him */ if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) { @@ -323,7 +331,8 @@ static bool cancel_cmd(JCR *cjcr) Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId); pthread_cond_broadcast(&wait_device_release); } - Jmsg(jcr, M_INFO, 0, _("Job %s marked to be canceled.\n"), jcr->Job); + Jmsg(jcr, M_INFO, 0, _("JobId=%d Job=\"%s\" marked to be canceled.\n"), + (int)jcr->JobId, jcr->Job); dir->fsend(_("3000 Job %s marked to be canceled.\n"), jcr->Job); free_jcr(jcr); } @@ -457,9 +466,9 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, dev->truncating = true; /* let open() know we will truncate it */ } /* Set old volume name for open if relabeling */ - bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName)); + dcr->setVolCatName(volname); if (dev->open(dcr, mode) < 0) { - dir->fsend(_("3910 Unable to open device %s: ERR=%s\n"), + dir->fsend(_("3910 Unable to open device \"%s\": ERR=%s\n"), dev->print_name(), dev->bstrerror()); goto bail_out; } @@ -468,7 +477,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, label_status = read_dev_volume_label(dcr); /* Set new volume name */ - bstrncpy(dcr->VolCatInfo.VolCatName, newname, sizeof(dcr->VolCatInfo.VolCatName)); + dcr->setVolCatName(newname); switch(label_status) { case VOL_NAME_ERROR: case VOL_VERSION_ERROR: @@ -546,7 +555,7 @@ static bool read_label(DCR *dcr) ok = true; break; default: - dir->fsend(_("3902 Cannot mount Volume on Storage Device %s because:\n%s"), + dir->fsend(_("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s"), dev->print_name(), jcr->errmsg); ok = false; break; @@ -658,8 +667,9 @@ static bool mount_cmd(JCR *jcr) /* Someone is waiting, wake him */ Dmsg0(100, "Waiting for mount. Attempting to wake thread\n"); dev->set_blocked(BST_MOUNT); - dir->fsend("3001 OK mount. Device=%s\n", - dev->print_name()); + dir->fsend("3001 OK mount requested. %sDevice=%s\n", + slot>0?_("Specified slot ignored. "):"", + dev->print_name()); pthread_cond_broadcast(&dev->wait_next_vol); Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)dcr->jcr->JobId); pthread_cond_broadcast(&wait_device_release); @@ -673,7 +683,7 @@ static bool mount_cmd(JCR *jcr) } /* We freed the device, so reopen it and wake any waiting threads */ if (dev->open(dcr, OPEN_READ_ONLY) < 0) { - dir->fsend(_("3901 Unable to open device %s: ERR=%s\n"), + dir->fsend(_("3901 Unable to open device \"%s\": ERR=%s\n"), dev->print_name(), dev->bstrerror()); if (dev->blocked() == BST_UNMOUNTED) { /* We blocked the device, so unblock it */ @@ -693,10 +703,10 @@ static bool mount_cmd(JCR *jcr) dev->set_blocked(BST_MOUNT); } if (dev->is_labeled()) { - dir->fsend(_("3001 Device %s is mounted with Volume \"%s\"\n"), + dir->fsend(_("3001 Device \"%s\" is mounted with Volume \"%s\"\n"), dev->print_name(), dev->VolHdr.VolumeName); } else { - dir->fsend(_("3905 Device %s open but no Bacula volume is mounted.\n" + dir->fsend(_("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()); } @@ -706,12 +716,12 @@ static bool mount_cmd(JCR *jcr) break; case BST_DOING_ACQUIRE: - dir->fsend(_("3001 Device %s is doing acquire.\n"), + dir->fsend(_("3001 Device \"%s\" is doing acquire.\n"), dev->print_name()); break; case BST_WRITING_LABEL: - dir->fsend(_("3903 Device %s is being labeled.\n"), + dir->fsend(_("3903 Device \"%s\" is being labeled.\n"), dev->print_name()); break; @@ -721,43 +731,49 @@ static bool mount_cmd(JCR *jcr) } if (dev->is_open()) { if (dev->is_labeled()) { - dir->fsend(_("3001 Device %s is mounted with Volume \"%s\"\n"), + dir->fsend(_("3001 Device \"%s\" is mounted with Volume \"%s\"\n"), dev->print_name(), dev->VolHdr.VolumeName); } else { - dir->fsend(_("3905 Device %s open but no Bacula volume is mounted.\n" + dir->fsend(_("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()) { if (dev->open(dcr, OPEN_READ_ONLY) < 0) { - dir->fsend(_("3901 Unable to open device %s: ERR=%s\n"), + dir->fsend(_("3901 Unable to open device \"%s\": ERR=%s\n"), dev->print_name(), dev->bstrerror()); break; } read_label(dcr); if (dev->is_labeled()) { - dir->fsend(_("3001 Device %s is already mounted with Volume \"%s\"\n"), + dir->fsend(_("3001 Device \"%s\" is already mounted with Volume \"%s\"\n"), dev->print_name(), dev->VolHdr.VolumeName); } else { - dir->fsend(_("3905 Device %s open but no Bacula volume is mounted.\n" + dir->fsend(_("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_unmountable()) { if (dev->mount(1)) { - dir->fsend(_("3002 Device %s is mounted.\n"), - dev->print_name()); + dir->fsend(_("3002 Device \"%s\" is mounted.\n"), dev->print_name()); } else { dir->fsend(_("3907 %s"), dev->bstrerror()); } } else { /* must be file */ - dir->fsend(_("3906 File device %s is always mounted.\n"), + dir->fsend(_("3906 File device \"%s\" is always mounted.\n"), dev->print_name()); + pthread_cond_broadcast(&dev->wait_next_vol); + Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)dcr->jcr->JobId); + pthread_cond_broadcast(&wait_device_release); } break; + case BST_RELEASING: + dir->fsend(_("3930 Device \"%s\" is being released.\n"), dev->print_name()); + break; + default: - dir->fsend(_("3905 Bizarre wait state %d\n"), dev->blocked()); + dir->fsend(_("3905 Unknown wait state %d\n"), dev->blocked()); break; } dev->dunlock(); @@ -795,14 +811,14 @@ static bool unmount_cmd(JCR *jcr) } if (dev->is_unmountable()) { if (dev->unmount(0)) { - dir->fsend(_("3002 Device %s unmounted.\n"), + dir->fsend(_("3002 Device \"%s\" unmounted.\n"), dev->print_name()); } else { dir->fsend(_("3907 %s"), dev->bstrerror()); } } else { Dmsg0(90, "Device already unmounted\n"); - dir->fsend(_("3901 Device %s is already unmounted.\n"), + dir->fsend(_("3901 Device \"%s\" is already unmounted.\n"), dev->print_name()); } } else if (dev->blocked() == BST_WAITING_FOR_SYSOP) { @@ -811,21 +827,22 @@ static bool unmount_cmd(JCR *jcr) if (!unload_autochanger(dcr, -1)) { /* ***FIXME**** what is this ???? */ dev->close(); + free_volume(dev); } if (dev->is_unmountable() && !dev->unmount(0)) { dir->fsend(_("3907 %s"), dev->bstrerror()); } else { dev->set_blocked(BST_UNMOUNTED_WAITING_FOR_SYSOP); - dir->fsend(_("3001 Device %s unmounted.\n"), + dir->fsend(_("3001 Device \"%s\" unmounted.\n"), dev->print_name()); } } else if (dev->blocked() == BST_DOING_ACQUIRE) { - dir->fsend(_("3902 Device %s is busy in acquire.\n"), + dir->fsend(_("3902 Device \"%s\" is busy in acquire.\n"), dev->print_name()); } else if (dev->blocked() == BST_WRITING_LABEL) { - dir->fsend(_("3903 Device %s is being labeled.\n"), + dir->fsend(_("3903 Device \"%s\" is being labeled.\n"), dev->print_name()); } else if (dev->is_busy()) { @@ -842,11 +859,12 @@ static bool unmount_cmd(JCR *jcr) clear_thread_id(dev->no_wait_id); if (!unload_autochanger(dcr, -1)) { dev->close(); + free_volume(dev); } if (dev->is_unmountable() && !dev->unmount(0)) { dir->fsend(_("3907 %s"), dev->bstrerror()); } else { - dir->fsend(_("3002 Device %s unmounted.\n"), + dir->fsend(_("3002 Device \"%s\" unmounted.\n"), dev->print_name()); } } @@ -864,6 +882,46 @@ static bool unmount_cmd(JCR *jcr) return true; } +#if 0 +/* + * The truncate command will recycle a volume. The director can call this + * after purging a volume so that disk space will not be wasted. Only useful + * for File Storage, of course. + * + * + * It is currently disabled + */ +static bool action_on_purge_cmd(JCR *jcr) +{ + BSOCK *dir = jcr->dir_bsock; + + char devname[MAX_NAME_LENGTH]; + char volumename[MAX_NAME_LENGTH]; + int action; + + /* TODO: Need to find a free device and ask for slot to the director */ + if (sscanf(dir->msg, + "action_on_purge %127s vol=%127s action=%d", + devname, volumename, &action)!= 5) + { + dir->fsend(_("3916 Error scanning action_on_purge command\n")); + goto done; + } + unbash_spaces(volumename); + unbash_spaces(devname); + + /* Check if action is correct */ + if (action & AOP_TRUNCTATE) { + + } + /* ... */ + +done: + dir->signal(BNET_EOD); + return true; +} +#endif + /* * Release command from Director. This rewinds the device and if * configured does a offline and ensures that Bacula will @@ -889,28 +947,28 @@ static bool release_cmd(JCR *jcr) unload_autochanger(dcr, -1); } Dmsg0(90, "Device already released\n"); - dir->fsend(_("3921 Device %s already released.\n"), + dir->fsend(_("3921 Device \"%s\" already released.\n"), dev->print_name()); } else if (dev->blocked() == BST_WAITING_FOR_SYSOP) { Dmsg2(90, "%d waiter dev_block=%d.\n", dev->num_waiting, dev->blocked()); unload_autochanger(dcr, -1); - dir->fsend(_("3922 Device %s waiting for sysop.\n"), + dir->fsend(_("3922 Device \"%s\" waiting for sysop.\n"), dev->print_name()); } else if (dev->blocked() == BST_UNMOUNTED_WAITING_FOR_SYSOP) { Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, dev->blocked()); - dir->fsend(_("3922 Device %s waiting for mount.\n"), + dir->fsend(_("3922 Device \"%s\" waiting for mount.\n"), dev->print_name()); } else if (dev->blocked() == BST_DOING_ACQUIRE) { - dir->fsend(_("3923 Device %s is busy in acquire.\n"), + dir->fsend(_("3923 Device \"%s\" is busy in acquire.\n"), dev->print_name()); } else if (dev->blocked() == BST_WRITING_LABEL) { - dir->fsend(_("3914 Device %s is being labeled.\n"), + dir->fsend(_("3914 Device \"%s\" is being labeled.\n"), dev->print_name()); } else if (dev->is_busy()) { @@ -918,7 +976,7 @@ static bool release_cmd(JCR *jcr) } else { /* device not being used */ Dmsg0(90, "Device not in use, releasing\n"); dcr->release_volume(); - dir->fsend(_("3022 Device %s released.\n"), + dir->fsend(_("3022 Device \"%s\" released.\n"), dev->print_name()); } dev->dunlock(); @@ -935,13 +993,65 @@ static bool release_cmd(JCR *jcr) return true; } +static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER; +static uint32_t bsr_uniq = 0; + +static bool get_bootstrap_file(JCR *jcr, BSOCK *sock) +{ + POOLMEM *fname = get_pool_memory(PM_FNAME); + FILE *bs; + bool ok = false; + + if (jcr->RestoreBootstrap) { + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + } + P(bsr_mutex); + bsr_uniq++; + Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name, + jcr->Job, bsr_uniq); + V(bsr_mutex); + Dmsg1(400, "bootstrap=%s\n", fname); + jcr->RestoreBootstrap = fname; + bs = fopen(fname, "a+b"); /* create file */ + if (!bs) { + berrno be; + Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"), + jcr->RestoreBootstrap, be.bstrerror()); + goto bail_out; + } + Dmsg0(10, "=== Bootstrap file ===\n"); + while (sock->recv() >= 0) { + Dmsg1(10, "%s", sock->msg); + fputs(sock->msg, bs); + } + fclose(bs); + Dmsg0(10, "=== end bootstrap file ===\n"); + jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap); + if (!jcr->bsr) { + Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n")); + goto bail_out; + } + if (debug_level >= 10) { + dump_bsr(jcr->bsr, true); + } + /* If we got a bootstrap, we are reading, so create read volume list */ + create_restore_volume_list(jcr); + ok = true; + +bail_out: + unlink(jcr->RestoreBootstrap); + free_pool_memory(jcr->RestoreBootstrap); + jcr->RestoreBootstrap = NULL; + if (!ok) { + sock->fsend(ERROR_bootstrap); + return false; + } + return sock->fsend(OK_bootstrap); +} static bool bootstrap_cmd(JCR *jcr) { - /* If getting the bootstrap file succeeds, we do not need - * the FD because we will be reading. - */ - jcr->need_fd = false; return get_bootstrap_file(jcr, jcr->dir_bsock); } @@ -962,7 +1072,10 @@ static bool changer_cmd(JCR *jcr) */ bool safe_cmd = false; - if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) { + if (sscanf(dir->msg, "autochanger listall %127s", devname.c_str()) == 1) { + cmd = "listall"; + safe_cmd = ok = true; + } else if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) { cmd = "list"; safe_cmd = ok = true; } else if (sscanf(dir->msg, "autochanger slots %127s", devname.c_str()) == 1) { @@ -978,7 +1091,7 @@ static bool changer_cmd(JCR *jcr) dev = dcr->dev; dev->dlock(); /* Use P to avoid indefinite block */ if (!dev->device->changer_res) { - dir->fsend(_("3995 Device %s is not an autochanger.\n"), + dir->fsend(_("3995 Device \"%s\" is not an autochanger.\n"), dev->print_name()); /* Under certain "safe" conditions, we can steal the lock */ } else if (safe_cmd || !dev->is_open() || dev->can_steal_lock()) { @@ -1070,7 +1183,7 @@ static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot) Dmsg1(100, "Volume: %s\n", dev->VolHdr.VolumeName); break; default: - dir->fsend(_("3902 Cannot mount Volume on Storage Device %s because:\n%s"), + dir->fsend(_("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s"), dev->print_name(), jcr->errmsg); break; } @@ -1098,35 +1211,35 @@ static void send_dir_busy_message(BSOCK *dir, DEVICE *dev) if (dev->is_blocked()) { switch (dev->blocked()) { case BST_UNMOUNTED: - dir->fsend(_("3931 Device %s is BLOCKED. user unmounted.\n"), + dir->fsend(_("3931 Device \"%s\" is BLOCKED. user unmounted.\n"), dev->print_name()); break; case BST_UNMOUNTED_WAITING_FOR_SYSOP: - dir->fsend(_("3932 Device %s is BLOCKED. user unmounted during wait for media/mount.\n"), + dir->fsend(_("3932 Device \"%s\" is BLOCKED. user unmounted during wait for media/mount.\n"), dev->print_name()); break; case BST_WAITING_FOR_SYSOP: - dir->fsend(_("3933 Device %s is BLOCKED waiting for media.\n"), + dir->fsend(_("3933 Device \"%s\" is BLOCKED waiting for media.\n"), dev->print_name()); break; case BST_DOING_ACQUIRE: - dir->fsend(_("3934 Device %s is being initialized.\n"), + dir->fsend(_("3934 Device \"%s\" is being initialized.\n"), dev->print_name()); break; case BST_WRITING_LABEL: - dir->fsend(_("3935 Device %s is blocked labeling a Volume.\n"), + dir->fsend(_("3935 Device \"%s\" is blocked labeling a Volume.\n"), dev->print_name()); break; default: - dir->fsend(_("3935 Device %s is blocked for unknown reason.\n"), + dir->fsend(_("3935 Device \"%s\" is blocked for unknown reason.\n"), dev->print_name()); break; } } else if (dev->can_read()) { - dir->fsend(_("3936 Device %s is busy reading.\n"), + dir->fsend(_("3936 Device \"%s\" is busy reading.\n"), dev->print_name());; } else { - dir->fsend(_("3937 Device %s is busy with %d writer(s).\n"), + dir->fsend(_("3937 Device \"%s\" is busy with %d writer(s).\n"), dev->print_name(), dev->num_writers); } }