From 79fd87cefe1ee39bb36aa5a11121b598a046fd4b Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 6 Aug 2007 18:20:26 +0000 Subject: [PATCH] kes Correct seg fault when switching tape drives during restore. kes Commit uid_gid_name.c (replacement for idcache.c), but will not be used until after 2.2.0 release. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@5293 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/filed/restore.c | 2 +- bacula/src/lib/uid_gid_name.c | 209 ++++++++++++++++++++++++++++++++ bacula/src/stored/acquire.c | 54 ++++++--- bacula/src/stored/dev.h | 1 + bacula/src/stored/read.c | 36 +++--- bacula/src/stored/read_record.c | 35 +++--- bacula/src/version.h | 4 +- bacula/technotes-2.1 | 4 + 8 files changed, 288 insertions(+), 57 deletions(-) create mode 100644 bacula/src/lib/uid_gid_name.c diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index acfaafbe5d..c505971de8 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -654,7 +654,7 @@ void do_restore(JCR *jcr) } Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), rctx.stream); - Dmsg2(0, "None of above!!! stream=%d data=%s\n", rctx.stream,sd->msg); + Dmsg2(0, "Unknown stream=%d data=%s\n", rctx.stream, sd->msg); break; } /* end switch(stream) */ diff --git a/bacula/src/lib/uid_gid_name.c b/bacula/src/lib/uid_gid_name.c new file mode 100644 index 0000000000..7f7d665678 --- /dev/null +++ b/bacula/src/lib/uid_gid_name.c @@ -0,0 +1,209 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2007 Kern Sibbald + + 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 + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Written by Kern Sibbald, July 2005 to replace idcache.c + * + * Program to convert uid and gid into names, and cache the results + * for preformance reasons. + */ + +#include "bacula.h" + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +struct guitem { + dlink link; + char *name; + union { + uid_t uid; + gid_t gid; + }; +}; + +class guid_list { +public: + dlist *uid_list; + dlist *gid_list; + + char *uid_to_name(uid_t uid, char *name, int maxlen); + char *gid_to_name(gid_t gid, char *name, int maxlen); +}; + +guid_list *new_guid_list() +{ + guid_list *list; + guitem *item = NULL; + list = (guid_list *)malloc(sizeof(guid_list)); + list->uid_list = New(dlist(item, &item->link)); + list->gid_list = New(dlist(item, &item->link)); + return list; +} + +void free_guid_list(guid_list *list) +{ + guitem *item; + foreach_dlist(item, list->uid_list) { + free(item->name); + } + foreach_dlist(item, list->gid_list) { + free(item->name); + } + delete list->uid_list; + delete list->gid_list; + free(list); +} + +static int uid_compare(void *item1, void *item2) +{ + guitem *i1 = (guitem *)item1; + guitem *i2 = (guitem *)item2; + if (i1->uid < i2->uid) { + return -1; + } else if (i1->uid > i2->uid) { + return 1; + } else { + return 0; + } +} + +static int gid_compare(void *item1, void *item2) +{ + guitem *i1 = (guitem *)item1; + guitem *i2 = (guitem *)item2; + if (i1->gid < i2->gid) { + return -1; + } else if (i1->gid > i2->gid) { + return 1; + } else { + return 0; + } +} + + +static void get_uidname(uid_t uid, guitem *item) +{ +#ifndef HAVE_WIN32 + struct passwd *pwbuf; + P(mutex); + pwbuf = getpwuid(uid); + if (pwbuf != NULL && strcmp(pwbuf->pw_name, "????????") != 0) { + item->name = bstrdup(pwbuf->pw_name); + } + V(mutex); +#endif +} + +static void get_gidname(gid_t gid, guitem *item) +{ +#ifndef HAVE_WIN32 + struct group *grbuf; + P(mutex); + grbuf = getgrgid(gid); + if (grbuf != NULL && strcmp(grbuf->gr_name, "????????") != 0) { + item->name = bstrdup(grbuf->gr_name); + } + V(mutex); +#endif +} + + +char *guid_list::uid_to_name(uid_t uid, char *name, int maxlen) +{ + guitem sitem, *item, *fitem; + sitem.uid = uid; + char buf[50]; + + item = (guitem *)uid_list->binary_search(&sitem, uid_compare); + Dmsg2(900, "uid=%d item=%p\n", uid, item); + if (!item) { + item = (guitem *)malloc(sizeof(guitem)); + item->uid = uid; + item->name = NULL; + get_uidname(uid, item); + if (!item->name) { + item->name = bstrdup(edit_int64(uid, buf)); + Dmsg2(900, "set uid=%d name=%s\n", uid, item->name); + } + fitem = (guitem *)uid_list->binary_insert(item, uid_compare); + if (fitem != item) { /* item already there this shouldn't happen */ + free(item); + item = fitem; + } + } + bstrncpy(name, item->name, maxlen); + return name; +} + +char *guid_list::gid_to_name(gid_t gid, char *name, int maxlen) +{ + guitem sitem, *item, *fitem; + sitem.gid = gid; + char buf[50]; + + item = (guitem *)uid_list->binary_search(&sitem, gid_compare); + if (!item) { + item = (guitem *)malloc(sizeof(guitem)); + item->gid = gid; + item->name = NULL; + get_gidname(gid, item); + if (!item->name) { + item->name = bstrdup(edit_int64(gid, buf)); + } + fitem = (guitem *)gid_list->binary_insert(item, gid_compare); + if (fitem != item) { /* item already there this shouldn't happen */ + free(item); + item = fitem; + } + } + + bstrncpy(name, item->name, maxlen); + return name; +} + +#ifdef TEST_PROGRAM + +int main() +{ + int i; + guid_list *list; + char ed1[50], ed2[50]; + list = new_guid_list(); + for (i=0; i<1001; i++) { + printf("uid=%d name=%s gid=%d name=%s\n", i, list->uid_to_name(i, ed1, sizeof(ed1)), + i, list->gid_to_name(i, ed2, sizeof(ed2))); + printf("uid=%d name=%s gid=%d name=%s\n", i, list->uid_to_name(i, ed1, sizeof(ed1)), + i, list->gid_to_name(i, ed2, sizeof(ed2))); + } + + free_guid_list(list); + sm_dump(false); + + return 0; +} + +#endif diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index f1efa71188..5736d70334 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -62,7 +62,7 @@ bool acquire_device_for_read(DCR *dcr) int vol_label_status; int retry = 0; - Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr); + Dmsg1(950, "jcr->dcr=%p\n", jcr->dcr); dev->dblock(BST_DOING_ACQUIRE); if (dev->num_writers > 0) { @@ -97,6 +97,12 @@ bool acquire_device_for_read(DCR *dcr) * same as the current drive, we attempt to find the same * device that was used to write the orginal volume. If * found, we switch to using that device. + * + * N.B. A lot of routines rely on the dcr pointer not changing + * read_records.c even has multiple dcrs cached, so we take care + * here to release all important parts of the dcr and re-acquire + * them such as the block pointer (size may change), but we do + * not release the dcr. */ Dmsg2(50, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type); if (dcr->media_type[0] && strcmp(dcr->media_type, dev->device->media_type) != 0) { @@ -107,9 +113,11 @@ bool acquire_device_for_read(DCR *dcr) Jmsg3(jcr, M_INFO, 0, _("Changing device. Want Media Type=\"%s\" have=\"%s\"\n" " device=%s\n"), dcr->media_type, dev->device->media_type, dev->print_name()); + Dmsg3(50, "Changing device. Want Media Type=\"%s\" have=\"%s\"\n" + " device=%s\n", + dcr->media_type, dev->device->media_type, dev->print_name()); dev->dunblock(DEV_UNLOCKED); - detach_dcr_from_dev(dcr); /* release old device */ lock_reservations(); memset(&rctx, 0, sizeof(RCTX)); @@ -125,30 +133,35 @@ bool acquire_device_for_read(DCR *dcr) bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type)); store->append = false; rctx.store = store; + dcr->keep_dcr = true; /* do not free the dcr */ + release_device(dcr); + dcr->keep_dcr = false; /* - * Note, if search_for_device() succeeds, we get a new dcr, - * which we do not use except for the dev info. + * Search for a new device */ stat = search_res_for_device(rctx); release_reserve_messages(jcr); /* release queued messages */ unlock_reservations(); - dev->dblock(BST_DOING_ACQUIRE); + if (stat == 1) { + dev = dcr->dev; /* get new device pointer */ + dev->dblock(BST_DOING_ACQUIRE); dcr->VolumeName[0] = 0; Jmsg(jcr, M_INFO, 0, _("Media Type change. New device %s chosen.\n"), dev->print_name()); + Dmsg1(50, "Media Type change. New device %s chosen.\n", dev->print_name()); + bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type)); dcr->VolCatInfo.Slot = vol->Slot; bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name)); bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type)); - } else if (stat == 0) { /* device busy */ - Pmsg1(000, "Device %s is busy.\n", vol->device); } else { /* error */ Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"), vol->VolumeName); + Dmsg1(50, "No suitable device found to read Volume \"%s\"\n", vol->VolumeName); goto get_out; } } @@ -193,11 +206,10 @@ bool acquire_device_for_read(DCR *dcr) dev->print_name(), dcr->VolumeName, dev->bstrerror()); goto default_path; } - Dmsg1(100, "opened dev %s OK\n", dev->print_name()); + Dmsg1(50, "opened dev %s OK\n", dev->print_name()); /* Read Volume Label */ - - Dmsg0(200, "calling read-vol-label\n"); + Dmsg0(50, "calling read-vol-label\n"); vol_label_status = read_dev_volume_label(dcr); switch (vol_label_status) { case VOL_OK: @@ -275,13 +287,13 @@ default_path: get_out: dev->dlock(); - if (dcr->reserved_device) { + if (dcr && dcr->reserved_device) { dev->reserved_device--; - Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); + Dmsg2(50, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name()); dcr->reserved_device = false; } dev->dunblock(DEV_LOCKED); - Dmsg1(50, "jcr->dcr=%p\n", jcr->dcr); + Dmsg1(950, "jcr->dcr=%p\n", jcr->dcr); return ok; } @@ -551,13 +563,17 @@ bool release_device(DCR *dcr) Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId); pthread_cond_broadcast(&wait_device_release); dev->dunlock(); - if (jcr->read_dcr == dcr) { - jcr->read_dcr = NULL; - } - if (jcr->dcr == dcr) { - jcr->dcr = NULL; + if (dcr->keep_dcr) { + detach_dcr_from_dev(dcr); + } else { + if (jcr->read_dcr == dcr) { + jcr->read_dcr = NULL; + } + if (jcr->dcr == dcr) { + jcr->dcr = NULL; + } + free_dcr(dcr); } - free_dcr(dcr); Dmsg2(100, "===== Device %s released by JobId=%u\n", dev->print_name(), (uint32_t)jcr->JobId); return ok; diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 5babdf67b2..39f4306b5d 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -439,6 +439,7 @@ public: bool any_volume; /* Any OK for dir_find_next... */ bool attached_to_dev; /* set when attached to dev */ bool volume_in_use; /* set in dir_find_next_appendable_volume() */ + bool keep_dcr; /* do not free dcr in release_dcr */ uint32_t VolFirstIndex; /* First file index this Volume */ uint32_t VolLastIndex; /* Last file index this Volume */ uint32_t FileIndex; /* Current File Index */ diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index 90a7c04645..da554ddb84 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -1,14 +1,7 @@ -/* - * Read code for Storage daemon - * - * Kern Sibbald, November MM - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + Copyright (C) 2000-2007 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. @@ -32,6 +25,13 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * Read code for Storage daemon + * + * Kern Sibbald, November MM + * + * Version $Id$ + */ #include "bacula.h" #include "stored.h" @@ -67,7 +67,7 @@ bool do_read_data(JCR *jcr) if (jcr->NumReadVolumes == 0) { Jmsg(jcr, M_FATAL, 0, _("No Volume names found for restore.\n")); free_restore_volume_list(jcr); - bnet_fsend(fd, FD_error); + fd->fsend(FD_error); return false; } @@ -77,16 +77,16 @@ bool do_read_data(JCR *jcr) /* Ready device for reading */ if (!acquire_device_for_read(dcr)) { free_restore_volume_list(jcr); - bnet_fsend(fd, FD_error); + fd->fsend(FD_error); return false; } /* Tell File daemon we will send data */ - bnet_fsend(fd, OK_data); + fd->fsend(OK_data); ok = read_records(dcr, record_cb, mount_next_read_volume); /* Send end of data to FD */ - bnet_sig(fd, BNET_EOD); + fd->signal(BNET_EOD); if (!release_device(jcr->read_dcr)) { ok = false; @@ -117,11 +117,11 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) rec->data_len); /* Send record header to File daemon */ - if (!bnet_fsend(fd, rec_header, rec->VolSessionId, rec->VolSessionTime, + if (!fd->fsend(rec_header, rec->VolSessionId, rec->VolSessionTime, rec->FileIndex, rec->Stream, rec->data_len)) { Pmsg1(000, _(">filed: Error Hdr=%s\n"), fd->msg); Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"), - bnet_strerror(fd)); + fd->bstrerror()); return false; } else { Dmsg1(400, ">filed: Hdr=%s\n", fd->msg); @@ -130,13 +130,13 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) /* Send data record to File daemon */ save_msg = fd->msg; /* save fd message pointer */ - fd->msg = rec->data; /* pass data directly to bnet_send */ + fd->msg = rec->data; /* pass data directly to the FD */ fd->msglen = rec->data_len; Dmsg1(400, ">filed: send %d bytes data.\n", fd->msglen); - if (!bnet_send(fd)) { - Pmsg1(000, _("Error sending to FD. ERR=%s\n"), bnet_strerror(fd)); + if (!fd->send()) { + Pmsg1(000, _("Error sending to FD. ERR=%s\n"), fd->bstrerror()); Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"), - bnet_strerror(fd)); + fd->bstrerror()); ok = false; } diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index 6c2b52fe3c..69707e247d 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -1,22 +1,7 @@ -/* - * - * This routine provides a routine that will handle all - * the gory little details of reading a record from a Bacula - * archive. It uses a callback to pass you each record in turn, - * as well as a callback for mounting the next tape. It takes - * care of reading blocks, applying the bsr, ... - * Note, this routine is really the heart of the restore routines, - * and we are *really* bit pushing here so be careful about making - * any modifications. - * - * Kern E. Sibbald, August MMII - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2002-2006 Free Software Foundation Europe e.V. + Copyright (C) 2002-2007 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. @@ -40,6 +25,21 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * + * This routine provides a routine that will handle all + * the gory little details of reading a record from a Bacula + * archive. It uses a callback to pass you each record in turn, + * as well as a callback for mounting the next tape. It takes + * care of reading blocks, applying the bsr, ... + * Note, this routine is really the heart of the restore routines, + * and we are *really* bit pushing here so be careful about making + * any modifications. + * + * Kern E. Sibbald, August MMII + * + * Version $Id$ + */ #include "bacula.h" #include "stored.h" @@ -103,9 +103,10 @@ bool read_records(DCR *dcr, jcr->mount_next_volume = false; /* * The Device can change at the end of a tape, so refresh it - * from the dcr. + * and the block from the dcr. */ dev = dcr->dev; + block = dcr->block; /* * We just have a new tape up, now read the label (first record) * and pass it off to the callback routine, then continue diff --git a/bacula/src/version.h b/bacula/src/version.h index 4715735305..684687652f 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "2.1.29" -#define BDATE "04 August 2007" -#define LSMDATE "04Aug07" +#define BDATE "06 August 2007" +#define LSMDATE "06Aug07" #define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n" #define BYEAR "2007" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.1 b/bacula/technotes-2.1 index 0fae8c96de..78cbe3058d 100644 --- a/bacula/technotes-2.1 +++ b/bacula/technotes-2.1 @@ -1,6 +1,10 @@ Technical notes on version 2.1 General: +06Aug07 +kes Correct seg fault when switching tape drives during restore. +kes Commit uid_gid_name.c (replacement for idcache.c), but will not + be used until after 2.2.0 release. 04Aug07 kes Remove fnmatch() in SD that permitted wild card specifications. This fixes bug #914. -- 2.39.5