diff options
Diffstat (limited to 'bin/gensquashfs')
| -rw-r--r-- | bin/gensquashfs/dirscan.c | 321 | ||||
| -rw-r--r-- | bin/gensquashfs/mkfs.c | 216 | ||||
| -rw-r--r-- | bin/gensquashfs/mkfs.h | 72 | ||||
| -rw-r--r-- | bin/gensquashfs/options.c | 289 | ||||
| -rw-r--r-- | bin/gensquashfs/selinux.c | 78 | 
5 files changed, 976 insertions, 0 deletions
| diff --git a/bin/gensquashfs/dirscan.c b/bin/gensquashfs/dirscan.c new file mode 100644 index 0000000..dbc862c --- /dev/null +++ b/bin/gensquashfs/dirscan.c @@ -0,0 +1,321 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * fstree_from_dir.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "mkfs.h" + +#ifdef HAVE_SYS_XATTR_H +static char *get_full_path(const char *prefix, tree_node_t *node) +{ +	char *path = NULL, *new = NULL; +	size_t path_len, prefix_len; +	int ret; + +	path = fstree_get_path(node); +	if (path == NULL) +		goto fail; + +	ret = canonicalize_name(path); +	assert(ret == 0); + +	path_len = strlen(path); +	prefix_len = strlen(prefix); + +	while (prefix_len > 0 && prefix[prefix_len - 1] == '/') +		--prefix_len; + +	if (prefix_len > 0) { +		new = realloc(path, path_len + prefix_len + 2); +		if (new == NULL) +			goto fail; + +		path = new; + +		memmove(path + prefix_len + 1, path, path_len + 1); +		memcpy(path, prefix, prefix_len); +		path[prefix_len] = '/'; +	} + +	return path; +fail: +	perror("getting full path for xattr scan"); +	free(path); +	return NULL; +} + +static int xattr_from_path(sqfs_xattr_writer_t *xwr, const char *path) +{ +	char *key, *value = NULL, *buffer = NULL; +	ssize_t buflen, vallen, keylen; +	int ret; + +	buflen = llistxattr(path, NULL, 0); +	if (buflen < 0) { +		fprintf(stderr, "llistxattr %s: %s", path, strerror(errno)); +		return -1; +	} + +	if (buflen == 0) +		return 0; + +	buffer = malloc(buflen); +	if (buffer == NULL) { +		perror("xattr name buffer"); +		return -1; +	} + +	buflen = llistxattr(path, buffer, buflen); +	if (buflen == -1) { +		fprintf(stderr, "llistxattr %s: %s", path, strerror(errno)); +		goto fail; +	} + +	key = buffer; +	while (buflen > 0) { +		vallen = lgetxattr(path, key, NULL, 0); +		if (vallen == -1) { +			fprintf(stderr, "lgetxattr %s: %s", +				path, strerror(errno)); +			goto fail; +		} + +		if (vallen > 0) { +			value = calloc(1, vallen); +			if (value == NULL) { +				perror("allocating xattr value buffer"); +				goto fail; +			} + +			vallen = lgetxattr(path, key, value, vallen); +			if (vallen == -1) { +				fprintf(stderr, "lgetxattr %s: %s\n", +					path, strerror(errno)); +				goto fail; +			} + +			ret = sqfs_xattr_writer_add(xwr, key, value, vallen); +			if (ret) { +				sqfs_perror(path, +					    "storing xattr key-value pairs", +					    ret); +				goto fail; +			} + +			free(value); +			value = NULL; +		} + +		keylen = strlen(key) + 1; +		buflen -= keylen; +		key += keylen; +	} + +	free(buffer); +	return 0; +fail: +	free(value); +	free(buffer); +	return -1; +} +#endif + +#ifdef _WIN32 +int fstree_from_dir(fstree_t *fs, const char *path, void *selinux_handle, +		    sqfs_xattr_writer_t *xwr, unsigned int flags) +{ +	(void)fs; (void)path; (void)selinux_handle; (void)xwr; (void)flags; +	fputs("Packing a directory is not supported on Windows.\n", stderr); +	return -1; +} +#else +static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle, +			  sqfs_xattr_writer_t *xwr, unsigned int flags, +			  tree_node_t *node) +{ +	char *path; +	int ret; + +	ret = sqfs_xattr_writer_begin(xwr); +	if (ret) { +		sqfs_perror(node->name, "recoding xattr key-value pairs\n", +			    ret); +		return -1; +	} + +#ifdef HAVE_SYS_XATTR_H +	if (flags & DIR_SCAN_READ_XATTR) { +		path = get_full_path(path_prefix, node); +		if (path == NULL) +			return -1; + +		ret = xattr_from_path(xwr, path); +		free(path); + +		if (ret) +			return -1; +	} +#else +	(void)path_prefix; +#endif + +	if (selinux_handle != NULL) { +		path = fstree_get_path(node); +		if (path == NULL) { +			perror("reconstructing absolute path"); +			return -1; +		} + +		ret = selinux_relable_node(selinux_handle, xwr, node, path); +		free(path); + +		if (ret) +			return -1; +	} + +	if (sqfs_xattr_writer_end(xwr, &node->xattr_idx)) { +		sqfs_perror(node->name, "completing xattr key-value pairs", +			    ret); +		return -1; +	} + +	if (S_ISDIR(node->mode)) { +		node = node->data.dir.children; + +		while (node != NULL) { +			if (xattr_xcan_dfs(path_prefix, selinux_handle, xwr, +					   flags, node)) { +				return -1; +			} + +			node = node->next; +		} +	} + +	return 0; +} + +static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, +			dev_t devstart, unsigned int flags) +{ +	char *extra = NULL; +	struct dirent *ent; +	struct stat sb; +	tree_node_t *n; +	int childfd; +	DIR *dir; + +	dir = fdopendir(dir_fd); +	if (dir == NULL) { +		perror("fdopendir"); +		close(dir_fd); +		return -1; +	} + +	/* XXX: fdopendir can dup and close dir_fd internally +	   and still be compliant with the spec. */ +	dir_fd = dirfd(dir); + +	for (;;) { +		errno = 0; +		ent = readdir(dir); + +		if (ent == NULL) { +			if (errno) { +				perror("readdir"); +				goto fail; +			} +			break; +		} + +		if (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, ".")) +			continue; + +		if (fstatat(dir_fd, ent->d_name, &sb, AT_SYMLINK_NOFOLLOW)) { +			perror(ent->d_name); +			goto fail; +		} + +		if ((flags & DIR_SCAN_ONE_FILESYSTEM) && sb.st_dev != devstart) +			continue; + +		if (S_ISLNK(sb.st_mode)) { +			extra = calloc(1, sb.st_size + 1); +			if (extra == NULL) +				goto fail_rdlink; + +			if (readlinkat(dir_fd, ent->d_name, +				       extra, sb.st_size) < 0) { +				goto fail_rdlink; +			} + +			extra[sb.st_size] = '\0'; +		} + +		if (!(flags & DIR_SCAN_KEEP_TIME)) +			sb.st_mtime = fs->defaults.st_mtime; + +		n = fstree_mknode(root, ent->d_name, strlen(ent->d_name), +				  extra, &sb); +		if (n == NULL) { +			perror("creating tree node"); +			goto fail; +		} + +		free(extra); +		extra = NULL; + +		if (S_ISDIR(n->mode)) { +			childfd = openat(dir_fd, n->name, O_DIRECTORY | +					 O_RDONLY | O_CLOEXEC); +			if (childfd < 0) { +				perror(n->name); +				goto fail; +			} + +			if (populate_dir(childfd, fs, n, devstart, flags)) +				goto fail; +		} +	} + +	closedir(dir); +	return 0; +fail_rdlink: +	perror("readlink"); +fail: +	closedir(dir); +	free(extra); +	return -1; +} + +int fstree_from_dir(fstree_t *fs, const char *path, void *selinux_handle, +		    sqfs_xattr_writer_t *xwr, unsigned int flags) +{ +	struct stat sb; +	int fd; + +	fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); +	if (fd < 0) { +		perror(path); +		return -1; +	} + +	if (fstat(fd, &sb)) { +		perror(path); +		close(fd); +		return -1; +	} + +	if (populate_dir(fd, fs, fs->root, sb.st_dev, flags)) +		return -1; + +	if (xwr != NULL && (selinux_handle != NULL || +			    (flags & DIR_SCAN_READ_XATTR))) { +		if (xattr_xcan_dfs(path, selinux_handle, xwr, flags, fs->root)) +			return -1; +	} + +	return 0; +} +#endif diff --git a/bin/gensquashfs/mkfs.c b/bin/gensquashfs/mkfs.c new file mode 100644 index 0000000..9ffbb94 --- /dev/null +++ b/bin/gensquashfs/mkfs.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * mkfs.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "mkfs.h" + +static int set_working_dir(options_t *opt) +{ +	const char *ptr; +	char *path; + +	if (opt->packdir != NULL) { +		if (chdir(opt->packdir)) { +			perror(opt->packdir); +			return -1; +		} +		return 0; +	} + +	ptr = strrchr(opt->infile, '/'); +	if (ptr == NULL) +		return 0; + +	path = strndup(opt->infile, ptr - opt->infile); +	if (path == NULL) { +		perror("constructing input directory path"); +		return -1; +	} + +	if (chdir(path)) { +		perror(path); +		free(path); +		return -1; +	} + +	free(path); +	return 0; +} + +static int pack_files(sqfs_block_processor_t *data, fstree_t *fs, +		      options_t *opt) +{ +	sqfs_inode_generic_t **inode_ptr; +	sqfs_u64 filesize; +	sqfs_file_t *file; +	tree_node_t *node; +	const char *path; +	char *node_path; +	file_info_t *fi; +	int flags; +	int ret; + +	if (set_working_dir(opt)) +		return -1; + +	for (fi = fs->files; fi != NULL; fi = fi->next) { +		if (fi->input_file == NULL) { +			node = container_of(fi, tree_node_t, data.file); + +			node_path = fstree_get_path(node); +			if (node_path == NULL) { +				perror("reconstructing file path"); +				return -1; +			} + +			ret = canonicalize_name(node_path); +			assert(ret == 0); + +			path = node_path; +		} else { +			node_path = NULL; +			path = fi->input_file; +		} + +		if (!opt->cfg.quiet) +			printf("packing %s\n", path); + +		file = sqfs_open_file(path, SQFS_FILE_OPEN_READ_ONLY); +		if (file == NULL) { +			perror(path); +			free(node_path); +			return -1; +		} + +		flags = 0; +		filesize = file->get_size(file); + +		if (opt->no_tail_packing && filesize > opt->cfg.block_size) +			flags |= SQFS_BLK_DONT_FRAGMENT; + +		inode_ptr = (sqfs_inode_generic_t **)&fi->user_ptr; + +		ret = write_data_from_file(path, data, inode_ptr, file, flags); +		sqfs_destroy(file); +		free(node_path); + +		if (ret) +			return -1; +	} + +	return 0; +} + +static int relabel_tree_dfs(const char *filename, sqfs_xattr_writer_t *xwr, +			    tree_node_t *n, void *selinux_handle) +{ +	char *path = fstree_get_path(n); +	int ret; + +	if (path == NULL) { +		perror("getting absolute node path for SELinux relabeling"); +		return -1; +	} + +	ret = sqfs_xattr_writer_begin(xwr); +	if (ret) { +		sqfs_perror(filename, "recording xattr key-value pairs", ret); +		return -1; +	} + +	if (selinux_relable_node(selinux_handle, xwr, n, path)) { +		free(path); +		return -1; +	} + +	ret = sqfs_xattr_writer_end(xwr, &n->xattr_idx); +	if (ret) { +		sqfs_perror(filename, "flushing completed key-value pairs", +			    ret); +		return -1; +	} + +	free(path); + +	if (S_ISDIR(n->mode)) { +		for (n = n->data.dir.children; n != NULL; n = n->next) { +			if (relabel_tree_dfs(filename, xwr, n, selinux_handle)) +				return -1; +		} +	} + +	return 0; +} + +static int read_fstree(fstree_t *fs, options_t *opt, sqfs_xattr_writer_t *xwr, +		       void *selinux_handle) +{ +	FILE *fp; +	int ret; + +	if (opt->infile == NULL) { +		return fstree_from_dir(fs, opt->packdir, selinux_handle, +				       xwr, opt->dirscan_flags); +	} + +	fp = fopen(opt->infile, "rb"); +	if (fp == NULL) { +		perror(opt->infile); +		return -1; +	} + +	ret = fstree_from_file(fs, opt->infile, fp); +	fclose(fp); + +	if (ret == 0 && selinux_handle != NULL) +		ret = relabel_tree_dfs(opt->cfg.filename, xwr, +				       fs->root, selinux_handle); + +	return ret; +} + +int main(int argc, char **argv) +{ +	int status = EXIT_FAILURE; +	void *sehnd = NULL; +	sqfs_writer_t sqfs; +	options_t opt; + +	process_command_line(&opt, argc, argv); + +	if (sqfs_writer_init(&sqfs, &opt.cfg)) +		return EXIT_FAILURE; + +	if (opt.selinux != NULL) { +		sehnd = selinux_open_context_file(opt.selinux); +		if (sehnd == NULL) +			goto out; +	} + +	if (read_fstree(&sqfs.fs, &opt, sqfs.xwr, sehnd)) { +		if (sehnd != NULL) +			selinux_close_context_file(sehnd); +		goto out; +	} + +	if (sehnd != NULL) { +		selinux_close_context_file(sehnd); +		sehnd = NULL; +	} + +	if (fstree_post_process(&sqfs.fs)) +		goto out; + +	if (pack_files(sqfs.data, &sqfs.fs, &opt)) +		goto out; + +	if (sqfs_writer_finish(&sqfs, &opt.cfg)) +		goto out; + +	status = EXIT_SUCCESS; +out: +	sqfs_writer_cleanup(&sqfs, status); +	return status; +} diff --git a/bin/gensquashfs/mkfs.h b/bin/gensquashfs/mkfs.h new file mode 100644 index 0000000..1b767aa --- /dev/null +++ b/bin/gensquashfs/mkfs.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * mkfs.h + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#ifndef MKFS_H +#define MKFS_H + +#include "config.h" + +#include "common.h" +#include "fstree.h" + +#ifdef HAVE_SYS_XATTR_H +#include <sys/xattr.h> + +#if defined(__APPLE__) && defined(__MACH__) +#define llistxattr(path, list, size) \ +	listxattr(path, list, size, XATTR_NOFOLLOW) + +#define lgetxattr(path, name, value, size) \ +	getxattr(path, name, value, size, 0, XATTR_NOFOLLOW) +#endif +#endif + +#ifdef WITH_SELINUX +#include <selinux/selinux.h> +#include <selinux/label.h> +#endif + +#include <getopt.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <dirent.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> + +typedef struct { +	sqfs_writer_cfg_t cfg; +	unsigned int dirscan_flags; +	const char *infile; +	const char *packdir; +	const char *selinux; +	bool no_tail_packing; +} options_t; + +enum { +	DIR_SCAN_KEEP_TIME = 0x01, + +	DIR_SCAN_ONE_FILESYSTEM = 0x02, + +	DIR_SCAN_READ_XATTR = 0x04, +}; + +void process_command_line(options_t *opt, int argc, char **argv); + +int fstree_from_dir(fstree_t *fs, const char *path, void *selinux_handle, +		    sqfs_xattr_writer_t *xwr, unsigned int flags); + + +void *selinux_open_context_file(const char *filename); + +int selinux_relable_node(void *sehnd, sqfs_xattr_writer_t *xwr, +			 tree_node_t *node, const char *path); + +void selinux_close_context_file(void *sehnd); + +#endif /* MKFS_H */ diff --git a/bin/gensquashfs/options.c b/bin/gensquashfs/options.c new file mode 100644 index 0000000..2369787 --- /dev/null +++ b/bin/gensquashfs/options.c @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * options.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "mkfs.h" + +static struct option long_opts[] = { +	{ "compressor", required_argument, NULL, 'c' }, +	{ "block-size", required_argument, NULL, 'b' }, +	{ "dev-block-size", required_argument, NULL, 'B' }, +	{ "defaults", required_argument, NULL, 'd' }, +	{ "comp-extra", required_argument, NULL, 'X' }, +	{ "pack-file", required_argument, NULL, 'F' }, +	{ "pack-dir", required_argument, NULL, 'D' }, +	{ "num-jobs", required_argument, NULL, 'j' }, +	{ "queue-backlog", required_argument, NULL, 'Q' }, +	{ "keep-time", no_argument, NULL, 'k' }, +#ifdef HAVE_SYS_XATTR_H +	{ "keep-xattr", no_argument, NULL, 'x' }, +#endif +	{ "one-file-system", no_argument, NULL, 'o' }, +	{ "exportable", no_argument, NULL, 'e' }, +	{ "no-tail-packing", no_argument, NULL, 'T' }, +	{ "force", no_argument, NULL, 'f' }, +	{ "quiet", no_argument, NULL, 'q' }, +#ifdef WITH_SELINUX +	{ "selinux", required_argument, NULL, 's' }, +#endif +	{ "version", no_argument, NULL, 'V' }, +	{ "help", no_argument, NULL, 'h' }, +	{ NULL, 0, NULL, 0 }, +}; + +static const char *short_opts = "F:D:X:c:b:B:d:j:Q:kxoefqThV" +#ifdef WITH_SELINUX +"s:" +#endif +#ifdef HAVE_SYS_XATTR_H +"x" +#endif +; + +static const char *help_string = +"Usage: gensquashfs [OPTIONS...] <squashfs-file>\n" +"\n" +"Possible options:\n" +"\n" +"  --pack-file, -F <file>      Use a `gen_init_cpio` style description file.\n" +"                              The file format is specified below.\n" +"                              If --pack-dir is used, input file paths are\n" +"                              relative to the pack directory, otherwise\n" +"                              they are relative to the directory the pack\n" +"                              file is in.\n" +"  --pack-dir, -D <directory>  If --pack-file is used, this is the root path\n" +"                              relative to which to read files. If no pack\n" +"                              file is specified, pack the contents of the\n" +"                              given directory into a SquashFS image. The\n" +"                              directory becomes the root of the file\n" +"                              system.\n" +"\n" +"  --compressor, -c <name>     Select the compressor to use.\n" +"                              A list of available compressors is below.\n" +"  --comp-extra, -X <options>  A comma separated list of extra options for\n" +"                              the selected compressor. Specify 'help' to\n" +"                              get a list of available options.\n" +"  --num-jobs, -j <count>      Number of compressor jobs to create.\n" +"  --queue-backlog, -Q <count> Maximum number of data blocks in the thread\n" +"                              worker queue before the packer starts waiting\n" +"                              for the block processors to catch up.\n" +"                              Defaults to 10 times the number of jobs.\n" +"  --block-size, -b <size>     Block size to use for Squashfs image.\n" +"                              Defaults to %u.\n" +"  --dev-block-size, -B <size> Device block size to padd the image to.\n" +"                              Defaults to %u.\n" +"  --defaults, -d <options>    A comma separated list of default values for\n" +"                              implicitly created directories.\n" +"\n" +"                              Possible options:\n" +"                                 uid=<value>    0 if not set.\n" +"                                 gid=<value>    0 if not set.\n" +"                                 mode=<value>   0755 if not set.\n" +"                                 mtime=<value>  0 if not set.\n" +"\n" +#ifdef WITH_SELINUX +"  --selinux, -s <file>        Specify an SELinux label file to get context\n" +"                              attributes from.\n" +#endif +"  --keep-time, -k             When using --pack-dir only, use the timestamps\n" +"                              from the input files instead of setting\n" +"                              defaults on all input paths.\n" +"  --keep-xattr, -x            When using --pack-dir only, read and pack the\n" +"                              extended attributes from the input files.\n" +"  --one-file-system, -o       When using --pack-dir only, stay in local file\n" +"                              system and do not cross mount points.\n" +"  --exportable, -e            Generate an export table for NFS support.\n" +"  --no-tail-packing, -T       Do not perform tail end packing on files that\n" +"                              are larger than block size.\n" +"  --force, -f                 Overwrite the output file if it exists.\n" +"  --quiet, -q                 Do not print out progress reports.\n" +"  --help, -h                  Print help text and exit.\n" +"  --version, -V               Print version information and exit.\n" +"\n"; + +const char *help_details = +"When using the pack file option, the given file is expected to contain\n" +"newline separated entries that describe the files to be included in the\n" +"SquashFS image. The following entry types can be specified:\n" +"\n" +"# a comment\n" +"file <path> <mode> <uid> <gid> [<location>]\n" +"dir <path> <mode> <uid> <gid>\n" +"nod <path> <mode> <uid> <gid> <dev_type> <maj> <min>\n" +"slink <path> <mode> <uid> <gid> <target>\n" +"link <path> <dummy> <dummy> <dummy> <target>\n" +"pipe <path> <mode> <uid> <gid>\n" +"sock <path> <mode> <uid> <gid>\n" +"\n" +"<path>       Absolute path of the entry in the image. Can be put in quotes\n" +"             if some components contain spaces.\n" +"<location>   If given, location of the input file. Either absolute or relative\n" +"             to the description file. If omitted, the image path is used,\n" +"             relative to the description file.\n" +"<target>     Symlink or hardlink target.\n" +"<mode>       Mode/permissions of the entry.\n" +"<uid>        Numeric user id.\n" +"<gid>        Numeric group id.\n" +"<dev_type>   Device type (b=block, c=character).\n" +"<maj>        Major number of a device special file.\n" +"<min>        Minor number of a device special file.\n" +"\n" +"Example:\n" +"    # A simple squashfs image\n" +"    dir /dev 0755 0 0\n" +"    nod /dev/console 0600 0 0 c 5 1\n" +"    dir /root 0700 0 0\n" +"    dir /sbin 0755 0 0\n" +"    \n" +"    # Add a file. Input is relative to listing or pack dir.\n" +"    file /sbin/init 0755 0 0 ../init/sbin/init\n" +"    \n" +"    # Read bin/bash, relative to listing or pack dir.\n" +"    # Implicitly create /bin.\n" +"    file /bin/bash 0755 0 0\n" +"    \n" +"    # file name with a space in it.\n" +"    file \"/opt/my app/\\\"special\\\"/data\" 0600 0 0\n" +"\n\n"; + +void process_command_line(options_t *opt, int argc, char **argv) +{ +	bool have_compressor; +	int i, ret; + +	memset(opt, 0, sizeof(*opt)); +	sqfs_writer_cfg_init(&opt->cfg); + +	for (;;) { +		i = getopt_long(argc, argv, short_opts, long_opts, NULL); +		if (i == -1) +			break; + +		switch (i) { +		case 'T': +			opt->no_tail_packing = true; +			break; +		case 'c': +			have_compressor = true; +			ret = sqfs_compressor_id_from_name(optarg); + +			if (ret < 0) { +				have_compressor = false; +#ifdef WITH_LZO +				if (opt->cfg.comp_id == SQFS_COMP_LZO) +					have_compressor = true; +#endif +			} + +			if (!have_compressor) { +				fprintf(stderr, "Unsupported compressor '%s'\n", +					optarg); +				exit(EXIT_FAILURE); +			} + +			opt->cfg.comp_id = ret; +			break; +		case 'b': +			if (parse_size("Block size", &opt->cfg.block_size, +				       optarg, 0)) { +				exit(EXIT_FAILURE); +			} +			break; +		case 'j': +			opt->cfg.num_jobs = strtol(optarg, NULL, 0); +			break; +		case 'Q': +			opt->cfg.max_backlog = strtol(optarg, NULL, 0); +			break; +		case 'B': +			if (parse_size("Device block size", +				       &opt->cfg.devblksize, optarg, 0)) { +				exit(EXIT_FAILURE); +			} +			if (opt->cfg.devblksize < 1024) { +				fputs("Device block size must be at " +				      "least 1024\n", stderr); +				exit(EXIT_FAILURE); +			} +			break; +		case 'd': +			opt->cfg.fs_defaults = optarg; +			break; +		case 'k': +			opt->dirscan_flags |= DIR_SCAN_KEEP_TIME; +			break; +#ifdef HAVE_SYS_XATTR_H +		case 'x': +			opt->dirscan_flags |= DIR_SCAN_READ_XATTR; +			break; +#endif +		case 'o': +			opt->dirscan_flags |= DIR_SCAN_ONE_FILESYSTEM; +			break; +		case 'e': +			opt->cfg.exportable = true; +			break; +		case 'f': +			opt->cfg.outmode |= SQFS_FILE_OPEN_OVERWRITE; +			break; +		case 'q': +			opt->cfg.quiet = true; +			break; +		case 'X': +			opt->cfg.comp_extra = optarg; +			break; +		case 'F': +			opt->infile = optarg; +			break; +		case 'D': +			opt->packdir = optarg; +			break; +#ifdef WITH_SELINUX +		case 's': +			opt->selinux = optarg; +			break; +#endif +		case 'h': +			printf(help_string, +			       SQFS_DEFAULT_BLOCK_SIZE, SQFS_DEVBLK_SIZE); +			fputs(help_details, stdout); +			compressor_print_available(); +			exit(EXIT_SUCCESS); +		case 'V': +			print_version("gensquashfs"); +			exit(EXIT_SUCCESS); +		default: +			goto fail_arg; +		} +	} + +	if (opt->cfg.num_jobs < 1) +		opt->cfg.num_jobs = 1; + +	if (opt->cfg.max_backlog < 1) +		opt->cfg.max_backlog = 10 * opt->cfg.num_jobs; + +	if (opt->cfg.comp_extra != NULL && +	    strcmp(opt->cfg.comp_extra, "help") == 0) { +		compressor_print_help(opt->cfg.comp_id); +		exit(EXIT_SUCCESS); +	} + +	if (opt->infile == NULL && opt->packdir == NULL) { +		fputs("No input file or directory specified.\n", stderr); +		goto fail_arg; +	} + +	if (optind >= argc) { +		fputs("No output file specified.\n", stderr); +		goto fail_arg; +	} + +	opt->cfg.filename = argv[optind++]; +	return; +fail_arg: +	fputs("Try `gensquashfs --help' for more information.\n", stderr); +	exit(EXIT_FAILURE); +} diff --git a/bin/gensquashfs/selinux.c b/bin/gensquashfs/selinux.c new file mode 100644 index 0000000..678723b --- /dev/null +++ b/bin/gensquashfs/selinux.c @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * selinux.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "mkfs.h" + +#define XATTR_NAME_SELINUX "security.selinux" +#define XATTR_VALUE_SELINUX "system_u:object_r:unlabeled_t:s0" + +#ifdef WITH_SELINUX +int selinux_relable_node(void *sehnd, sqfs_xattr_writer_t *xwr, +			 tree_node_t *node, const char *path) +{ +	char *context = NULL; +	int ret; + +	if (selabel_lookup(sehnd, &context, path, node->mode) < 0) { +		context = strdup(XATTR_VALUE_SELINUX); +		if (context == NULL) +			goto fail; +	} + +	ret = sqfs_xattr_writer_add(xwr, XATTR_NAME_SELINUX, +				    context, strlen(context)); +	free(context); + +	if (ret) +		sqfs_perror(node->name, "storing SELinux xattr", ret); + +	return ret; +fail: +	perror("relabeling files"); +	return -1; +} + +void *selinux_open_context_file(const char *filename) +{ +	struct selabel_handle *sehnd; +	struct selinux_opt seopts[] = { +		{ SELABEL_OPT_PATH, filename }, +	}; + +	sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1); +	if (sehnd == NULL) +		perror(filename); + +	return sehnd; +} + +void selinux_close_context_file(void *sehnd) +{ +	selabel_close(sehnd); +} +#else +int selinux_relable_node(void *sehnd, sqfs_xattr_writer_t *xwr, +			 tree_node_t *node, const char *path) +{ +	(void)sehnd; (void)xwr; (void)node; (void)path; +	fputs("Built without SELinux support, cannot add SELinux labels\n", +	      stderr); +	return -1; +} + +void *selinux_open_context_file(const char *filename) +{ +	(void)filename; +	fputs("Built without SELinux support, cannot open contexts file\n", +	      stderr); +	return NULL; +} + +void selinux_close_context_file(void *sehnd) +{ +	(void)sehnd; +} +#endif | 
