From 6a91f7512a627f21459393f071dd5680a1e55b16 Mon Sep 17 00:00:00 2001 From: brooks Date: Thu, 14 Mar 2013 22:57:27 +0000 Subject: [PATCH] MFC all change to makefs through r247052. Key functional changes include: r239562: Add -p flag to create the image as a sparse file. r242501: If no contents keyword is specified, the default for files is the named file. r247041: Add a -D flag that causes duplicate entries in an mtree manifest to be treated as warnings rather than errors. r247042: Fix the -N option in manifest mode by using pwcache(3). This also speeds up image creation appreciably. r247043: Allow '.' components in manifest paths. They are always the first component of mtree -C and install -M output and are easily skipped. r247052: Support hardlinks in manifest files by the same logic as the treewalk code. git-svn-id: svn://svn.freebsd.org/base/stable/9@248293 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- usr.sbin/makefs/cd9660.c | 20 +---- usr.sbin/makefs/cd9660/cd9660_eltorito.c | 2 +- usr.sbin/makefs/cd9660/cd9660_write.c | 4 +- usr.sbin/makefs/cd9660/iso9660_rrip.c | 2 +- usr.sbin/makefs/ffs.c | 31 +++++-- usr.sbin/makefs/ffs/ffs_alloc.c | 5 +- usr.sbin/makefs/ffs/ffs_extern.h | 6 +- usr.sbin/makefs/ffs/ffs_subr.c | 8 +- usr.sbin/makefs/ffs/ufs_bmap.c | 2 - usr.sbin/makefs/makefs.8 | 8 +- usr.sbin/makefs/makefs.c | 12 ++- usr.sbin/makefs/makefs.h | 4 + usr.sbin/makefs/mtree.c | 105 +++++++++++++++++++---- usr.sbin/makefs/walk.c | 5 +- 14 files changed, 146 insertions(+), 68 deletions(-) diff --git a/usr.sbin/makefs/cd9660.c b/usr.sbin/makefs/cd9660.c index 83cc9f119..2b33446d0 100644 --- a/usr.sbin/makefs/cd9660.c +++ b/usr.sbin/makefs/cd9660.c @@ -621,10 +621,6 @@ static void cd9660_finalize_PVD(void) { time_t tim; - unsigned char *temp; - - /* Copy the root directory record */ - temp = (unsigned char *) &diskStructure.primaryDescriptor; /* root should be a fixed size of 34 bytes since it has no name */ memcpy(diskStructure.primaryDescriptor.root_directory_record, @@ -1051,7 +1047,7 @@ static cd9660node * cd9660_rename_filename(cd9660node *iter, int num, int delete_chars) { int i = 0; - int numbts, dot, semi, digit, digits, temp, powers, multiplier, count; + int numbts, digit, digits, temp, powers, count; char *naming; int maxlength; char *tmp; @@ -1073,7 +1069,6 @@ cd9660_rename_filename(cd9660node *iter, int num, int delete_chars) powers = 1; count = 0; digits = 1; - multiplier = 1; while (((int)(i / powers) ) >= 10) { digits++; powers = powers * 10; @@ -1088,15 +1083,9 @@ cd9660_rename_filename(cd9660node *iter, int num, int delete_chars) } */ - dot = -1; - semi = -1; while (count < maxlength) { - if (*naming == '.') - dot = count; - else if (*naming == ';') { - semi = count; + if (*naming == ';') break; - } naming++; count++; } @@ -1527,7 +1516,6 @@ cd9660_generate_path_table(void) cd9660node *last = dirNode; int pathTableSize = 0; /* computed as we go */ int counter = 1; /* root gets a count of 0 */ - int parentRecNum = 0; /* root's parent is '0' */ TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head; TAILQ_INIT(&pt_head); @@ -1557,10 +1545,6 @@ cd9660_generate_path_table(void) } last = dirNode; - parentRecNum = 1; - if (dirNode->parent != 0) - parentRecNum = dirNode->parent->ptnumber; - /* Push children onto queue */ TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) { /* diff --git a/usr.sbin/makefs/cd9660/cd9660_eltorito.c b/usr.sbin/makefs/cd9660/cd9660_eltorito.c index a709d627b..f26a5549b 100644 --- a/usr.sbin/makefs/cd9660/cd9660_eltorito.c +++ b/usr.sbin/makefs/cd9660/cd9660_eltorito.c @@ -610,7 +610,7 @@ cd9660_write_boot(FILE *fd) e->entry_type); } /* - * It doesnt matter which one gets written + * It doesn't matter which one gets written * since they are the same size */ fwrite(&(e->entry_data.VE), 1, 32, fd); diff --git a/usr.sbin/makefs/cd9660/cd9660_write.c b/usr.sbin/makefs/cd9660/cd9660_write.c index 017395ec1..f27a76f89 100644 --- a/usr.sbin/makefs/cd9660/cd9660_write.c +++ b/usr.sbin/makefs/cd9660/cd9660_write.c @@ -305,10 +305,10 @@ cd9660_write_file(FILE *fd, cd9660node *writenode) } } else { /* - * Here is a new revelation that ECMA didnt explain + * Here is a new revelation that ECMA didn't explain * (at least not well). * ALL . and .. records store the name "\0" and "\1" - * resepctively. So, for each directory, we have to + * respectively. So, for each directory, we have to * make a new node. * * This is where it gets kinda messy, since we have to diff --git a/usr.sbin/makefs/cd9660/iso9660_rrip.c b/usr.sbin/makefs/cd9660/iso9660_rrip.c index 68de7ccc0..39e0acfe0 100644 --- a/usr.sbin/makefs/cd9660/iso9660_rrip.c +++ b/usr.sbin/makefs/cd9660/iso9660_rrip.c @@ -298,7 +298,7 @@ cd9660_susp_initialize_node(cd9660node *node) * CE: is added for us where needed * ST: not sure if it is even required, but if so, should be * handled by the CE code - * PD: isnt needed (though might be added for testing) + * PD: isn't needed (though might be added for testing) * SP: is stored ONLY on the . record of the root directory * ES: not sure */ diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c index 367abfee5..0417d8609 100644 --- a/usr.sbin/makefs/ffs.c +++ b/usr.sbin/makefs/ffs.c @@ -145,7 +145,7 @@ static void *ffs_build_dinode2(struct ufs2_dinode *, dirbuf_t *, fsnode *, int sectorsize; /* XXX: for buf.c::getblk() */ - /* publically visible functions */ + /* publicly visible functions */ void ffs_prep_opts(fsinfo_t *fsopts) @@ -493,13 +493,25 @@ ffs_create_image(const char *image, fsinfo_t *fsopts) bufsize = sfs.f_iosize; #endif bufrem = fsopts->size; - if (debug & DEBUG_FS_CREATE_IMAGE) - printf( - "zero-ing image `%s', %lld sectors, using %d byte chunks\n", - image, (long long)bufrem, bufsize); - if ((buf = calloc(1, bufsize)) == NULL) { - warn("Can't create buffer for sector"); - return (-1); + if (fsopts->sparse) { + if (ftruncate(fsopts->fd, bufrem) == -1) { + warn("sparse option disabled.\n"); + fsopts->sparse = 0; + } + } + if (fsopts->sparse) { + /* File truncated at bufrem. Remaining is 0 */ + bufrem = 0; + buf = NULL; + } else { + if (debug & DEBUG_FS_CREATE_IMAGE) + printf("zero-ing image `%s', %lld sectors, " + "using %d byte chunks\n", image, (long long)bufrem, + bufsize); + if ((buf = calloc(1, bufsize)) == NULL) { + warn("Can't create buffer for sector"); + return (-1); + } } while (bufrem > 0) { i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); @@ -511,7 +523,8 @@ ffs_create_image(const char *image, fsinfo_t *fsopts) } bufrem -= i; } - free(buf); + if (buf) + free(buf); /* make the file system */ if (debug & DEBUG_FS_CREATE_IMAGE) diff --git a/usr.sbin/makefs/ffs/ffs_alloc.c b/usr.sbin/makefs/ffs/ffs_alloc.c index f676a39af..afab86995 100644 --- a/usr.sbin/makefs/ffs/ffs_alloc.c +++ b/usr.sbin/makefs/ffs/ffs_alloc.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include "makefs.h" @@ -439,8 +440,8 @@ ffs_blkfree(struct inode *ip, daddr_t bno, long size) } cg = dtog(fs, bno); if (bno >= fs->fs_size) { - warnx("bad block %lld, ino %llu", (long long)bno, - (unsigned long long)ip->i_number); + warnx("bad block %lld, ino %ju", (long long)bno, + (uintmax_t)ip->i_number); return; } error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)), diff --git a/usr.sbin/makefs/ffs/ffs_extern.h b/usr.sbin/makefs/ffs/ffs_extern.h index d95e69bf0..7755823c1 100644 --- a/usr.sbin/makefs/ffs/ffs_extern.h +++ b/usr.sbin/makefs/ffs/ffs_extern.h @@ -35,6 +35,8 @@ #include "ffs/buf.h" +struct inode; + /* * Structure used to pass around logical block paths generated by * ufs_getlbns and used by truncate and bmap code. @@ -42,12 +44,10 @@ struct indir { daddr_t in_lbn; /* Logical block number. */ int in_off; /* Offset in buffer. */ - int in_exists; /* Flag if the block exists. */ }; /* ffs.c */ -void panic(const char *, ...) - __attribute__((__noreturn__,__format__(__printf__,1,2))); +_Noreturn void panic(const char *, ...) __printflike(1, 2); /* ffs_alloc.c */ int ffs_alloc(struct inode *, daddr_t, daddr_t, int, daddr_t *); diff --git a/usr.sbin/makefs/ffs/ffs_subr.c b/usr.sbin/makefs/ffs/ffs_subr.c index b857a581b..b55174db0 100644 --- a/usr.sbin/makefs/ffs/ffs_subr.c +++ b/usr.sbin/makefs/ffs/ffs_subr.c @@ -38,11 +38,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include "ffs/ffs_extern.h" #include "ffs/ufs_bswap.h" -void panic __P((const char *, ...)) - __attribute__((__noreturn__,__format__(__printf__,1,2))); - /* * Update the frsum fields to reflect addition or deletion * of some frags. @@ -80,8 +78,8 @@ ffs_fragacct_swap(struct fs *fs, int fragmap, int32_t fraglist[], int cnt, int n * block operations * * check if a block is available - * returns true if all the correponding bits in the free map are 1 - * returns false if any corresponding bit in the free map is 0 + * returns true if all the corresponding bits in the free map are 1 + * returns false if any corresponding bit in the free map is 0 */ int ffs_isblock(fs, cp, h) diff --git a/usr.sbin/makefs/ffs/ufs_bmap.c b/usr.sbin/makefs/ffs/ufs_bmap.c index 85c1d8759..b65b41636 100644 --- a/usr.sbin/makefs/ffs/ufs_bmap.c +++ b/usr.sbin/makefs/ffs/ufs_bmap.c @@ -117,7 +117,6 @@ ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump) */ ap->in_lbn = metalbn; ap->in_off = off = NIADDR - i; - ap->in_exists = 0; ap++; for (++numlevels; i <= NIADDR; i++) { /* If searching for a meta-data block, quit when found. */ @@ -131,7 +130,6 @@ ufs_getlbns(struct inode *ip, daddr_t bn, struct indir *ap, int *nump) ++numlevels; ap->in_lbn = metalbn; ap->in_off = off; - ap->in_exists = 0; ++ap; metalbn -= -1 + (off << lbc); diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8 index cc6e38928..81bf3341b 100644 --- a/usr.sbin/makefs/makefs.8 +++ b/usr.sbin/makefs/makefs.8 @@ -35,7 +35,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 30, 2012 +.Dd August 22, 2012 .Dt MAKEFS 8 .Os .Sh NAME @@ -43,7 +43,7 @@ .Nd create a file system image from a directory tree or a mtree manifest .Sh SYNOPSIS .Nm -.Op Fl x +.Op Fl Dpx .Op Fl B Ar byte-order .Op Fl b Ar free-blocks .Op Fl d Ar debug-mask @@ -106,6 +106,8 @@ An optional suffix may be provided to indicate that .Ar free-blocks indicates a percentage of the calculated image size. +.It Fl D +Treat duplicate paths in an mtree manifest as warnings not error. .It Fl d Ar debug-mask Enable various levels of debugging, depending upon which bits are set in @@ -188,6 +190,8 @@ Set file system specific options. .Ar fs-options is a comma separated list of options. Valid file system specific options are detailed below. +.It Fl p +Create the image as a sparse file. .It Fl S Ar sector-size Set the file system sector size to .Ar sector-size . diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c index 623ca8ac4..03ff1ac38 100644 --- a/usr.sbin/makefs/makefs.c +++ b/usr.sbin/makefs/makefs.c @@ -73,6 +73,7 @@ static fstype_t fstypes[] = { }; u_int debug; +int dupsok; struct timespec start_time; static fstype_t *get_fstype(const char *); @@ -112,7 +113,7 @@ main(int argc, char *argv[]) start_time.tv_sec = start.tv_sec; start_time.tv_nsec = start.tv_usec * 1000; - while ((ch = getopt(argc, argv, "B:b:d:f:F:M:m:N:o:s:S:t:x")) != -1) { + while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:ps:S:t:x")) != -1) { switch (ch) { case 'B': @@ -148,6 +149,10 @@ main(int argc, char *argv[]) } break; + case 'D': + dupsok = 1; + break; + case 'd': debug = strtoll(optarg, NULL, 0); break; @@ -199,6 +204,9 @@ main(int argc, char *argv[]) } break; } + case 'p': + fsoptions.sparse = 1; + break; case 's': fsoptions.minsize = fsoptions.maxsize = @@ -346,7 +354,7 @@ usage(void) fprintf(stderr, "usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n" "\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-s image-size]\n" -"\t[-b free-blocks] [-f free-files] [-F mtree-specfile] [-x]\n" +"\t[-b free-blocks] [-f free-files] [-F mtree-specfile] [-px]\n" "\t[-N userdb-dir] image-file directory | manifest [extra-directory ...]\n", prog); exit(1); diff --git a/usr.sbin/makefs/makefs.h b/usr.sbin/makefs/makefs.h index f6cadeb98..c6707d93f 100644 --- a/usr.sbin/makefs/makefs.h +++ b/usr.sbin/makefs/makefs.h @@ -129,6 +129,7 @@ typedef struct { int freeblockpc; /* free block % */ int needswap; /* non-zero if byte swapping needed */ int sectorsize; /* sector size */ + int sparse; /* sparse image, don't fill it with zeros */ void *fs_specific; /* File system specific additions. */ } fsinfo_t; @@ -168,6 +169,7 @@ void cd9660_makefs(const char *, const char *, fsnode *, fsinfo_t *); extern u_int debug; +extern int dupsok; extern struct timespec start_time; /* @@ -278,6 +280,8 @@ extern struct timespec start_time; struct fs; void ffs_fragacct_swap(struct fs *, int, int32_t [], int, int); +fsinode *link_check(fsinode *); + /* * Declarations for compat routines. */ diff --git a/usr.sbin/makefs/mtree.c b/usr.sbin/makefs/mtree.c index 5d88ad6b0..c90c974d6 100644 --- a/usr.sbin/makefs/mtree.c +++ b/usr.sbin/makefs/mtree.c @@ -135,6 +135,47 @@ mtree_warning(const char *fmt, ...) fputc('\n', stderr); } +#ifndef MAKEFS_MAX_TREE_DEPTH +# define MAKEFS_MAX_TREE_DEPTH (MAXPATHLEN/2) +#endif + +/* construct path to node->name */ +static char * +mtree_file_path(fsnode *node) +{ + fsnode *pnode; + struct sbuf *sb; + char *res, *rp[MAKEFS_MAX_TREE_DEPTH]; + int depth; + + depth = 0; + rp[depth] = node->name; + for (pnode = node->parent; pnode && depth < MAKEFS_MAX_TREE_DEPTH; + pnode = pnode->parent) { + if (strcmp(pnode->name, ".") == 0) + break; + rp[++depth] = pnode->name; + } + + sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); + if (sb == NULL) { + errno = ENOMEM; + return (NULL); + } + while (depth > 0) { + sbuf_cat(sb, rp[depth--]); + sbuf_putc(sb, '/'); + } + sbuf_cat(sb, rp[depth]); + sbuf_finish(sb); + res = strdup(sbuf_data(sb)); + sbuf_delete(sb); + if (res == NULL) + errno = ENOMEM; + return res; + +} + /* mtree_resolve() sets errno to indicate why NULL was returned. */ static char * mtree_resolve(const char *spec, int *istemp) @@ -467,8 +508,8 @@ read_mtree_keywords(FILE *fp, fsnode *node) { char keyword[PATH_MAX]; char *name, *p, *value; - struct group *grent; - struct passwd *pwent; + gid_t gid; + uid_t uid; struct stat *st, sb; intmax_t num; u_long flset, flclr; @@ -544,11 +585,10 @@ read_mtree_keywords(FILE *fp, fsnode *node) error = ENOATTR; break; } - grent = getgrnam(value); - if (grent != NULL) - st->st_gid = grent->gr_gid; + if (gid_from_group(value, &gid) == 0) + st->st_gid = gid; else - error = errno; + error = EINVAL; } else error = ENOSYS; break; @@ -657,11 +697,10 @@ read_mtree_keywords(FILE *fp, fsnode *node) error = ENOATTR; break; } - pwent = getpwnam(value); - if (pwent != NULL) - st->st_uid = pwent->pw_uid; + if (uid_from_user(value, &uid) == 0) + st->st_uid = uid; else - error = errno; + error = EINVAL; } else error = ENOSYS; break; @@ -706,6 +745,12 @@ read_mtree_keywords(FILE *fp, fsnode *node) return (0); } type = S_IFREG; + } else if (node->type != 0) { + type = node->type; + if (type == S_IFREG) { + /* the named path is the default contents */ + node->contents = mtree_file_path(node); + } } else type = (node->symlink != NULL) ? S_IFLNK : S_IFDIR; @@ -734,6 +779,24 @@ read_mtree_keywords(FILE *fp, fsnode *node) return (0); } + /* + * Check for hardlinks. If the contents key is used, then the check + * will only trigger if the contents file is a link even if it is used + * by more than one file + */ + if (sb.st_nlink > 1) { + fsinode *curino; + + st->st_ino = sb.st_ino; + st->st_dev = sb.st_dev; + curino = link_check(node->inode); + if (curino != NULL) { + free(node->inode); + node->inode = curino; + node->inode->nlink++; + } + } + free(node->contents); node->contents = name; st->st_size = sb.st_size; @@ -834,8 +897,14 @@ read_mtree_spec1(FILE *fp, bool def, const char *name) if (strcmp(name, node->name) == 0) { if (def == true) { - mtree_error("duplicate definition of %s", - name); + if (!dupsok) + mtree_error( + "duplicate definition of %s", + name); + else + mtree_warning( + "duplicate definition of %s", + name); return (0); } @@ -923,15 +992,15 @@ read_mtree_spec(FILE *fp) do { *cp++ = '\0'; - /* Disallow '.' and '..' as components. */ - if (IS_DOT(pathspec) || IS_DOTDOT(pathspec)) { - mtree_error("absolute path cannot contain . " - "or .. components"); + /* Disallow '..' as a component. */ + if (IS_DOTDOT(pathspec)) { + mtree_error("absolute path cannot contain " + ".. component"); goto out; } - /* Ignore multiple adjacent slashes. */ - if (pathspec[0] != '\0') + /* Ignore multiple adjacent slashes and '.'. */ + if (pathspec[0] != '\0' && !IS_DOT(pathspec)) error = read_mtree_spec1(fp, false, pathspec); memmove(pathspec, cp, strlen(cp) + 1); cp = strchr(pathspec, '/'); diff --git a/usr.sbin/makefs/walk.c b/usr.sbin/makefs/walk.c index 96da72bb9..7af92bb7e 100644 --- a/usr.sbin/makefs/walk.c +++ b/usr.sbin/makefs/walk.c @@ -59,7 +59,6 @@ static void apply_specdir(const char *, NODE *, fsnode *, int); static void apply_specentry(const char *, NODE *, fsnode *); static fsnode *create_fsnode(const char *, const char *, const char *, struct stat *); -static fsinode *link_check(fsinode *); /* @@ -236,7 +235,7 @@ create_fsnode(const char *root, const char *path, const char *name, /* * free_fsnodes -- * Removes node from tree and frees it and all of - * its decendents. + * its descendants. */ void free_fsnodes(fsnode *node) @@ -644,7 +643,7 @@ inode_type(mode_t mode) /* This was borrowed from du.c and tweaked to keep an fsnode * pointer instead. -- dbj@netbsd.org */ -static fsinode * +fsinode * link_check(fsinode *entry) { static struct entry { -- 2.45.0