Skip to content

Commit

Permalink
Add a notification mechanism for signaling when the mountpoint is ready
Browse files Browse the repository at this point in the history
Add the notify_pipe option which allows the user to specify the path to
a named pipe. When the mountpoint is ready, a message will be written to
this pipe: 's' for success and 'f' for failure. To avoid blocking the
fuse process until the pipe is read, a new process is spawned which
performs a blocking operation on the pipe. In case of mount failure, no
additional process is created and the main process blocks until the pipe
is read.

An example of operation is provided below:
```
set -x
FIFO=$(mktemp -u)
mkfifo "$FIFO"
./squashfuse_ll -o notify_pipe="$FIFO" -f /path/to/squashfs/archive /tmp/squash&
STATUS=$(head -c1 "$FIFO")
if [ "$STATUS" = "s" ]; then
	echo "Mountpoint contains:"
	ls /tmp/squash
else
	echo "Mounting squashfuse on /tmp/squash failed"
fi
```

Fixes vasi#49
  • Loading branch information
ariel-miculas committed Aug 30, 2023
1 parent 21ab372 commit 4ee02c9
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 1 deletion.
1 change: 1 addition & 0 deletions fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 33 additions & 0 deletions fuseprivate.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "nonstd.h"

Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions fuseprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
30 changes: 29 additions & 1 deletion hl.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


typedef struct sqfs_hl sqfs_hl;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
};

Expand Down Expand Up @@ -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)
Expand All @@ -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;
}
19 changes: 19 additions & 0 deletions ll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);


Expand Down
9 changes: 9 additions & 0 deletions ll_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand All @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 4ee02c9

Please sign in to comment.