Add support for using mtree(5) manifest files to define the image

to be created. The support is based on mtree version 2.0, as used
in libarchive, but adds new features on top of it.

The current implementation is fully functional, but is envisioned
to grow at least the following additional features over time:
o   Add support for the /include special command so that manifest
    files can be constructed using includable fragments.
o   Add support specifying a search path to locate content files.
o   Content file filters: commands that provide file contents on
    stdout.

The manifest file eliminates the need to first construct a tree
as root in order to create an image and allows images (releases)
to be created directly from object trees and/or source trees.

Reviewed by:	deo
Sponsored by:	Juniper Networks, Inc
This commit is contained in:
marcel 2011-06-19 18:34:49 +00:00
parent 6842f5f27f
commit 20c059f23d
7 changed files with 1111 additions and 18 deletions

View File

@ -7,6 +7,7 @@ CFLAGS+=-I${.CURDIR}
SRCS= cd9660.c ffs.c \
getid.c \
makefs.c \
mtree.c \
walk.c
MAN= makefs.8
@ -26,4 +27,7 @@ SRCS+= misc.c spec.c
.PATH: ${.CURDIR}/../../sys/ufs/ffs
SRCS+= ffs_tables.c
DPADD= ${LIBSBUF}
LDADD= -lsbuf
.include <bsd.prog.mk>

View File

@ -294,10 +294,12 @@ cd9660_write_file(FILE *fd, cd9660node *writenode)
INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
__func__, (int)inode->st.st_ino, inode->ino));
inode->flags |= FI_WRITTEN;
cd9660_compute_full_filename(writenode,
temp_file_name, 0);
if (writenode->node->contents == NULL)
cd9660_compute_full_filename(writenode,
temp_file_name, 0);
ret = cd9660_copy_file(fd, writenode->fileDataSector,
temp_file_name);
(writenode->node->contents != NULL) ?
writenode->node->contents : temp_file_name);
if (ret == 0)
goto out;
}

View File

@ -776,9 +776,11 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
continue; /* skip hard-linked entries */
cur->inode->flags |= FI_WRITTEN;
if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
>= sizeof(path))
errx(1, "Pathname too long.");
if (cur->contents == NULL) {
if (snprintf(path, sizeof(path), "%s/%s", dir,
cur->name) >= sizeof(path))
errx(1, "Pathname too long.");
}
if (cur->child != NULL)
continue; /* child creates own inode */
@ -802,7 +804,8 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
if (membuf != NULL) {
ffs_write_file(&din, cur->inode->ino, membuf, fsopts);
} else if (S_ISREG(cur->type)) {
ffs_write_file(&din, cur->inode->ino, path, fsopts);
ffs_write_file(&din, cur->inode->ino,
(cur->contents) ? cur->contents : path, fsopts);
} else {
assert (! S_ISDIR(cur->type));
ffs_write_inode(&din, cur->inode->ino, fsopts);

View File

@ -40,7 +40,7 @@
.Os
.Sh NAME
.Nm makefs
.Nd create a file system image from a directory tree
.Nd create a file system image from a directory tree or a mtree manifest
.Sh SYNOPSIS
.Nm
.Op Fl x
@ -57,14 +57,16 @@
.Op Fl s Ar image-size
.Op Fl t Ar fs-type
.Ar image-file
.Ar directory
.Ar directory | manifest
.Sh DESCRIPTION
The utility
.Nm
creates a file system image into
.Ar image-file
from the directory tree
.Ar directory .
.Ar directory
or from the mtree manifest
.Ar manifest .
No special devices or privileges are required to perform this task.
.Pp
The options are as follows:
@ -106,6 +108,8 @@ as an
.Xr mtree 8
.Sq specfile
specification.
This option has no effect when the image is created from a mtree manifest
rather than a directory.
.Pp
If a specfile entry exists in the underlying file system, its
permissions and modification time will be used unless specifically
@ -330,6 +334,7 @@ Use RockRidge extensions (for longer filenames, etc.).
Volume set identifier of the image.
.El
.Sh SEE ALSO
.Xr mtree 5 ,
.Xr mtree 8 ,
.Xr newfs 8
.Sh HISTORY

View File

@ -38,6 +38,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@ -80,11 +82,13 @@ int main(int, char *[]);
int
main(int argc, char *argv[])
{
struct stat sb;
struct timeval start;
fstype_t *fstype;
fsinfo_t fsoptions;
fsnode *root;
int ch, len;
char *subtree;
char *specfile;
setprogname(argv[0]);
@ -244,26 +248,47 @@ main(int argc, char *argv[])
if (fsoptions.onlyspec != 0 && specfile == NULL)
errx(1, "-x requires -F mtree-specfile.");
/* walk the tree */
TIMER_START(start);
root = walk_dir(argv[1], NULL);
TIMER_RESULTS(start, "walk_dir");
/* Accept '-' as meaning "read from standard input". */
if (strcmp(argv[1], "-") == 0)
sb.st_mode = S_IFREG;
else {
if (stat(argv[1], &sb) == -1)
err(1, "Can't stat `%s'", argv[1]);
}
switch (sb.st_mode & S_IFMT) {
case S_IFDIR: /* walk the tree */
subtree = argv[1];
TIMER_START(start);
root = walk_dir(subtree, NULL);
TIMER_RESULTS(start, "walk_dir");
break;
case S_IFREG: /* read the manifest file */
subtree = ".";
TIMER_START(start);
root = read_mtree(argv[1], NULL);
TIMER_RESULTS(start, "manifest");
break;
default:
errx(1, "%s: not a file or directory", argv[1]);
/* NOTREACHED */
}
if (specfile) { /* apply a specfile */
TIMER_START(start);
apply_specfile(specfile, argv[1], root, fsoptions.onlyspec);
apply_specfile(specfile, subtree, root, fsoptions.onlyspec);
TIMER_RESULTS(start, "apply_specfile");
}
if (debug & DEBUG_DUMP_FSNODES) {
printf("\nparent: %s\n", argv[1]);
printf("\nparent: %s\n", subtree);
dump_fsnodes(".", root);
putchar('\n');
}
/* build the file system */
TIMER_START(start);
fstype->make_fs(argv[0], argv[1], root, &fsoptions);
fstype->make_fs(argv[0], subtree, root, &fsoptions);
TIMER_RESULTS(start, "make_fs");
free_fsnodes(root);
@ -311,7 +336,7 @@ usage(void)
"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[-N userdb-dir] image-file directory\n",
"\t[-N userdb-dir] image-file directory | manifest\n",
prog);
exit(1);
}

View File

@ -93,11 +93,13 @@ typedef struct _fsnode {
uint32_t type; /* type of entry */
fsinode *inode; /* actual inode data */
char *symlink; /* symlink target */
char *contents; /* file to provide contents */
char *name; /* file name */
int flags; /* misc flags */
} fsnode;
#define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */
#define FSNODE_F_OPTIONAL 0x02 /* fsnode is optional */
/*
* fsinfo_t - contains various settings and parameters pertaining to
@ -147,6 +149,7 @@ typedef struct {
void apply_specfile(const char *, const char *, fsnode *, int);
void dump_fsnodes(const char *, fsnode *);
const char * inode_type(mode_t);
fsnode * read_mtree(const char *, fsnode *);
int set_option(option_t *, const char *, const char *);
fsnode * walk_dir(const char *, fsnode *);
void free_fsnodes(fsnode *);

1051
usr.sbin/makefs/mtree.c Normal file

File diff suppressed because it is too large Load Diff