From 5682a17b62e1229ec9d160fcdc86ceb35a73ef1c Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 1 Feb 2003 18:16:08 +0000 Subject: [PATCH] Mult Vols + fix restore hard links + file permissions git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@331 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/kernstodo | 16 +- bacula/src/cats/make_sqlite_tables.in | 2 +- bacula/src/dird/ua_restore.c | 53 +++- bacula/src/dird/verify.c | 5 +- bacula/src/filed/backup.c | 3 +- bacula/src/filed/restore.c | 3 +- bacula/src/filed/verify.c | 2 +- bacula/src/findlib/attribs.c | 14 +- bacula/src/findlib/find.h | 3 + bacula/src/findlib/find_one.c | 378 +++++++++++++++----------- bacula/src/findlib/protos.h | 22 +- bacula/src/lib/.cvsignore | 2 + bacula/src/lib/Makefile.in | 19 +- bacula/src/lib/bnet_pkt.c | 86 +++++- bacula/src/lib/daemon.c | 10 +- bacula/src/stored/acquire.c | 58 ++-- bacula/src/stored/append.c | 2 +- bacula/src/stored/bcopy.c | 2 +- bacula/src/stored/bextract.c | 3 +- bacula/src/stored/bls.c | 4 +- bacula/src/stored/bscan.c | 3 +- bacula/src/stored/btape.c | 2 +- bacula/src/stored/dev.c | 4 +- bacula/src/stored/dev.h | 186 ++++++------- bacula/src/stored/protos.h | 2 +- bacula/src/stored/stored_conf.c | 1 + bacula/src/stored/stored_conf.h | 1 + bacula/src/version.h | 4 +- 28 files changed, 555 insertions(+), 335 deletions(-) diff --git a/bacula/kernstodo b/bacula/kernstodo index 1257c5fb5e..07be04fd78 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -15,6 +15,13 @@ Testing to do: (painful) - blocksize recognition code. For 1.30 release: +- Fix restore of hard linked file. +- Implement FileOptions (see end of this document) +- Implement Bacula plugins -- design API +- Make bcopy read through bad tape records. +- Fix read_record to handle multiple sessions. +- Program files (i.e. execute a program to read/write files). + Pass read date of last backup, size of file last time. - Add Signature type to File DB record. - CD into subdirectory when open()ing files for backup to speed up things. Test with testfind(). @@ -32,9 +39,6 @@ For 1.30 release: - Implement finer multiprocessing options. - Solaris -I on tar for include list - Enable avoid backing up archive device (findlib/find_one.c:128) -- Implement FileOptions (see end of this document) -- Implement Bacula plugins -- design API -- Make bcopy read through bad tape records. - Need a verbose mode in restore, perhaps to bsr. - bscan without -v is too quiet -- perhaps show jobs. - Add code to reject whole blocks if not wanted on restore. @@ -48,9 +52,6 @@ For 1.30 release: records -- one per Job, maybe a JCR or some other structure with a block and a record. - Figure out how to do a bare metal Windows restore -- Fix read_record to handle multiple sessions. -- Program files (i.e. execute a program to read/write files). - Pass read date of last backup, size of file last time. - Put system type returned by FD into catalog. - Possibly add email to Watchdog if drive is unmounted too long and a job is waiting on the drive. @@ -827,4 +828,5 @@ Done: (see kernsdone for more) ====== 1.30 ======= - Implement SHA1 - Get correct error status from run_program or open_bpipe(). - +- Restrict permissions on File Volumes (now 0640). +- Umasked 022 daemons diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in index d9516deda4..55e5993366 100644 --- a/bacula/src/cats/make_sqlite_tables.in +++ b/bacula/src/cats/make_sqlite_tables.in @@ -31,7 +31,7 @@ CREATE TABLE File ( FilenameId INTEGER REFERENCES Filename NOT NULL, MarkId INTEGER UNSIGNED DEFAULT 0, LStat VARCHAR(255) NOT NULL, - MD5 VARCHAR(25) NOT NULL, + MD5 VARCHAR(255) NOT NULL, PRIMARY KEY(FileId) ); diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index c808dcd6bd..7ab4a8848c 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -906,14 +906,41 @@ static int insert_tree_handler(void *ctx, int num_fields, char **row) * down the tree setting all children if the * node is a directory. */ -static void set_extract(TREE_NODE *node, int value) +static void set_extract(UAContext *ua, TREE_NODE *node, TREE_CTX *tree, int value) { TREE_NODE *n; + FILE_DBR fdbr; + struct stat statp; node->extract = value; + /* For a non-file (i.e. directory), we see all the children */ if (node->type != TN_FILE) { for (n=node->child; n; n=n->sibling) { - set_extract(n, value); + set_extract(ua, n, tree, value); + } + } else if (value) { + char cwd[2000]; + /* Ordinary file, we get the full path, look up the + * attributes, decode them, and if we are hard linked to + * a file that was saved, we must load that file too. + */ + tree_getpath(node, cwd, sizeof(cwd)); + fdbr.FileId = 0; + fdbr.JobId = node->JobId; + if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) { + uint32_t LinkFI; + decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */ + /* If we point to a hard linked file, traverse the tree to + * find that file, and mark it for restoration as well. + */ + if (LinkFI) { + for (n=first_tree_node(tree->root); n; n=next_tree_node(n)) { + if (n->FileIndex == LinkFI) { + n->extract = 1; + break; + } + } + } } } } @@ -929,7 +956,7 @@ static int markcmd(UAContext *ua, TREE_CTX *tree) } for (node = tree->node->child; node; node=node->sibling) { if (fnmatch(ua->argk[1], node->fname, 0) == 0) { - set_extract(node, 1); + set_extract(ua, node, tree, 1); } } return 1; @@ -993,14 +1020,15 @@ static int lscmd(UAContext *ua, TREE_CTX *tree) extern char *getuser(uid_t uid); extern char *getgroup(gid_t gid); -static void ls_output(char *buf, char *fname, struct stat *statp) +/* + * This is actually the long form used for "dir" + */ +static void ls_output(char *buf, char *fname, int extract, struct stat *statp) { char *p, *f; char ec1[30]; int n; -// Dmsg2(000, "%s mode=0%o\n", fname, statp->st_mode); - p = encode_mode(statp->st_mode, buf); n = sprintf(p, " %2d ", (uint32_t)statp->st_nlink); p += n; @@ -1010,7 +1038,11 @@ static void ls_output(char *buf, char *fname, struct stat *statp) p += n; p = encode_time(statp->st_ctime, p); *p++ = ' '; - *p++ = ' '; + if (extract) { + *p++ = '*'; + } else { + *p++ = ' '; + } for (f=fname; *f; ) *p++ = *f++; *p = 0; @@ -1037,8 +1069,9 @@ static int dircmd(UAContext *ua, TREE_CTX *tree) fdbr.FileId = 0; fdbr.JobId = node->JobId; if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, &fdbr)) { - decode_stat(fdbr.LStat, &statp); /* decode stat pkt */ - ls_output(buf, cwd, &statp); + uint32_t LinkFI; + decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */ + ls_output(buf, cwd, node->extract, &statp); bsendmsg(ua, "%s\n", buf); } else { /* Something went wrong getting attributes -- print name */ @@ -1118,7 +1151,7 @@ static int unmarkcmd(UAContext *ua, TREE_CTX *tree) } for (node = tree->node->child; node; node=node->sibling) { if (fnmatch(ua->argk[1], node->fname, 0) == 0) { - set_extract(node, 0); + set_extract(ua, node, tree, 0); } } return 1; diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index cc62515d0e..f365a2796d 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -432,10 +432,11 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId) * Got attributes stream, decode it */ if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_WIN32_ATTRIBUTES) { + uint32_t LinkFIf, LinkFIc; Dmsg2(400, "file_index=%d attr=%s\n", file_index, attr); jcr->JobFiles++; jcr->FileIndex = file_index; /* remember attribute file_index */ - decode_stat(attr, &statf); /* decode file stat packet */ + decode_stat(attr, &statf, &LinkFIf); /* decode file stat packet */ do_SIG = NO_SIG; jcr->fn_printed = FALSE; strcpy(jcr->fname, fname); /* move filename into JCR */ @@ -462,7 +463,7 @@ int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId) Dmsg3(400, "Found %s in catalog. inx=%d Opts=%s\n", jcr->fname, file_index, Opts_SIG); - decode_stat(fdbr.LStat, &statc); /* decode catalog stat */ + decode_stat(fdbr.LStat, &statc, &LinkFIc); /* decode catalog stat */ /* * Loop over options supplied by user and verify the * fields he requests. diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 75a5da3e02..62719ef061 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -196,12 +196,13 @@ static int save_file(FF_PKT *ff_pkt, void *ijcr) } Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname); - encode_stat(attribs, &ff_pkt->statp); + encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI); stream = encode_attribsEx(jcr, attribsEx, ff_pkt); Dmsg3(200, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx); P(jcr->mutex); jcr->JobFiles++; /* increment number of files sent */ + ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */ pm_strcpy(&jcr->last_fname, ff_pkt->fname); V(jcr->mutex); diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 7447678834..bc946757a2 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -120,6 +120,7 @@ void do_restore(JCR *jcr) /* File Attributes stream */ if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_WIN32_ATTRIBUTES) { char *ap, *lp, *fp, *apex; + uint32_t LinkFI; Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract); /* If extracting, it was from previous stream, so @@ -207,7 +208,7 @@ void do_restore(JCR *jcr) Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", fname, ap, attribsEx); - decode_stat(ap, &statp); + decode_stat(ap, &statp, &LinkFI); /* * Prepend the where directory so that the * files are put where the user wants. diff --git a/bacula/src/filed/verify.c b/bacula/src/filed/verify.c index 20214f086d..3bff5a1d51 100644 --- a/bacula/src/filed/verify.c +++ b/bacula/src/filed/verify.c @@ -149,7 +149,7 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) fid = -1; } - encode_stat(attribs, &ff_pkt->statp); + encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI); P(jcr->mutex); jcr->JobFiles++; /* increment number of files sent */ diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c index 8ef3d7b359..7aee3723e6 100755 --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -54,7 +54,7 @@ void win_error(void *jcr, char *prefix, POOLMEM *ofile); /* Encode a stat structure into a base64 character string */ -void encode_stat(char *buf, struct stat *statp) +void encode_stat(char *buf, struct stat *statp, uint32_t LinkFI) { char *p = buf; /* @@ -89,6 +89,8 @@ void encode_stat(char *buf, struct stat *statp) p += to_base64((int64_t)statp->st_mtime, p); *p++ = ' '; p += to_base64((int64_t)statp->st_ctime, p); + *p++ = ' '; + p += to_base64((int64_t)LinkFI, p); *p = 0; return; } @@ -97,7 +99,7 @@ void encode_stat(char *buf, struct stat *statp) /* Decode a stat packet from base64 characters */ void -decode_stat(char *buf, struct stat *statp) +decode_stat(char *buf, struct stat *statp, uint32_t *LinkFI) { char *p = buf; int64_t val; @@ -140,6 +142,14 @@ decode_stat(char *buf, struct stat *statp) p++; p += from_base64(&val, p); statp->st_ctime = val; + /* Optional FileIndex of hard linked file data */ + if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) { + p++; + p += from_base64(&val, p); + *LinkFI = (uint32_t)val; + } else { + *LinkFI = 0; + } } /* diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 00c17cb49b..4318f9ed24 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -130,6 +130,9 @@ typedef struct ff { char *link; /* link if file linked */ POOLMEM *sys_fname; /* system filename */ struct stat statp; /* stat packet */ + uint32_t FileIndex; /* FileIndex of this file */ + uint32_t LinkFI; /* FileIndex of main hard linked file */ + struct f_link *linked; /* Set if we are hard linked */ int type; /* FT_ type from above */ int fid; /* file id if opened */ int flags; /* control flags */ diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index 8bd209fb45..39a58ccff1 100755 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -38,14 +38,19 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); /* - * Structure for keeping track of hard linked files + * Structure for keeping track of hard linked files, we + * keep an entry for each hardlinked file that we save, + * which is the first one found. For all the other files that + * are linked to this one, we save only the directory + * entry so we can link it. */ struct f_link { struct f_link *next; - dev_t dev; - ino_t ino; + dev_t dev; /* device */ + ino_t ino; /* inode with device is unique */ short linkcount; - char name[1]; + uint32_t FileIndex; /* Bacula FileIndex of this file */ + char name[1]; /* The name */ }; @@ -124,7 +129,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), return handle_file(ff_pkt, pkt); } #endif - + ff_pkt->LinkFI = 0; /* * Handle hard linked files * @@ -141,173 +146,212 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), struct f_link *lp; - /* Search link list of hard linked files */ - for (lp = ff_pkt->linklist; lp; lp = lp->next) - if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) { - ff_pkt->link = lp->name; - ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */ - return handle_file(ff_pkt, pkt); - } - - /* File not previously dumped. Chain it into our list. */ - lp = (struct f_link *)bmalloc(sizeof(struct f_link) + strlen(fname) +1); - lp->ino = ff_pkt->statp.st_ino; - lp->dev = ff_pkt->statp.st_dev; - strcpy(lp->name, fname); - lp->next = ff_pkt->linklist; - ff_pkt->linklist = lp; + /* Search link list of hard linked files */ + for (lp = ff_pkt->linklist; lp; lp = lp->next) + if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) { + ff_pkt->link = lp->name; + ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */ + ff_pkt->LinkFI = lp->FileIndex; + return handle_file(ff_pkt, pkt); + } + + /* File not previously dumped. Chain it into our list. */ + lp = (struct f_link *)bmalloc(sizeof(struct f_link) + strlen(fname) +1); + lp->ino = ff_pkt->statp.st_ino; + lp->dev = ff_pkt->statp.st_dev; + strcpy(lp->name, fname); + lp->next = ff_pkt->linklist; + ff_pkt->linklist = lp; + ff_pkt->linked = lp; /* mark saved link */ + } else { + ff_pkt->linked = NULL; } /* This is not a link to a previously dumped file, so dump it. */ if (S_ISREG(ff_pkt->statp.st_mode)) { - off_t sizeleft; - - sizeleft = ff_pkt->statp.st_size; - - /* Don't bother opening empty, world readable files. Also do not open - files when archive is meant for /dev/null. */ - if (ff_pkt->null_output_device || (sizeleft == 0 - && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) { - ff_pkt->type = FT_REGE; - } else { - ff_pkt->type = FT_REG; - } - return handle_file(ff_pkt, pkt); + off_t sizeleft; + + sizeleft = ff_pkt->statp.st_size; + + /* Don't bother opening empty, world readable files. Also do not open + files when archive is meant for /dev/null. */ + if (ff_pkt->null_output_device || (sizeleft == 0 + && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) { + ff_pkt->type = FT_REGE; + } else { + ff_pkt->type = FT_REG; + } + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; + } else if (S_ISLNK(ff_pkt->statp.st_mode)) { - int size; - char *buffer = (char *)alloca(path_max + name_max + 2); - - size = readlink(fname, buffer, path_max + name_max + 1); - if (size < 0) { - /* Could not follow link */ - ff_pkt->type = FT_NOFOLLOW; - ff_pkt->ff_errno = errno; - return handle_file(ff_pkt, pkt); - } - buffer[size] = 0; - ff_pkt->link = buffer; - ff_pkt->type = FT_LNK; /* got a real link */ - return handle_file(ff_pkt, pkt); + int size; + char *buffer = (char *)alloca(path_max + name_max + 2); + + size = readlink(fname, buffer, path_max + name_max + 1); + if (size < 0) { + /* Could not follow link */ + ff_pkt->type = FT_NOFOLLOW; + ff_pkt->ff_errno = errno; + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; + } + buffer[size] = 0; + ff_pkt->link = buffer; + ff_pkt->type = FT_LNK; /* got a real link */ + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; } else if (S_ISDIR(ff_pkt->statp.st_mode)) { - DIR *directory; - struct dirent *entry, *result; - char *link; - int link_len; - int len; - int status; - dev_t our_device = ff_pkt->statp.st_dev; - - if (access(fname, R_OK) == -1 && geteuid() != 0) { - /* Could not access() directory */ - ff_pkt->type = FT_NOACCESS; - ff_pkt->ff_errno = errno; - return handle_file(ff_pkt, pkt); - } - - /* Build a canonical directory name with a trailing slash. */ - len = strlen(fname); - link_len = len + 200; - link = (char *)bmalloc(link_len + 2); - bstrncpy(link, fname, link_len); - /* Strip all trailing slashes */ - while (len >= 1 && link[len - 1] == '/') - len--; - link[len++] = '/'; /* add back one */ - link[len] = 0; - - ff_pkt->link = link; - if (ff_pkt->incremental && - (ff_pkt->statp.st_mtime < ff_pkt->save_time && - ff_pkt->statp.st_ctime < ff_pkt->save_time)) { - /* Incremental option, directory entry not changed */ - ff_pkt->type = FT_DIRNOCHG; - } else { - ff_pkt->type = FT_DIR; - } - handle_file(ff_pkt, pkt); /* handle directory entry */ - - ff_pkt->link = ff_pkt->fname; /* reset "link" */ - - /* - * Do not decend into subdirectories (recurse) if the - * user has turned it off for this directory. - */ - if (ff_pkt->flags & FO_NO_RECURSION) { - free(link); - /* No recursion into this directory */ - ff_pkt->type = FT_NORECURSE; - return handle_file(ff_pkt, pkt); - } - - /* - * See if we are crossing file systems, and - * avoid doing so if the user only wants to dump one file system. - */ - if (!top_level && !(ff_pkt->flags & FO_MULTIFS) && - parent_device != ff_pkt->statp.st_dev) { - free(link); - /* returning here means we do not handle this directory */ - ff_pkt->type = FT_NOFSCHG; - return handle_file(ff_pkt, pkt); - } - /* - * Now process the files in this directory. - */ - errno = 0; - if ((directory = opendir(fname)) == NULL) { - free(link); - ff_pkt->type = FT_NOOPEN; - ff_pkt->ff_errno = errno; - return handle_file(ff_pkt, pkt); - } - - /* - * This would possibly run faster if we chdir to the directory - * before traversing it. - */ - rtn_stat = 1; - entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100); - for ( ; !job_cancelled(jcr); ) { - char *p, *q; - int i; - - status = readdir_r(directory, entry, &result); - Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result, - entry->d_name); - if (status != 0 || result == NULL) { - break; - } - ASSERT(name_max+1 > sizeof(struct dirent) + (int)NAMELEN(entry)); - p = entry->d_name; - /* Skip `.', `..', and excluded file names. */ - if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' || - (p[1] == '.' && p[2] == '\0')))) { - continue; - } - - if ((int)NAMELEN(entry) + len >= link_len) { - link_len = len + NAMELEN(entry) + 1; - link = (char *)brealloc(link, link_len + 1); - } - q = link + len; - for (i=0; i < (int)NAMELEN(entry); i++) { - *q++ = *p++; - } - *q = 0; - if (!file_is_excluded(ff_pkt, link)) { - rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0); - } - } - closedir(directory); - free(link); - free(entry); - - if (ff_pkt->atime_preserve) { - utime(fname, &restore_times); - } - return rtn_stat; + DIR *directory; + struct dirent *entry, *result; + char *link; + int link_len; + int len; + int status; + dev_t our_device = ff_pkt->statp.st_dev; + + if (access(fname, R_OK) == -1 && geteuid() != 0) { + /* Could not access() directory */ + ff_pkt->type = FT_NOACCESS; + ff_pkt->ff_errno = errno; + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; + } + + /* Build a canonical directory name with a trailing slash. */ + len = strlen(fname); + link_len = len + 200; + link = (char *)bmalloc(link_len + 2); + bstrncpy(link, fname, link_len); + /* Strip all trailing slashes */ + while (len >= 1 && link[len - 1] == '/') + len--; + link[len++] = '/'; /* add back one */ + link[len] = 0; + + ff_pkt->link = link; + if (ff_pkt->incremental && + (ff_pkt->statp.st_mtime < ff_pkt->save_time && + ff_pkt->statp.st_ctime < ff_pkt->save_time)) { + /* Incremental option, directory entry not changed */ + ff_pkt->type = FT_DIRNOCHG; + } else { + ff_pkt->type = FT_DIR; + } + handle_file(ff_pkt, pkt); /* handle directory entry */ + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + + ff_pkt->link = ff_pkt->fname; /* reset "link" */ + + /* + * Do not decend into subdirectories (recurse) if the + * user has turned it off for this directory. + */ + if (ff_pkt->flags & FO_NO_RECURSION) { + free(link); + /* No recursion into this directory */ + ff_pkt->type = FT_NORECURSE; + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; + } + + /* + * See if we are crossing file systems, and + * avoid doing so if the user only wants to dump one file system. + */ + if (!top_level && !(ff_pkt->flags & FO_MULTIFS) && + parent_device != ff_pkt->statp.st_dev) { + free(link); + /* returning here means we do not handle this directory */ + ff_pkt->type = FT_NOFSCHG; + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; + } + /* + * Now process the files in this directory. + */ + errno = 0; + if ((directory = opendir(fname)) == NULL) { + free(link); + ff_pkt->type = FT_NOOPEN; + ff_pkt->ff_errno = errno; + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; + } + + /* + * This would possibly run faster if we chdir to the directory + * before traversing it. + */ + rtn_stat = 1; + entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100); + for ( ; !job_cancelled(jcr); ) { + char *p, *q; + int i; + + status = readdir_r(directory, entry, &result); + Dmsg3(200, "readdir stat=%d result=%x name=%s\n", status, result, + entry->d_name); + if (status != 0 || result == NULL) { + break; + } + ASSERT(name_max+1 > sizeof(struct dirent) + (int)NAMELEN(entry)); + p = entry->d_name; + /* Skip `.', `..', and excluded file names. */ + if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' || + (p[1] == '.' && p[2] == '\0')))) { + continue; + } + + if ((int)NAMELEN(entry) + len >= link_len) { + link_len = len + NAMELEN(entry) + 1; + link = (char *)brealloc(link, link_len + 1); + } + q = link + len; + for (i=0; i < (int)NAMELEN(entry); i++) { + *q++ = *p++; + } + *q = 0; + if (!file_is_excluded(ff_pkt, link)) { + rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + } + } + closedir(directory); + free(link); + free(entry); + + if (ff_pkt->atime_preserve) { + utime(fname, &restore_times); + } + return rtn_stat; } /* end check for directory */ /* @@ -324,7 +368,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), /* The only remaining types are special (character, ...) files */ ff_pkt->type = FT_SPEC; } - return handle_file(ff_pkt, pkt); + rtn_stat = handle_file(ff_pkt, pkt); + if (ff_pkt->linked) { + ff_pkt->linked->FileIndex = ff_pkt->FileIndex; + } + return rtn_stat; } int term_find_one(FF_PKT *ff) diff --git a/bacula/src/findlib/protos.h b/bacula/src/findlib/protos.h index 3c2c876362..770f97ea4b 100644 --- a/bacula/src/findlib/protos.h +++ b/bacula/src/findlib/protos.h @@ -24,17 +24,17 @@ */ /* from attribs.c */ -void encode_stat (char *buf, struct stat *statp); -void decode_stat (char *buf, struct stat *statp); -int encode_attribsEx (void *jcr, char *attribsEx, FF_PKT *ff_pkt); +void encode_stat (char *buf, struct stat *statp, uint32_t LinkFI); +void decode_stat (char *buf, struct stat *statp, uint32_t *LinkFI); +int encode_attribsEx (void *jcr, char *attribsEx, FF_PKT *ff_pkt); int set_attributes(void *jcr, char *fname, char *ofile, char *lname, - int type, int stream, struct stat *statp, - char *attribsEx, int *ofd); + int type, int stream, struct stat *statp, + char *attribsEx, int *ofd); /* from create_file.c */ int create_file(void *jcr, char *fname, char *ofile, char *lname, - int type, int stream, struct stat *statp, - char *attribsEx, int *ofd, int replace); + int type, int stream, struct stat *statp, + char *attribsEx, int *ofd, int replace); /* From find.c */ FF_PKT *init_find_files(); @@ -50,15 +50,15 @@ void add_fname_to_exclude_list(FF_PKT *ff, char *fname); int file_is_excluded(FF_PKT *ff, char *file); int file_is_included(FF_PKT *ff, char *file); struct s_included_file *get_next_included_file(FF_PKT *ff, - struct s_included_file *inc); + struct s_included_file *inc); /* From find_one.c */ int find_one_file(JCR *jcr, FF_PKT *ff, int handle_file(FF_PKT *ff_pkt, void *hpkt), - void *pkt, char *p, dev_t parent_device, int top_level); + void *pkt, char *p, dev_t parent_device, int top_level); int term_find_one(FF_PKT *ff); /* from makepath.c */ int make_path(void *jcr, const char *argpath, int mode, - int parent_mode, uid_t owner, gid_t group, - int preserve_existing, char *verbose_fmt_string); + int parent_mode, uid_t owner, gid_t group, + int preserve_existing, char *verbose_fmt_string); diff --git a/bacula/src/lib/.cvsignore b/bacula/src/lib/.cvsignore index afa729ee85..b2d6cfa59f 100644 --- a/bacula/src/lib/.cvsignore +++ b/bacula/src/lib/.cvsignore @@ -4,3 +4,5 @@ btraceback btraceback.gdb startit stopit +sha1sum +md5sum diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 58a4aec748..bd866d1be2 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -94,12 +94,27 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status cd $(topdir) \ && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status -rwlock_test: rwlock.o +rwlock_test: rm -f rwlock.o $(CXX) -DTEST_RWLOCK $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) rwlock.c $(CXX) $(LDFLAGS) -L. -o $@ rwlock.o $(LIBS) $(DLIB) -lbac -lm rm -f rwlock.o $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) rwlock.c + +md5sum: + rm -f md5.o + $(CXX) -DMD5_SUM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) md5.c + $(CXX) $(LDFLAGS) -L. -o $@ md5.o $(LIBS) $(DLIB) -lbac -lm + rm -f md5.o + $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) md5.c + + +sha1sum: + rm -f sha1.o + $(CXX) -DSHA1_SUM $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) sha1.c + $(CXX) $(LDFLAGS) -L. -o $@ sha1.o $(LIBS) $(DLIB) -lbac -lm + rm -f sha1.o + $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) md5.c install: @@ -107,7 +122,7 @@ uninstall: clean: $(RMF) *.a core a.out *.o *.bak *.tex *.pdf *~ *.intpro *.extpro 1 2 3 - $(RMF) rwlock_test md5 sha1 + $(RMF) rwlock_test md5sum sha1sum realclean: clean $(RMF) tags diff --git a/bacula/src/lib/bnet_pkt.c b/bacula/src/lib/bnet_pkt.c index fb5ae14d87..fe4acf92a5 100644 --- a/bacula/src/lib/bnet_pkt.c +++ b/bacula/src/lib/bnet_pkt.c @@ -7,7 +7,7 @@ * Version $Id$ */ /* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + Copyright (C) 2002-2003 Kern Sibbald and John Walker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -39,8 +39,57 @@ * Returns -2 on error */ int32_t -bnet_recv_pkt(BSOCK *bsock, BPKT *pkt) +bnet_recv_pkt(BSOCK *bsock, BPKT *pkt, int *version) { + unser_declare; + short lversion; + int type; + + unser_begin(bsock->msg, 0); + unser_uint16(lversion); + *version = (int)lversion; + + + for ( ; pkt->type != BP_EOF; pkt++) { + if (pkt->id) { + ser_int8(BP_ID); + ser_string((char *)pkt->id); + } + ser_int8(pkt->type); + switch (pkt->type) { + case BP_CHAR: + ser_int8(*(int8_t *)pkt->value); + break; + case BP_INT32: + ser_int32(*(int32_t *)pkt->value); + break; + case BP_UINT32: + break; + ser_unit32(*(uint32_t *)pkt->value); + break; + case BP_INT64: + ser_int64(*(int64_t *)pkt->value); + break; + case BP_BTIME: + case BP_UTIME: + case BP_UINT64: + ser_uint64(*(uint64_t *)pkt->value); + break; + case BP_POOL: + case BP_STRING: + case BP_NAME: + ser_string((char *)pkt->value); + break; + case BP_BYTES: + ser_uint32(*(uint32_t *)pkt->len); + ser_bytes((char *)pkt->value, pkt->len); + break; + default: + Emsg1(M_ABORT, 0, _("Unknown BPKT type: %d\n"), pkt->type); + } + } + unser_end(bsock->msg, 0); + } /* @@ -52,37 +101,50 @@ bnet_recv_pkt(BSOCK *bsock, BPKT *pkt) * 1 on success */ int -bnet_send_pkt(BSOCK *bsock, BPKT *pkt) +bnet_send_pkt(BSOCK *bsock, BPKT *pkt, int version) { ser_declare; ser_begin(bsock->msg, 0); + ser_uint16(version); - while (pkt->type != BP_EOF) { + for ( ; pkt->type != BP_EOF; pkt++) { + if (pkt->id) { + ser_int8(BP_ID); + ser_string((char *)pkt->id); + } ser_int8(pkt->type); switch (pkt->type) { case BP_CHAR: - ser_int8(*((int8_t)pkt->value))); + ser_int8(*(int8_t *)pkt->value); break; case BP_INT32: - ser_int32(*(int32_t)pkt->value))); + ser_int32(*(int32_t *)pkt->value); break; case BP_UINT32: break; + ser_unit32(*(uint32_t *)pkt->value); + break; case BP_INT64: + ser_int64(*(int64_t *)pkt->value); break; - case BP_STRING: + case BP_BTIME: + case BP_UTIME: + case BP_UINT64: + ser_uint64(*(uint64_t *)pkt->value); break; + case BP_POOL: + case BP_STRING: case BP_NAME: + ser_string((char *)pkt->value); break; case BP_BYTES: - break; - case BP_FLOAT32: - break; - case BP_FLOAT64: + ser_uint32(*(uint32_t *)pkt->len); + ser_bytes((char *)pkt->value, pkt->len); break; default: Emsg1(M_ABORT, 0, _("Unknown BPKT type: %d\n"), pkt->type); } - + } + ser_end(bsock->msg, 0); } diff --git a/bacula/src/lib/daemon.c b/bacula/src/lib/daemon.c index 6613b7f6aa..01e11bb694 100644 --- a/bacula/src/lib/daemon.c +++ b/bacula/src/lib/daemon.c @@ -42,6 +42,7 @@ daemon_start() #ifndef HAVE_CYGWIN int i; int cpid; + mode_t oldmask; /* * Become a daemon. */ @@ -76,8 +77,13 @@ daemon_start() chdir("/"); #endif - /* clear any inherited umask */ - umask(0); + /* + * Avoid creating files 666 but don't override any + * more restrictive mask set by the user. + */ + oldmask = umask(022); + oldmask |= 022; + umask(oldmask); Dmsg0(200, "Exit daemon_start\n"); #endif /* HAVE_CYGWIN */ diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 215e2b2fb3..99a6f33333 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -28,6 +28,7 @@ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /********************************************************************* * Acquire device for reading. We permit (for the moment) @@ -143,20 +144,20 @@ get_out: * Acquire device for writing. We permit multiple writers. * If this is the first one, we read the label. * - * Returns: 0 if failed for any reason - * 1 if successful + * Returns: NULL if failed for any reason + * dev if successful (may change if new dev opened) */ -int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) +DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) { int release = 0; int do_mount = 0; - int stat = 0; + DEVICE *rtn_dev = NULL; lock_device(dev); block_device(dev, BST_DOING_ACQUIRE); unlock_device(dev); Dmsg1(190, "acquire_append device is %s\n", dev_is_tape(dev)?"tape":"disk"); - + if (dev->state & ST_APPEND) { /* @@ -173,14 +174,31 @@ int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) !(dir_find_next_appendable_volume(jcr) && strcmp(dev->VolHdr.VolName, jcr->VolumeName) == 0)) { /* wrong tape mounted */ if (dev->num_writers != 0) { - /* - * ***FIXME*** add multiple writers here if permitted - * find end of dev chain - * dev->next = init_dev(NULL, dev->device); - * ... - */ - Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev)); - goto get_out; + DEVICE *d = ((DEVRES *)dev->device)->dev; + uint32_t open_vols = 0; + for ( ; d; d=d->next) { + open_vols++; + } + if (dev->state & ST_FILE && dev->max_open_vols > open_vols) { + P(mutex); /* lock all devices */ + d = init_dev(NULL, (DEVRES *)dev->device); /* init new device */ + d->prev = dev; /* chain in new device */ + d->next = dev->next; + dev->next = d; + /* Release old device */ + P(dev->mutex); + unblock_device(dev); + V(dev->mutex); + /* Make new device current device and lock it */ + dev = d; + lock_device(dev); + block_device(dev, BST_DOING_ACQUIRE); + unlock_device(dev); + V(mutex); + } else { + Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev)); + goto get_out; + } } /* Wrong tape mounted, release it, then fall through to get correct one */ release = 1; @@ -213,13 +231,13 @@ int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) jcr->NumVolumes = 1; } attach_jcr_to_device(dev, jcr); /* attach jcr to device */ - stat = 1; /* good return */ + rtn_dev = dev; /* return device */ get_out: P(dev->mutex); unblock_device(dev); V(dev->mutex); - return stat; + return rtn_dev; } /* @@ -281,6 +299,14 @@ int release_device(JCR *jcr, DEVICE *dev) dev_name(dev), NPRT(jcr->VolumeName)); } detach_jcr_from_device(dev, jcr); - unlock_device(dev); + if (dev->prev && !(dev->state & ST_READ) && dev->num_writers == 0) { + P(mutex); + unlock_device(dev); + dev->prev->next = dev->next; /* dechain */ + term_dev(dev); + V(mutex); + } else { + unlock_device(dev); + } return 1; } diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index c3ea57e560..307b1becae 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -73,7 +73,7 @@ int do_append_data(JCR *jcr) * subroutine. */ Dmsg0(100, "just before acquire_device\n"); - if (!acquire_device_for_append(jcr, dev, block)) { + if (!(dev=acquire_device_for_append(jcr, dev, block))) { set_jcr_job_status(jcr, JS_ErrorTerminated); free_block(block); return 0; diff --git a/bacula/src/stored/bcopy.c b/bacula/src/stored/bcopy.c index 9da6927c02..5dded6d184 100644 --- a/bacula/src/stored/bcopy.c +++ b/bacula/src/stored/bcopy.c @@ -144,7 +144,7 @@ int main (int argc, char *argv[]) exit(1); } unlock_device(out_dev); - if (!acquire_device_for_append(out_jcr, out_dev, out_block)) { + if (!(out_dev=acquire_device_for_append(out_jcr, out_dev, out_block))) { free_block(out_block); free_jcr(in_jcr); exit(1); diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index be9b1fa5ad..10c6300cca 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -321,8 +321,9 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) { + uint32_t LinkFI; - decode_stat(ap, &statp); + decode_stat(ap, &statp, &LinkFI); /* * Prepend the where directory so that the * files are put where the user wants. diff --git a/bacula/src/stored/bls.c b/bacula/src/stored/bls.c index dedf4fb5cd..3d00ea70c1 100644 --- a/bacula/src/stored/bls.c +++ b/bacula/src/stored/bls.c @@ -322,6 +322,8 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) /* File Attributes stream */ if (rec->Stream == STREAM_UNIX_ATTRIBUTES || rec->Stream == STREAM_WIN32_ATTRIBUTES) { char *ap, *fp; + uint32_t LinkFI; + sscanf(rec->data, "%ld %d", &record_file_index, &type); if (record_file_index != rec->FileIndex) { Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n", @@ -340,7 +342,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } *fp = *ap++; /* terminate filename & point to attribs */ - decode_stat(ap, &statp); + decode_stat(ap, &statp, &LinkFI); /* Skip to link name */ while (*ap++ != 0) ; diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index ebc4977aca..9ccdc3fab9 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -537,7 +537,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } strcat(lname, lp); /* "save" link name */ if (verbose > 1) { - decode_stat(ap, &statp); + uint32_t LinkFI; + decode_stat(ap, &statp, &LinkFI); print_ls_output(fname, lname, type, &statp); } mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index 1b80ff02a9..94780827b9 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -1043,7 +1043,7 @@ This may take a long time. I.e. hours! ...\n\n"); * subroutine. */ Dmsg0(100, "just before acquire_device\n"); - if (!acquire_device_for_append(jcr, dev, block)) { + if (!(dev=acquire_device_for_append(jcr, dev, block))) { set_jcr_job_status(jcr, JS_ErrorTerminated); free_block(block); return; diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 24572066b4..e19032544d 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -153,6 +153,7 @@ init_dev(DEVICE *dev, DEVRES *device) dev->volume_capacity = device->volume_capacity; dev->max_rewind_wait = device->max_rewind_wait; dev->max_open_wait = device->max_open_wait; + dev->max_open_vols = device->max_open_vols; dev->device = device; if (tape) { @@ -305,7 +306,8 @@ open_dev(DEVICE *dev, char *VolName, int mode) } else { Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); } - if ((dev->fd = open(archive_name, dev->mode, MODE_RW)) < 0) { + /* If creating file, give 0640 permissions */ + if ((dev->fd = open(archive_name, dev->mode, 0640)) < 0) { dev->dev_errno = errno; Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name, strerror(dev->dev_errno)); Emsg0(M_FATAL, 0, dev->errmsg); diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 7f91545a70..d2fd63c935 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -31,9 +31,9 @@ /* #define NEW_LOCK 1 */ -#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev)) +#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev)) #define new_lock_device_state(dev,state) _new_lock_device(__FILE__, __LINE__, (dev), (state)) -#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev)) +#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev)) #define lock_device(d) _lock_device(__FILE__, __LINE__, (d)) #define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d)) @@ -46,64 +46,64 @@ #define READ_WRITE 0 #define READ_ONLY 1 #define OPEN_READ_WRITE 0 -#define OPEN_READ_ONLY 1 +#define OPEN_READ_ONLY 1 #define OPEN_WRITE_ONLY 2 /* Generic status bits returned from status_dev() */ -#define MT_TAPE (1<<0) /* is tape device */ -#define MT_EOF (1<<1) /* just read EOF */ -#define MT_BOT (1<<2) /* at beginning of tape */ -#define MT_EOT (1<<3) /* end of tape reached */ -#define MT_SM (1<<4) /* DDS setmark */ -#define MT_EOD (1<<5) /* DDS at end of data */ -#define MT_WR_PROT (1<<6) /* tape write protected */ -#define MT_ONLINE (1<<7) /* tape online */ -#define MT_DR_OPEN (1<<8) /* tape door open */ -#define MT_IM_REP_EN (1<<9) /* immediate report enabled */ +#define MT_TAPE (1<<0) /* is tape device */ +#define MT_EOF (1<<1) /* just read EOF */ +#define MT_BOT (1<<2) /* at beginning of tape */ +#define MT_EOT (1<<3) /* end of tape reached */ +#define MT_SM (1<<4) /* DDS setmark */ +#define MT_EOD (1<<5) /* DDS at end of data */ +#define MT_WR_PROT (1<<6) /* tape write protected */ +#define MT_ONLINE (1<<7) /* tape online */ +#define MT_DR_OPEN (1<<8) /* tape door open */ +#define MT_IM_REP_EN (1<<9) /* immediate report enabled */ /* Test capabilities */ #define dev_cap(dev, cap) ((dev)->capabilities & (cap)) /* Bits for device capabilities */ -#define CAP_EOF 0x0001 /* has MTWEOF */ -#define CAP_BSR 0x0002 /* has MTBSR */ -#define CAP_BSF 0x0004 /* has MTBSF */ -#define CAP_FSR 0x0008 /* has MTFSR */ -#define CAP_FSF 0x0010 /* has MTFSF */ -#define CAP_EOM 0x0020 /* has MTEOM */ -#define CAP_REM 0x0040 /* is removable media */ -#define CAP_RACCESS 0x0080 /* is random access device */ -#define CAP_AUTOMOUNT 0x0100 /* Read device at start to see what is there */ -#define CAP_LABEL 0x0200 /* Label blank tapes */ -#define CAP_ANONVOLS 0x0400 /* Mount without knowing volume name */ -#define CAP_ALWAYSOPEN 0x0800 /* always keep device open */ +#define CAP_EOF 0x0001 /* has MTWEOF */ +#define CAP_BSR 0x0002 /* has MTBSR */ +#define CAP_BSF 0x0004 /* has MTBSF */ +#define CAP_FSR 0x0008 /* has MTFSR */ +#define CAP_FSF 0x0010 /* has MTFSF */ +#define CAP_EOM 0x0020 /* has MTEOM */ +#define CAP_REM 0x0040 /* is removable media */ +#define CAP_RACCESS 0x0080 /* is random access device */ +#define CAP_AUTOMOUNT 0x0100 /* Read device at start to see what is there */ +#define CAP_LABEL 0x0200 /* Label blank tapes */ +#define CAP_ANONVOLS 0x0400 /* Mount without knowing volume name */ +#define CAP_ALWAYSOPEN 0x0800 /* always keep device open */ #define CAP_AUTOCHANGER 0x1000 /* AutoChanger */ #define CAP_OFFLINEUNMOUNT 0x2000 /* Offline before unmount */ -#define CAP_STREAM 0x4000 /* Stream device */ +#define CAP_STREAM 0x4000 /* Stream device */ /* Test state */ #define dev_state(dev, state) ((dev)->state & (state)) /* Device state bits */ -#define ST_OPENED 0x0001 /* set when device opened */ -#define ST_TAPE 0x0002 /* is a tape device */ -#define ST_FILE 0x0004 /* is a file device */ -#define ST_FIFO 0x0008 /* is a fifo device */ -#define ST_PROG 0x0010 /* is a program device */ -#define ST_LABEL 0x0020 /* label found */ +#define ST_OPENED 0x0001 /* set when device opened */ +#define ST_TAPE 0x0002 /* is a tape device */ +#define ST_FILE 0x0004 /* is a file device */ +#define ST_FIFO 0x0008 /* is a fifo device */ +#define ST_PROG 0x0010 /* is a program device */ +#define ST_LABEL 0x0020 /* label found */ #define ST_MALLOC 0x0040 /* dev packet malloc'ed in init_dev() */ -#define ST_APPEND 0x0080 /* ready for Bacula append */ -#define ST_READ 0x0100 /* ready for Bacula read */ -#define ST_EOT 0x0200 /* at end of tape */ -#define ST_WEOT 0x0400 /* Got EOT on write */ -#define ST_EOF 0x0800 /* Read EOF i.e. zero bytes */ -#define ST_NEXTVOL 0x1000 /* Start writing on next volume */ -#define ST_SHORT 0x2000 /* Short block read */ +#define ST_APPEND 0x0080 /* ready for Bacula append */ +#define ST_READ 0x0100 /* ready for Bacula read */ +#define ST_EOT 0x0200 /* at end of tape */ +#define ST_WEOT 0x0400 /* Got EOT on write */ +#define ST_EOF 0x0800 /* Read EOF i.e. zero bytes */ +#define ST_NEXTVOL 0x1000 /* Start writing on next volume */ +#define ST_SHORT 0x2000 /* Short block read */ /* dev_blocked states (mutually exclusive) */ #define BST_NOT_BLOCKED 0 /* not blocked */ -#define BST_UNMOUNTED 1 /* User unmounted device */ +#define BST_UNMOUNTED 1 /* User unmounted device */ #define BST_WAITING_FOR_SYSOP 2 /* Waiting for operator to mount tape */ #define BST_DOING_ACQUIRE 3 /* Opening/validating/moving tape */ #define BST_WRITING_LABEL 4 /* Labeling a tape */ @@ -112,69 +112,71 @@ /* Volume Catalog Information structure definition */ typedef struct s_volume_catalog_info { /* Media info for the current Volume */ - uint32_t VolCatJobs; /* number of jobs on this Volume */ - uint32_t VolCatFiles; /* Number of files */ - uint32_t VolCatBlocks; /* Number of blocks */ - uint64_t VolCatBytes; /* Number of bytes written */ - uint32_t VolCatMounts; /* Number of mounts this volume */ - uint32_t VolCatErrors; /* Number of errors this volume */ - uint32_t VolCatWrites; /* Number of writes this volume */ - uint32_t VolCatReads; /* Number of reads this volume */ - uint32_t VolCatRecycles; /* Number of recycles this volume */ - int32_t Slot; /* Slot in changer */ - uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ - uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ - uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ + uint32_t VolCatJobs; /* number of jobs on this Volume */ + uint32_t VolCatFiles; /* Number of files */ + uint32_t VolCatBlocks; /* Number of blocks */ + uint64_t VolCatBytes; /* Number of bytes written */ + uint32_t VolCatMounts; /* Number of mounts this volume */ + uint32_t VolCatErrors; /* Number of errors this volume */ + uint32_t VolCatWrites; /* Number of writes this volume */ + uint32_t VolCatReads; /* Number of reads this volume */ + uint32_t VolCatRecycles; /* Number of recycles this volume */ + int32_t Slot; /* Slot in changer */ + uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ + uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ + uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ uint64_t VolCatCapacityBytes; /* capacity estimate */ - char VolCatStatus[20]; /* Volume status */ + char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ } VOLUME_CAT_INFO; typedef struct s_steal_lock { - pthread_t no_wait_id; /* id of no wait thread */ - int dev_blocked; /* state */ + pthread_t no_wait_id; /* id of no wait thread */ + int dev_blocked; /* state */ } bsteal_lock_t; /* Device structure definition */ typedef struct s_device { - struct s_device *next; /* pointer to next open device */ - void *attached_jcrs; /* attached JCR list */ - pthread_mutex_t mutex; /* access control */ - pthread_cond_t wait; /* thread wait variable */ + struct s_device *next; /* pointer to next open device */ + struct s_device *prev; /* pointer to prev open device */ + void *attached_jcrs; /* attached JCR list */ + pthread_mutex_t mutex; /* access control */ + pthread_cond_t wait; /* thread wait variable */ pthread_cond_t wait_next_vol; /* wait for tape to be mounted */ - pthread_t no_wait_id; /* this thread must not wait */ - int dev_blocked; /* set if we must wait (i.e. change tape) */ - int num_waiting; /* number of threads waiting */ - int num_writers; /* number of writing threads */ - int use_count; /* usage count on this device */ - int fd; /* file descriptor */ - int capabilities; /* capabilities mask */ - int state; /* state mask */ - int dev_errno; /* Our own errno */ - int mode; /* read/write modes */ - char *dev_name; /* device name */ - char *errmsg; /* nicely edited error message */ - uint32_t block_num; /* current block number base 0 */ - uint32_t file; /* current file number base 0 */ - uint64_t file_addr; /* Current file read/write address */ - uint32_t EndBlock; /* last block written */ - uint32_t EndFile; /* last file written */ - uint32_t min_block_size; /* min block size */ - uint32_t max_block_size; /* max block size */ - uint32_t max_volume_jobs; /* max jobs to put on one volume */ - uint64_t max_volume_files; /* max files to put on one volume */ - uint64_t max_volume_size; /* max bytes to put on one volume */ - uint64_t max_file_size; /* max file size to put in one file on volume */ - uint64_t volume_capacity; /* advisory capacity */ - uint32_t max_rewind_wait; /* max secs to allow for rewind */ - uint32_t max_open_wait; /* max secs to allow for open */ - void *device; /* pointer to Device Resource */ - btimer_id tid; /* timer id */ - - VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ - VOLUME_LABEL VolHdr; /* Actual volume label */ + pthread_t no_wait_id; /* this thread must not wait */ + int dev_blocked; /* set if we must wait (i.e. change tape) */ + int num_waiting; /* number of threads waiting */ + int num_writers; /* number of writing threads */ + int use_count; /* usage count on this device */ + int fd; /* file descriptor */ + int capabilities; /* capabilities mask */ + int state; /* state mask */ + int dev_errno; /* Our own errno */ + int mode; /* read/write modes */ + char *dev_name; /* device name */ + char *errmsg; /* nicely edited error message */ + uint32_t block_num; /* current block number base 0 */ + uint32_t file; /* current file number base 0 */ + uint64_t file_addr; /* Current file read/write address */ + uint32_t EndBlock; /* last block written */ + uint32_t EndFile; /* last file written */ + uint32_t min_block_size; /* min block size */ + uint32_t max_block_size; /* max block size */ + uint32_t max_volume_jobs; /* max jobs to put on one volume */ + uint64_t max_volume_files; /* max files to put on one volume */ + uint64_t max_volume_size; /* max bytes to put on one volume */ + uint64_t max_file_size; /* max file size to put in one file on volume */ + uint64_t volume_capacity; /* advisory capacity */ + uint32_t max_rewind_wait; /* max secs to allow for rewind */ + uint32_t max_open_wait; /* max secs to allow for open */ + uint32_t max_open_vols; /* max simultaneous open volumes */ + void *device; /* pointer to Device Resource */ + btimer_id tid; /* timer id */ + + VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ + VOLUME_LABEL VolHdr; /* Actual volume label */ } DEVICE; @@ -213,7 +215,7 @@ typedef struct s_device { * dependent. Arrgggg! */ #ifndef MTEOM -#ifdef MTSEOD +#ifdef MTSEOD #define MTEOM MTSEOD #endif #ifdef MTEOD diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 339246e335..6f0b4db6ff 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -28,7 +28,7 @@ uint32_t new_VolSessionId(); /* From acquire.c */ -int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); int release_device(JCR *jcr, DEVICE *dev); diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index b342433014..864b0534ad 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -99,6 +99,7 @@ static struct res_items dev_items[] = { {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0}, {"maximumchangerwait", store_pint, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 2 * 60}, {"maximumopenwait", store_pint, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60}, + {"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1}, {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0}, {"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}, diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 80c0f98a58..aead24a378 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -77,6 +77,7 @@ struct s_res_dev { uint32_t max_changer_wait; /* Changer timeout */ uint32_t max_rewind_wait; /* maximum secs to wait for rewind */ uint32_t max_open_wait; /* maximum secs to wait for open */ + uint32_t max_open_vols; /* maximum simultaneous open volumes */ uint32_t min_block_size; /* min block size */ uint32_t max_block_size; /* max block size */ uint32_t max_volume_jobs; /* max jobs to put on one volume */ diff --git a/bacula/src/version.h b/bacula/src/version.h index 9bcd124c6c..50be4a7ac7 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.30" #define VSTRING "1" -#define DATE "26 January 2003" -#define LSMDATE "26Jan03" +#define DATE "1 February 2003" +#define LSMDATE "01Feb03" /* Debug flags */ #define DEBUG 1 -- 2.39.2