diff --git a/fs.h b/fs.h index 957282d..ae07f4b 100644 --- a/fs.h +++ b/fs.h @@ -39,6 +39,7 @@ struct sqfs { int uid; int gid; struct squashfs_super_block sb; + const char *notify_pipe; sqfs_table id_table; sqfs_table frag_table; sqfs_table export_table; diff --git a/fuseprivate.c b/fuseprivate.c index 00a6ce6..9bdf5ec 100644 --- a/fuseprivate.c +++ b/fuseprivate.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "nonstd.h" @@ -78,6 +79,7 @@ void sqfs_usage(char *progname, bool fuse_usage, bool ll_usage) { fprintf(stderr, "\n%s options:\n", progname); fprintf(stderr, " -o offset=N offset N bytes into ARCHIVE to mount\n"); fprintf(stderr, " -o subdir=PATH mount subdirectory PATH of ARCHIVE\n"); + fprintf(stderr, " -o notify_pipe=PATH named pipe that will receive 's' or 'f' when the mount is ready\n"); if (ll_usage) { fprintf(stderr, " -o timeout=N idle N seconds for automatic unmount\n"); fprintf(stderr, " -o uid=N set file owner to uid N\n"); @@ -148,3 +150,34 @@ int sqfs_statfs(sqfs *sq, struct statvfs *st) { return 0; } + +void notify_mount_ready(const char *notify_pipe, int status) { + char message[] = "sf"; + struct stat stat_buf = {}; + + if (stat(notify_pipe, &stat_buf)) { + fprintf(stderr, "Cannot stat file \"%s\" (%d)\n", notify_pipe, errno); + goto err; + } + + if (!(stat_buf.st_mode & S_IFIFO)) { + fprintf(stderr, "\"%s\" is not a pipe\n", notify_pipe); + goto err; + } + + sqfs_fd_t pipe_fd = open(notify_pipe, O_WRONLY); + if(pipe_fd < 0) { + fprintf(stderr, "Open fifo failed \"%s\" (%d)\n", notify_pipe, errno); + goto err; + } + + if (write(pipe_fd, &message[!!status], 1) < 0) { + fprintf(stderr, "Write to fifo failed \"%s\" (%d)\n", notify_pipe, errno); + goto err; + } + + close(pipe_fd); + +err: + return; +} diff --git a/fuseprivate.h b/fuseprivate.h index e6c8fd5..a20f667 100644 --- a/fuseprivate.h +++ b/fuseprivate.h @@ -47,11 +47,13 @@ typedef struct { unsigned int idle_timeout_secs; int uid; int gid; + const char *notify_pipe; } sqfs_opts; int sqfs_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs); /* Get filesystem super block info */ int sqfs_statfs(sqfs *sq, struct statvfs *st); +void notify_mount_ready(const char *notify_pipe, int status); #endif diff --git a/hl.c b/hl.c index 7bce10f..08759fa 100644 --- a/hl.c +++ b/hl.c @@ -33,6 +33,7 @@ #include #include #include +#include typedef struct sqfs_hl sqfs_hl; @@ -72,7 +73,25 @@ static void *sqfs_hl_op_init(struct fuse_conn_info *conn ,struct fuse_config *cfg #endif ) { - return fuse_get_context()->private_data; + sqfs_hl *hl = fuse_get_context()->private_data; + + if (!hl->fs.notify_pipe) { + goto out; + } + + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "Fork Failed"); + } + else if (pid == 0) { /* child process */ + notify_mount_ready(hl->fs.notify_pipe, 0); + exit(0); + } + else { /* parent process */ + } + +out: + return hl; } static int sqfs_hl_op_getattr(const char *path, struct stat *st @@ -297,6 +316,7 @@ int main(int argc, char *argv[]) { struct fuse_opt fuse_opts[] = { {"offset=%zu", offsetof(sqfs_opts, offset), 0}, {"subdir=%s", offsetof(sqfs_opts, subdir), 0}, + {"notify_pipe=%s", offsetof(sqfs_opts, notify_pipe), 0}, FUSE_OPT_END }; @@ -326,6 +346,7 @@ int main(int argc, char *argv[]) { opts.subdir = NULL; opts.mountpoint = 0; opts.offset = 0; + opts.notify_pipe = NULL; if (fuse_opt_parse(&args, &opts, fuse_opts, sqfs_opt_proc) == -1) sqfs_usage(argv[0], true, false); if (!opts.image) @@ -334,9 +355,16 @@ int main(int argc, char *argv[]) { hl = sqfs_hl_open(opts.image, opts.offset, opts.subdir); if (!hl) return -1; + + hl->fs.notify_pipe = opts.notify_pipe; fuse_opt_add_arg(&args, "-s"); /* single threaded */ ret = fuse_main(args.argc, args.argv, &sqfs_hl_ops, hl); + if (ret) { + if (hl->fs.notify_pipe) { + notify_mount_ready(hl->fs.notify_pipe, -1); + } + } fuse_opt_free_args(&args); return ret; } diff --git a/ll.c b/ll.c index c5d040f..a2a5b0b 100644 --- a/ll.c +++ b/ll.c @@ -432,6 +432,25 @@ void stfs_ll_op_statfs(fuse_req_t req, fuse_ino_t ino) { } } +void sqfs_ll_op_init(void *userdata, struct fuse_conn_info *conn) { + sqfs_ll *ll = userdata; + + if (!ll->fs.notify_pipe) { + return; + } + + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "Fork Failed"); + } + else if (pid == 0) { /* child process */ + notify_mount_ready(ll->fs.notify_pipe, 0); + exit(0); + } + else { /* parent process */ + } +} + /* Helpers to abstract out FUSE 2.5 vs 3.0+ differences */ #if FUSE_USE_VERSION >= 30 diff --git a/ll.h b/ll.h index 2e6a6a9..f8721a2 100644 --- a/ll.h +++ b/ll.h @@ -111,6 +111,8 @@ void sqfs_ll_op_getxattr(fuse_req_t req, fuse_ino_t ino, void sqfs_ll_op_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); +void sqfs_ll_op_init(void *userdata, struct fuse_conn_info *conn); + void stfs_ll_op_statfs(fuse_req_t req, fuse_ino_t ino); diff --git a/ll_main.c b/ll_main.c index a9e2e9f..74e3a87 100644 --- a/ll_main.c +++ b/ll_main.c @@ -142,6 +142,7 @@ int main(int argc, char *argv[]) { {"uid=%d", offsetof(sqfs_opts, uid), 0}, {"gid=%d", offsetof(sqfs_opts, gid), 0}, {"subdir=%s", offsetof(sqfs_opts, subdir), 0}, + {"notify_pipe=%s", offsetof(sqfs_opts, notify_pipe), 0}, FUSE_OPT_END }; @@ -161,6 +162,7 @@ int main(int argc, char *argv[]) { sqfs_ll_ops.getxattr = sqfs_ll_op_getxattr; sqfs_ll_ops.forget = sqfs_ll_op_forget; sqfs_ll_ops.statfs = stfs_ll_op_statfs; + sqfs_ll_ops.init = sqfs_ll_op_init; /* PARSE ARGS */ args.argc = argc; @@ -175,6 +177,7 @@ int main(int argc, char *argv[]) { opts.uid = 0; opts.gid = 0; opts.subdir = NULL; + opts.notify_pipe = NULL; if (fuse_opt_parse(&args, &opts, fuse_opts, sqfs_opt_proc) == -1) sqfs_usage(argv[0], true, true); @@ -220,6 +223,8 @@ int main(int argc, char *argv[]) { if (!err) { ll->fs.uid = opts.uid; ll->fs.gid = opts.gid; + ll->fs.notify_pipe = opts.notify_pipe; + sqfs_ll_chan ch; err = -1; if (sqfs_ll_mount( @@ -259,6 +264,10 @@ int main(int argc, char *argv[]) { } sqfs_ll_destroy(ll); sqfs_ll_unmount(&ch, fuse_cmdline_opts.mountpoint); + } else { + if (ll->fs.notify_pipe) { + notify_mount_ready(ll->fs.notify_pipe, -1); + } } } fuse_opt_free_args(&args);