All of lore.kernel.org
 help / color / mirror / Atom feed
From: Octavian Purdila <octavian.purdila@intel.com>
To: linux-arch@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, thehajime@gmail.com,
	Octavian Purdila <octavian.purdila@intel.com>
Subject: [RFC PATCH 23/28] lkl tools: tool that converts a filesystem image to tar
Date: Tue,  3 Nov 2015 22:20:54 +0200	[thread overview]
Message-ID: <1446582059-17355-24-git-send-email-octavian.purdila@intel.com> (raw)
In-Reply-To: <1446582059-17355-1-git-send-email-octavian.purdila@intel.com>

Simple utility that converts a filesystem image to a tar file,
preserving file rights and extended attributes.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 tools/lkl/.gitignore |   1 +
 tools/lkl/Makefile   |   3 +
 tools/lkl/fs2tar.c   | 397 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 401 insertions(+)
 create mode 100644 tools/lkl/fs2tar.c

diff --git a/tools/lkl/.gitignore b/tools/lkl/.gitignore
index 7c456f2..a345a79 100644
--- a/tools/lkl/.gitignore
+++ b/tools/lkl/.gitignore
@@ -1 +1,2 @@
 test/boot
+fs2tar
diff --git a/tools/lkl/Makefile b/tools/lkl/Makefile
index 1ae4481..9aeab49 100644
--- a/tools/lkl/Makefile
+++ b/tools/lkl/Makefile
@@ -9,6 +9,7 @@ endif
 lib_source = $(filter-out %-host.c,$(wildcard lib/*.c))
 source = $(wildcard tests/*.c)
 ifneq (,$(filter $(shell $(LD) -r -print-output-format),elf64-x86-64 elf32-i386))
+source += $(wildcard *.c)
 lib_source += lib/posix-host.c
 LDFLAGS += -lpthread -lrt
 endif
@@ -35,3 +36,5 @@ $(execs): lib/liblkl.a
 
 clean:
 	-rm -rf include/lkl/ lib/liblkl.a $(lib_objs) $(objs) $(execs)
+
+fs2tar: LDFLAGS += -larchive
diff --git a/tools/lkl/fs2tar.c b/tools/lkl/fs2tar.c
new file mode 100644
index 0000000..b74da66
--- /dev/null
+++ b/tools/lkl/fs2tar.c
@@ -0,0 +1,397 @@
+#include <stdio.h>
+#include <time.h>
+#include <argp.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <archive.h>
+#include <archive_entry.h>
+#undef st_atime
+#undef st_mtime
+#undef st_ctime
+#include <lkl.h>
+#include <lkl_host.h>
+
+char doc[] = "";
+char args_doc[] = "-t fstype fsimage_path tar_path";
+static struct argp_option options[] = {
+	{"enable-printk", 'p', 0, 0, "show Linux printks"},
+	{"filesystem-type", 't', "string", 0,
+	 "select filesystem type - mandatory"},
+	{"selinux-contexts", 's', "file", 0,
+	 "export sexlinux contexts to file"},
+	{0},
+};
+
+static struct cl_args {
+	int printk;
+	const char *fsimg_type;
+	const char *fsimg_path;
+	const char *tar_path;
+	FILE *selinux;
+} cla;
+
+static error_t parse_opt(int key, char *arg, struct argp_state *state)
+{
+	struct cl_args *cla = state->input;
+
+	switch (key) {
+	case 'p':
+		cla->printk = 1;
+		break;
+	case 't':
+		cla->fsimg_type = arg;
+		break;
+	case 's':
+		cla->selinux = fopen(arg, "w");
+		if (!cla->selinux) {
+			fprintf(stderr, "failed to open selinux contexts file: %s\n",
+				strerror(errno));
+			return -1;
+		}
+		break;
+	case ARGP_KEY_ARG:
+		if (!cla->fsimg_path)
+			cla->fsimg_path = arg;
+		else if (!cla->tar_path)
+			cla->tar_path = arg;
+		else
+			return -1;
+		break;
+	case ARGP_KEY_END:
+		if (state->arg_num < 2 || !cla->fsimg_type)
+			argp_usage(state);
+	default:
+		return ARGP_ERR_UNKNOWN;
+	}
+
+	return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+
+static struct archive *tar;
+
+static int searchdir(const char *fsimg_path, const char *path);
+
+static int copy_file(const char *fsimg_path, const char *path)
+{
+	long fsimg_fd;
+	char buff[4096];
+	long len, wrote;
+	int ret = 0;
+
+	fsimg_fd = lkl_sys_open(fsimg_path, LKL_O_RDONLY, 0);
+	if (fsimg_fd < 0) {
+		fprintf(stderr, "fsimg error opening %s: %s\n", fsimg_path,
+			lkl_strerror(fsimg_fd));
+		return fsimg_fd;
+	}
+
+	do {
+		len = lkl_sys_read(fsimg_fd, buff, sizeof(buff));
+		if (len > 0) {
+			wrote = archive_write_data(tar, buff, len);
+			if (wrote != len) {
+				fprintf(stderr, "error writing file %s to archive: %s [%d %ld]\n",
+					path, archive_error_string(tar), ret,
+					len);
+				ret = -archive_errno(tar);
+				break;
+			}
+		}
+
+		if (len < 0) {
+			fprintf(stderr, "error reading fsimg file %s: %s\n",
+				fsimg_path, lkl_strerror(len));
+			ret = len;
+		}
+
+	} while (len > 0);
+
+	lkl_sys_close(fsimg_fd);
+
+	return ret;
+}
+
+static int add_link(const char *fsimg_path, const char *path,
+		    struct archive_entry *entry)
+{
+	char buf[4096] = { 0, };
+	long len;
+
+	len = lkl_sys_readlink(fsimg_path, buf, sizeof(buf));
+	if (len < 0) {
+		fprintf(stderr, "fsimg readlink error %s: %s\n",
+			fsimg_path, lkl_strerror(len));
+		return len;
+	}
+
+	archive_entry_set_symlink(entry, buf);
+
+	return 0;
+}
+
+static inline void fsimg_copy_stat(struct stat *st, struct lkl_stat64 *fst)
+{
+	st->st_dev = fst->st_dev;
+	st->st_ino = fst->st_ino;
+	st->st_mode = fst->st_mode;
+	st->st_nlink = fst->st_nlink;
+	st->st_uid = fst->st_uid;
+	st->st_gid = fst->st_gid;
+	st->st_rdev = fst->st_rdev;
+	st->st_size = fst->st_size;
+	st->st_blksize = fst->st_blksize;
+	st->st_blocks = fst->st_blocks;
+	st->st_atim.tv_sec = fst->st_atime;
+	st->st_atim.tv_nsec = fst->st_atime_nsec;
+	st->st_mtim.tv_sec = fst->st_mtime;
+	st->st_mtim.tv_nsec = fst->st_mtime_nsec;
+	st->st_ctim.tv_sec = fst->st_ctime;
+	st->st_ctim.tv_nsec = fst->st_ctime_nsec;
+}
+
+static int copy_xattr(const char *fsimg_path, const char *path,
+		      struct archive_entry *entry)
+{
+	long ret;
+	char *xattr_list, *i;
+	long xattr_list_size;
+
+	ret = lkl_sys_llistxattr(fsimg_path, NULL, 0);
+	if (ret < 0) {
+		fprintf(stderr, "fsimg llistxattr(%s) error: %s\n",
+			path, lkl_strerror(ret));
+		return ret;
+	}
+
+	if (!ret)
+		return 0;
+
+	xattr_list = malloc(ret);
+
+	ret = lkl_sys_llistxattr(fsimg_path, xattr_list, ret);
+	if (ret < 0) {
+		fprintf(stderr, "fsimg llistxattr(%s) error: %s\n", path,
+			lkl_strerror(ret));
+		free(xattr_list);
+		return ret;
+	}
+
+	xattr_list_size = ret;
+
+	for (i = xattr_list; i - xattr_list < xattr_list_size;
+	     i += strlen(i) + 1) {
+		void *xattr_buf;
+
+		ret = lkl_sys_lgetxattr(fsimg_path, i, NULL, 0);
+		if (ret < 0) {
+			fprintf(stderr, "fsimg lgetxattr(%s) error: %s\n", path,
+				lkl_strerror(ret));
+			free(xattr_list);
+			return ret;
+		}
+
+		xattr_buf = malloc(ret);
+
+		ret = lkl_sys_lgetxattr(fsimg_path, i, xattr_buf, ret);
+		if (ret < 0) {
+			fprintf(stderr, "fsimg lgetxattr2(%s) error: %s\n",
+				path, lkl_strerror(ret));
+			free(xattr_list);
+			free(xattr_buf);
+			return ret;
+		}
+
+		if (cla.selinux && strcmp(i, "security.selinux") == 0)
+			fprintf(cla.selinux, "%s %s\n", path,
+				(char *)xattr_buf);
+
+		archive_entry_xattr_clear(entry);
+		archive_entry_xattr_add_entry(entry, i, xattr_buf, ret);
+
+		free(xattr_buf);
+	}
+
+	free(xattr_list);
+
+	return 0;
+}
+
+static int do_entry(const char *fsimg_path, const char *path,
+		    const struct lkl_dirent64 *de)
+{
+	char fsimg_new_path[PATH_MAX], new_path[PATH_MAX];
+	struct lkl_stat64 fsimg_stat;
+	struct stat stat;
+	struct archive_entry *entry;
+	int ftype;
+	long ret;
+
+	snprintf(new_path, sizeof(new_path), "%s/%s", path, de->d_name);
+	snprintf(fsimg_new_path, sizeof(fsimg_new_path), "%s/%s", fsimg_path,
+		 de->d_name);
+
+	ret = lkl_sys_lstat64(fsimg_new_path, &fsimg_stat);
+	if (ret) {
+		fprintf(stderr, "fsimg fstat64(%s) error: %s\n",
+			path, lkl_strerror(ret));
+		return ret;
+	}
+
+	entry = archive_entry_new();
+
+	archive_entry_set_pathname(entry, new_path);
+	fsimg_copy_stat(&stat, &fsimg_stat);
+	archive_entry_copy_stat(entry, &stat);
+	ret = copy_xattr(fsimg_new_path, new_path, entry);
+	if (ret)
+		return ret;
+	/* TODO: ACLs */
+
+	ftype = stat.st_mode & S_IFMT;
+
+	switch (ftype) {
+	case S_IFREG:
+		archive_write_header(tar, entry);
+		ret = copy_file(fsimg_new_path, new_path);
+		break;
+	case S_IFDIR:
+		archive_write_header(tar, entry);
+		ret = searchdir(fsimg_new_path, new_path);
+		break;
+	case S_IFLNK:
+		ret = add_link(fsimg_new_path, new_path, entry);
+		/* fall through */
+	case S_IFSOCK:
+	case S_IFBLK:
+	case S_IFCHR:
+	case S_IFIFO:
+		if (ret)
+			break;
+		archive_write_header(tar, entry);
+		break;
+	default:
+		printf("skipping %s: unsupported entry type %d\n", new_path,
+		       ftype);
+	}
+
+	archive_entry_free(entry);
+
+	if (ret)
+		printf("error processing entry %s, aborting\n", new_path);
+
+	return ret;
+}
+
+static int searchdir(const char *fsimg_path, const char *path)
+{
+	long ret, fd;
+	char buf[1024], *pos;
+	long buf_len;
+
+	fd = lkl_sys_open(fsimg_path, LKL_O_RDONLY | LKL_O_DIRECTORY, 0);
+	if (fd < 0) {
+		fprintf(stderr, "failed to open dir %s: %s", fsimg_path,
+			lkl_strerror(fd));
+		return fd;
+	}
+
+	do {
+		struct lkl_dirent64 *de;
+
+		buf_len = lkl_sys_getdents64(fd, buf, sizeof(buf));
+		if (buf_len < 0) {
+			fprintf(stderr, "gentdents64 error: %s\n",
+				lkl_strerror(buf_len));
+			break;
+		}
+
+		for (pos = buf; pos - buf < buf_len; pos += de->d_reclen) {
+			de = (struct lkl_dirent64 *)pos;
+
+			if (!strcmp(de->d_name, ".") ||
+			    !strcmp(de->d_name, ".."))
+				continue;
+
+			ret = do_entry(fsimg_path, path, de);
+			if (ret)
+				goto out;
+		}
+
+	} while (buf_len > 0);
+
+out:
+	lkl_sys_close(fd);
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	union lkl_disk_backstore bs;
+	long ret;
+	char mpoint[32];
+	unsigned int disk_id;
+
+	if (argp_parse(&argp, argc, argv, 0, 0, &cla) < 0)
+		return -1;
+
+	if (!cla.printk)
+		lkl_host_ops.print = NULL;
+
+	bs.fd = open(cla.fsimg_path, O_RDONLY);
+	if (bs.fd < 0) {
+		fprintf(stderr, "can't open fsimg %s: %s\n", cla.fsimg_path,
+			strerror(errno));
+		ret = 1;
+		goto out;
+	}
+
+	disk_id = lkl_disk_add(bs);
+	if (disk_id < 0) {
+		fprintf(stderr, "can't add disk: %s\n", lkl_strerror(ret));
+		goto out_close;
+	}
+
+	lkl_start_kernel(&lkl_host_ops, 10 * 1024 * 1024, "");
+
+	ret = lkl_mount_dev(disk_id, cla.fsimg_type, LKL_MS_RDONLY, NULL,
+			    mpoint, sizeof(mpoint));
+	if (ret) {
+		fprintf(stderr, "can't mount disk: %s\n", lkl_strerror(ret));
+		goto out_close;
+	}
+
+	ret = lkl_sys_chdir(mpoint);
+	if (ret) {
+		fprintf(stderr, "can't chdir to %s: %s\n", mpoint,
+			lkl_strerror(ret));
+		goto out_umount;
+	}
+
+	tar = archive_write_new();
+	archive_write_set_format_pax_restricted(tar);
+	archive_write_open_filename(tar, cla.tar_path);
+
+	ret = searchdir(mpoint, "");
+
+	archive_write_free(tar);
+
+	if (cla.selinux)
+		fclose(cla.selinux);
+
+out_umount:
+	lkl_umount_dev(disk_id, 0, 1000);
+
+out_close:
+	close(bs.fd);
+
+out:
+	lkl_sys_halt();
+
+	return ret;
+}
-- 
2.1.0


  parent reply	other threads:[~2015-11-03 20:25 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-03 20:20 [RFC PATCH 00/28] Linux Kernel Library Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 01/28] asm-generic: atomic64: allow using generic atomic64 on 64bit platforms Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 02/28] kbuild: allow architectures to automatically define kconfig symbols Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 03/28] lkl: architecture skeleton for Linux kernel library Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 04/28] lkl: host interface Octavian Purdila
2015-11-03 23:30   ` Hajime Tazaki
2015-11-03 20:20 ` [RFC PATCH 05/28] lkl: memory handling Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 06/28] lkl: kernel threads support Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 07/28] lkl: interrupt support Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 08/28] lkl: system call interface and application API Octavian Purdila
2015-11-07 23:24   ` Arnd Bergmann
2015-11-08  3:49     ` Octavian Purdila
2015-11-08 10:26       ` Arnd Bergmann
2015-11-03 20:20 ` [RFC PATCH 09/28] lkl: timers, time and delay support Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 10/28] lkl: memory mapped I/O support Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 11/28] lkl: basic kernel console support Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 12/28] init: allow architecture code to overide run_init_process Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 13/28] lkl: initialization and cleanup Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 14/28] lkl: plug in the build system Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 15/28] lkl tools: skeleton for host side library, tests and tools Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 16/28] lkl tools: host lib: add lkl_strerror and lkl_printf Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 17/28] lkl tools: host lib: memory mapped I/O helpers Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 18/28] lkl tools: host lib: virtio devices Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 19/28] lkl tools: host lib: virtio block device Octavian Purdila
2015-11-07 12:24   ` Richard Weinberger
2015-11-08  4:15     ` Octavian Purdila
2015-11-08 13:30       ` Richard Weinberger
2015-11-03 20:20 ` [RFC PATCH 20/28] lkl tools: host lib: filesystem helpers Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 21/28] lkl tools: host lib: posix host operations Octavian Purdila
2015-11-07 23:16   ` Arnd Bergmann
2015-11-08  4:01     ` Octavian Purdila
2015-11-08 10:35       ` Arnd Bergmann
2015-11-03 20:20 ` [RFC PATCH 22/28] lkl tools: "boot" test Octavian Purdila
2015-11-03 20:20 ` Octavian Purdila [this message]
2015-11-03 20:20 ` [RFC PATCH 24/28] lkl tools: tool that reads/writes to/from a filesystem image Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 25/28] signal: use CONFIG_X86_32 instead of __i386__ Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 26/28] asm-generic: vmlinux.lds.h: allow customized rodata section name Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 27/28] lkl: add support for Windows hosts Octavian Purdila
2015-11-03 20:20 ` [RFC PATCH 28/28] lkl tools: add support for Windows host Octavian Purdila
2015-11-03 21:40 ` [RFC PATCH 00/28] Linux Kernel Library Richard Weinberger
2015-11-03 22:45   ` Richard W.M. Jones
2015-11-03 23:23     ` Hajime Tazaki
2015-11-03 23:24     ` Octavian Purdila
2015-11-04 13:22       ` Austin S Hemmelgarn
2015-11-04 13:50       ` Richard W.M. Jones
2015-11-04 14:15         ` Octavian Purdila
2015-11-07  0:35           ` Richard Weinberger
2015-11-07  7:19             ` Richard W.M. Jones
2015-11-07 10:48             ` Richard W.M. Jones
2015-11-09 16:35               ` Octavian Purdila
2015-11-08  4:16             ` Octavian Purdila
2015-11-08  4:36             ` Octavian Purdila
2015-11-03 23:06   ` Octavian Purdila
     [not found]     ` <1670BE0E-C0E0-4D45-BF16-1FF60C298149@gmail.com>
2015-11-09 15:11       ` Octavian Purdila
2015-11-08 13:45 ` Hajime Tazaki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1446582059-17355-24-git-send-email-octavian.purdila@intel.com \
    --to=octavian.purdila@intel.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=thehajime@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.