16881f68fSopenharmony_ci/*
26881f68fSopenharmony_ci  FUSE: Filesystem in Userspace
36881f68fSopenharmony_ci  Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
46881f68fSopenharmony_ci
56881f68fSopenharmony_ci  This program can be distributed under the terms of the GNU GPLv2.
66881f68fSopenharmony_ci  See the file COPYING.
76881f68fSopenharmony_ci*/
86881f68fSopenharmony_ci
96881f68fSopenharmony_ci/** @file
106881f68fSopenharmony_ci *
116881f68fSopenharmony_ci *  This example implements a file system with a single file whose
126881f68fSopenharmony_ci *  contents change dynamically: it always contains the current time.
136881f68fSopenharmony_ci *
146881f68fSopenharmony_ci *  While notify_inval_inode.c uses fuse_lowlevel_notify_inval_inode()
156881f68fSopenharmony_ci *  to let the kernel know that it has to invalidate the cache, this
166881f68fSopenharmony_ci *  example actively pushes the updated data into the kernel cache
176881f68fSopenharmony_ci *  using fuse_lowlevel_notify_store().
186881f68fSopenharmony_ci *
196881f68fSopenharmony_ci *  To see the effect, first start the file system with the
206881f68fSopenharmony_ci *  ``--no-notify`` option:
216881f68fSopenharmony_ci *
226881f68fSopenharmony_ci *      $ notify_store_retrieve --update-interval=1 --no-notify mnt/
236881f68fSopenharmony_ci *
246881f68fSopenharmony_ci *  Observe that the output never changes, even though the file system
256881f68fSopenharmony_ci *  updates it once per second. This is because the contents are cached
266881f68fSopenharmony_ci *  in the kernel:
276881f68fSopenharmony_ci *
286881f68fSopenharmony_ci *      $ for i in 1 2 3 4 5; do
296881f68fSopenharmony_ci *      >     cat mnt/current_time
306881f68fSopenharmony_ci *      >     sleep 1
316881f68fSopenharmony_ci *      > done
326881f68fSopenharmony_ci *      The current time is 15:58:18
336881f68fSopenharmony_ci *      The current time is 15:58:18
346881f68fSopenharmony_ci *      The current time is 15:58:18
356881f68fSopenharmony_ci *      The current time is 15:58:18
366881f68fSopenharmony_ci *      The current time is 15:58:18
376881f68fSopenharmony_ci *
386881f68fSopenharmony_ci *  If you instead enable the notification functions, the changes become
396881f68fSopenharmony_ci *  visible:
406881f68fSopenharmony_ci *
416881f68fSopenharmony_ci *      $ notify_store_retrieve --update-interval=1 mnt/
426881f68fSopenharmony_ci *      $ for i in 1 2 3 4 5; do
436881f68fSopenharmony_ci *      >     cat mnt/current_time
446881f68fSopenharmony_ci *      >     sleep 1
456881f68fSopenharmony_ci *      > done
466881f68fSopenharmony_ci *      The current time is 15:58:40
476881f68fSopenharmony_ci *      The current time is 15:58:41
486881f68fSopenharmony_ci *      The current time is 15:58:42
496881f68fSopenharmony_ci *      The current time is 15:58:43
506881f68fSopenharmony_ci *      The current time is 15:58:44
516881f68fSopenharmony_ci *
526881f68fSopenharmony_ci * ## Compilation ##
536881f68fSopenharmony_ci *
546881f68fSopenharmony_ci *     gcc -Wall notify_store_retrieve.c `pkg-config fuse3 --cflags --libs` -o notify_store_retrieve
556881f68fSopenharmony_ci *
566881f68fSopenharmony_ci * ## Source code ##
576881f68fSopenharmony_ci * \include notify_store_retrieve.c
586881f68fSopenharmony_ci */
596881f68fSopenharmony_ci
606881f68fSopenharmony_ci
616881f68fSopenharmony_ci#define FUSE_USE_VERSION 34
626881f68fSopenharmony_ci
636881f68fSopenharmony_ci#include <fuse_lowlevel.h>
646881f68fSopenharmony_ci#include <stdio.h>
656881f68fSopenharmony_ci#include <stdlib.h>
666881f68fSopenharmony_ci#include <string.h>
676881f68fSopenharmony_ci#include <errno.h>
686881f68fSopenharmony_ci#include <fcntl.h>
696881f68fSopenharmony_ci#include <assert.h>
706881f68fSopenharmony_ci#include <stddef.h>
716881f68fSopenharmony_ci#include <unistd.h>
726881f68fSopenharmony_ci#include <pthread.h>
736881f68fSopenharmony_ci
746881f68fSopenharmony_ci/* We can't actually tell the kernel that there is no
756881f68fSopenharmony_ci   timeout, so we just send a big value */
766881f68fSopenharmony_ci#define NO_TIMEOUT 500000
776881f68fSopenharmony_ci
786881f68fSopenharmony_ci#define MAX_STR_LEN 128
796881f68fSopenharmony_ci#define FILE_INO 2
806881f68fSopenharmony_ci#define FILE_NAME "current_time"
816881f68fSopenharmony_cistatic char file_contents[MAX_STR_LEN];
826881f68fSopenharmony_cistatic int lookup_cnt = 0;
836881f68fSopenharmony_cistatic size_t file_size;
846881f68fSopenharmony_ci
856881f68fSopenharmony_ci/* Keep track if we ever stored data (==1), and
866881f68fSopenharmony_ci   received it back correctly (==2) */
876881f68fSopenharmony_cistatic int retrieve_status = 0;
886881f68fSopenharmony_ci
896881f68fSopenharmony_ci/* Command line parsing */
906881f68fSopenharmony_cistruct options {
916881f68fSopenharmony_ci    int no_notify;
926881f68fSopenharmony_ci    int update_interval;
936881f68fSopenharmony_ci};
946881f68fSopenharmony_cistatic struct options options = {
956881f68fSopenharmony_ci    .no_notify = 0,
966881f68fSopenharmony_ci    .update_interval = 1,
976881f68fSopenharmony_ci};
986881f68fSopenharmony_ci
996881f68fSopenharmony_ci#define OPTION(t, p)                           \
1006881f68fSopenharmony_ci    { t, offsetof(struct options, p), 1 }
1016881f68fSopenharmony_cistatic const struct fuse_opt option_spec[] = {
1026881f68fSopenharmony_ci    OPTION("--no-notify", no_notify),
1036881f68fSopenharmony_ci    OPTION("--update-interval=%d", update_interval),
1046881f68fSopenharmony_ci    FUSE_OPT_END
1056881f68fSopenharmony_ci};
1066881f68fSopenharmony_ci
1076881f68fSopenharmony_cistatic int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
1086881f68fSopenharmony_ci    stbuf->st_ino = ino;
1096881f68fSopenharmony_ci    if (ino == FUSE_ROOT_ID) {
1106881f68fSopenharmony_ci        stbuf->st_mode = S_IFDIR | 0755;
1116881f68fSopenharmony_ci        stbuf->st_nlink = 1;
1126881f68fSopenharmony_ci    }
1136881f68fSopenharmony_ci
1146881f68fSopenharmony_ci    else if (ino == FILE_INO) {
1156881f68fSopenharmony_ci        stbuf->st_mode = S_IFREG | 0444;
1166881f68fSopenharmony_ci        stbuf->st_nlink = 1;
1176881f68fSopenharmony_ci        stbuf->st_size = file_size;
1186881f68fSopenharmony_ci    }
1196881f68fSopenharmony_ci
1206881f68fSopenharmony_ci    else
1216881f68fSopenharmony_ci        return -1;
1226881f68fSopenharmony_ci
1236881f68fSopenharmony_ci    return 0;
1246881f68fSopenharmony_ci}
1256881f68fSopenharmony_ci
1266881f68fSopenharmony_cistatic void tfs_lookup(fuse_req_t req, fuse_ino_t parent,
1276881f68fSopenharmony_ci                       const char *name) {
1286881f68fSopenharmony_ci    struct fuse_entry_param e;
1296881f68fSopenharmony_ci    memset(&e, 0, sizeof(e));
1306881f68fSopenharmony_ci
1316881f68fSopenharmony_ci    if (parent != FUSE_ROOT_ID)
1326881f68fSopenharmony_ci        goto err_out;
1336881f68fSopenharmony_ci    else if (strcmp(name, FILE_NAME) == 0) {
1346881f68fSopenharmony_ci        e.ino = FILE_INO;
1356881f68fSopenharmony_ci        lookup_cnt++;
1366881f68fSopenharmony_ci    } else
1376881f68fSopenharmony_ci        goto err_out;
1386881f68fSopenharmony_ci
1396881f68fSopenharmony_ci    e.attr_timeout = NO_TIMEOUT;
1406881f68fSopenharmony_ci    e.entry_timeout = NO_TIMEOUT;
1416881f68fSopenharmony_ci    if (tfs_stat(e.ino, &e.attr) != 0)
1426881f68fSopenharmony_ci        goto err_out;
1436881f68fSopenharmony_ci    fuse_reply_entry(req, &e);
1446881f68fSopenharmony_ci    return;
1456881f68fSopenharmony_ci
1466881f68fSopenharmony_cierr_out:
1476881f68fSopenharmony_ci    fuse_reply_err(req, ENOENT);
1486881f68fSopenharmony_ci}
1496881f68fSopenharmony_ci
1506881f68fSopenharmony_cistatic void tfs_forget (fuse_req_t req, fuse_ino_t ino,
1516881f68fSopenharmony_ci                        uint64_t nlookup) {
1526881f68fSopenharmony_ci    (void) req;
1536881f68fSopenharmony_ci    if(ino == FILE_INO)
1546881f68fSopenharmony_ci        lookup_cnt -= nlookup;
1556881f68fSopenharmony_ci    else
1566881f68fSopenharmony_ci        assert(ino == FUSE_ROOT_ID);
1576881f68fSopenharmony_ci    fuse_reply_none(req);
1586881f68fSopenharmony_ci}
1596881f68fSopenharmony_ci
1606881f68fSopenharmony_cistatic void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
1616881f68fSopenharmony_ci                        struct fuse_file_info *fi) {
1626881f68fSopenharmony_ci    struct stat stbuf;
1636881f68fSopenharmony_ci
1646881f68fSopenharmony_ci    (void) fi;
1656881f68fSopenharmony_ci
1666881f68fSopenharmony_ci    memset(&stbuf, 0, sizeof(stbuf));
1676881f68fSopenharmony_ci    if (tfs_stat(ino, &stbuf) != 0)
1686881f68fSopenharmony_ci        fuse_reply_err(req, ENOENT);
1696881f68fSopenharmony_ci    else
1706881f68fSopenharmony_ci        fuse_reply_attr(req, &stbuf, NO_TIMEOUT);
1716881f68fSopenharmony_ci}
1726881f68fSopenharmony_ci
1736881f68fSopenharmony_cistruct dirbuf {
1746881f68fSopenharmony_ci    char *p;
1756881f68fSopenharmony_ci    size_t size;
1766881f68fSopenharmony_ci};
1776881f68fSopenharmony_ci
1786881f68fSopenharmony_cistatic void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
1796881f68fSopenharmony_ci                       fuse_ino_t ino) {
1806881f68fSopenharmony_ci    struct stat stbuf;
1816881f68fSopenharmony_ci    size_t oldsize = b->size;
1826881f68fSopenharmony_ci    b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
1836881f68fSopenharmony_ci    b->p = (char *) realloc(b->p, b->size);
1846881f68fSopenharmony_ci    memset(&stbuf, 0, sizeof(stbuf));
1856881f68fSopenharmony_ci    stbuf.st_ino = ino;
1866881f68fSopenharmony_ci    fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
1876881f68fSopenharmony_ci                      b->size);
1886881f68fSopenharmony_ci}
1896881f68fSopenharmony_ci
1906881f68fSopenharmony_ci#define min(x, y) ((x) < (y) ? (x) : (y))
1916881f68fSopenharmony_ci
1926881f68fSopenharmony_cistatic int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
1936881f68fSopenharmony_ci                             off_t off, size_t maxsize) {
1946881f68fSopenharmony_ci    if (off < bufsize)
1956881f68fSopenharmony_ci        return fuse_reply_buf(req, buf + off,
1966881f68fSopenharmony_ci                              min(bufsize - off, maxsize));
1976881f68fSopenharmony_ci    else
1986881f68fSopenharmony_ci        return fuse_reply_buf(req, NULL, 0);
1996881f68fSopenharmony_ci}
2006881f68fSopenharmony_ci
2016881f68fSopenharmony_cistatic void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2026881f68fSopenharmony_ci                        off_t off, struct fuse_file_info *fi) {
2036881f68fSopenharmony_ci    (void) fi;
2046881f68fSopenharmony_ci
2056881f68fSopenharmony_ci    if (ino != FUSE_ROOT_ID)
2066881f68fSopenharmony_ci        fuse_reply_err(req, ENOTDIR);
2076881f68fSopenharmony_ci    else {
2086881f68fSopenharmony_ci        struct dirbuf b;
2096881f68fSopenharmony_ci
2106881f68fSopenharmony_ci        memset(&b, 0, sizeof(b));
2116881f68fSopenharmony_ci        dirbuf_add(req, &b, FILE_NAME, FILE_INO);
2126881f68fSopenharmony_ci        reply_buf_limited(req, b.p, b.size, off, size);
2136881f68fSopenharmony_ci        free(b.p);
2146881f68fSopenharmony_ci    }
2156881f68fSopenharmony_ci}
2166881f68fSopenharmony_ci
2176881f68fSopenharmony_cistatic void tfs_open(fuse_req_t req, fuse_ino_t ino,
2186881f68fSopenharmony_ci                     struct fuse_file_info *fi) {
2196881f68fSopenharmony_ci
2206881f68fSopenharmony_ci    /* Make cache persistent even if file is closed,
2216881f68fSopenharmony_ci       this makes it easier to see the effects */
2226881f68fSopenharmony_ci    fi->keep_cache = 1;
2236881f68fSopenharmony_ci
2246881f68fSopenharmony_ci    if (ino == FUSE_ROOT_ID)
2256881f68fSopenharmony_ci        fuse_reply_err(req, EISDIR);
2266881f68fSopenharmony_ci    else if ((fi->flags & O_ACCMODE) != O_RDONLY)
2276881f68fSopenharmony_ci        fuse_reply_err(req, EACCES);
2286881f68fSopenharmony_ci    else if (ino == FILE_INO)
2296881f68fSopenharmony_ci        fuse_reply_open(req, fi);
2306881f68fSopenharmony_ci    else {
2316881f68fSopenharmony_ci        // This should not happen
2326881f68fSopenharmony_ci        fprintf(stderr, "Got open for non-existing inode!\n");
2336881f68fSopenharmony_ci        fuse_reply_err(req, ENOENT);
2346881f68fSopenharmony_ci    }
2356881f68fSopenharmony_ci}
2366881f68fSopenharmony_ci
2376881f68fSopenharmony_cistatic void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size,
2386881f68fSopenharmony_ci                     off_t off, struct fuse_file_info *fi) {
2396881f68fSopenharmony_ci    (void) fi;
2406881f68fSopenharmony_ci
2416881f68fSopenharmony_ci    assert(ino == FILE_INO);
2426881f68fSopenharmony_ci    reply_buf_limited(req, file_contents, file_size, off, size);
2436881f68fSopenharmony_ci}
2446881f68fSopenharmony_ci
2456881f68fSopenharmony_cistatic void tfs_retrieve_reply(fuse_req_t req, void *cookie, fuse_ino_t ino,
2466881f68fSopenharmony_ci                               off_t offset, struct fuse_bufvec *data) {
2476881f68fSopenharmony_ci    struct fuse_bufvec bufv;
2486881f68fSopenharmony_ci    char buf[MAX_STR_LEN];
2496881f68fSopenharmony_ci    char *expected;
2506881f68fSopenharmony_ci    ssize_t ret;
2516881f68fSopenharmony_ci
2526881f68fSopenharmony_ci    assert(ino == FILE_INO);
2536881f68fSopenharmony_ci    assert(offset == 0);
2546881f68fSopenharmony_ci    expected = (char*) cookie;
2556881f68fSopenharmony_ci
2566881f68fSopenharmony_ci    bufv.count = 1;
2576881f68fSopenharmony_ci    bufv.idx = 0;
2586881f68fSopenharmony_ci    bufv.off = 0;
2596881f68fSopenharmony_ci    bufv.buf[0].size = MAX_STR_LEN;
2606881f68fSopenharmony_ci    bufv.buf[0].mem = buf;
2616881f68fSopenharmony_ci    bufv.buf[0].flags = 0;
2626881f68fSopenharmony_ci
2636881f68fSopenharmony_ci    ret = fuse_buf_copy(&bufv, data, 0);
2646881f68fSopenharmony_ci    assert(ret > 0);
2656881f68fSopenharmony_ci    assert(strncmp(buf, expected, ret) == 0);
2666881f68fSopenharmony_ci    free(expected);
2676881f68fSopenharmony_ci    retrieve_status = 2;
2686881f68fSopenharmony_ci    fuse_reply_none(req);
2696881f68fSopenharmony_ci}
2706881f68fSopenharmony_ci
2716881f68fSopenharmony_ci
2726881f68fSopenharmony_cistatic const struct fuse_lowlevel_ops tfs_oper = {
2736881f68fSopenharmony_ci    .lookup	= tfs_lookup,
2746881f68fSopenharmony_ci    .getattr	= tfs_getattr,
2756881f68fSopenharmony_ci    .readdir	= tfs_readdir,
2766881f68fSopenharmony_ci    .open	= tfs_open,
2776881f68fSopenharmony_ci    .read	= tfs_read,
2786881f68fSopenharmony_ci    .forget     = tfs_forget,
2796881f68fSopenharmony_ci    .retrieve_reply = tfs_retrieve_reply,
2806881f68fSopenharmony_ci};
2816881f68fSopenharmony_ci
2826881f68fSopenharmony_cistatic void update_fs(void) {
2836881f68fSopenharmony_ci    struct tm *now;
2846881f68fSopenharmony_ci    time_t t;
2856881f68fSopenharmony_ci    t = time(NULL);
2866881f68fSopenharmony_ci    now = localtime(&t);
2876881f68fSopenharmony_ci    assert(now != NULL);
2886881f68fSopenharmony_ci
2896881f68fSopenharmony_ci    file_size = strftime(file_contents, MAX_STR_LEN,
2906881f68fSopenharmony_ci                         "The current time is %H:%M:%S\n", now);
2916881f68fSopenharmony_ci    assert(file_size != 0);
2926881f68fSopenharmony_ci}
2936881f68fSopenharmony_ci
2946881f68fSopenharmony_cistatic void* update_fs_loop(void *data) {
2956881f68fSopenharmony_ci    struct fuse_session *se = (struct fuse_session*) data;
2966881f68fSopenharmony_ci    struct fuse_bufvec bufv;
2976881f68fSopenharmony_ci    int ret;
2986881f68fSopenharmony_ci
2996881f68fSopenharmony_ci    while(1) {
3006881f68fSopenharmony_ci        update_fs();
3016881f68fSopenharmony_ci        if (!options.no_notify && lookup_cnt) {
3026881f68fSopenharmony_ci            /* Only send notification if the kernel
3036881f68fSopenharmony_ci               is aware of the inode */
3046881f68fSopenharmony_ci            bufv.count = 1;
3056881f68fSopenharmony_ci            bufv.idx = 0;
3066881f68fSopenharmony_ci            bufv.off = 0;
3076881f68fSopenharmony_ci            bufv.buf[0].size = file_size;
3086881f68fSopenharmony_ci            bufv.buf[0].mem = file_contents;
3096881f68fSopenharmony_ci            bufv.buf[0].flags = 0;
3106881f68fSopenharmony_ci
3116881f68fSopenharmony_ci            /* This shouldn't fail, but apparently it sometimes
3126881f68fSopenharmony_ci               does - see https://github.com/libfuse/libfuse/issues/105 */
3136881f68fSopenharmony_ci            ret = fuse_lowlevel_notify_store(se, FILE_INO, 0, &bufv, 0);
3146881f68fSopenharmony_ci            if (-ret == ENODEV) {
3156881f68fSopenharmony_ci                // File system was unmounted
3166881f68fSopenharmony_ci                break;
3176881f68fSopenharmony_ci            }
3186881f68fSopenharmony_ci            else if (ret != 0) {
3196881f68fSopenharmony_ci                fprintf(stderr, "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n",
3206881f68fSopenharmony_ci                        strerror(-ret), -ret);
3216881f68fSopenharmony_ci                abort();
3226881f68fSopenharmony_ci            }
3236881f68fSopenharmony_ci
3246881f68fSopenharmony_ci            /* To make sure that everything worked correctly, ask the
3256881f68fSopenharmony_ci               kernel to send us back the stored data */
3266881f68fSopenharmony_ci            ret = fuse_lowlevel_notify_retrieve(se, FILE_INO, MAX_STR_LEN,
3276881f68fSopenharmony_ci                                                0, (void*) strdup(file_contents));
3286881f68fSopenharmony_ci            if (-ret == ENODEV) { // File system was unmounted
3296881f68fSopenharmony_ci                break;
3306881f68fSopenharmony_ci            }
3316881f68fSopenharmony_ci            assert(ret == 0);
3326881f68fSopenharmony_ci            if(retrieve_status == 0)
3336881f68fSopenharmony_ci                retrieve_status = 1;
3346881f68fSopenharmony_ci        }
3356881f68fSopenharmony_ci        sleep(options.update_interval);
3366881f68fSopenharmony_ci    }
3376881f68fSopenharmony_ci    return NULL;
3386881f68fSopenharmony_ci}
3396881f68fSopenharmony_ci
3406881f68fSopenharmony_cistatic void show_help(const char *progname)
3416881f68fSopenharmony_ci{
3426881f68fSopenharmony_ci    printf("usage: %s [options] <mountpoint>\n\n", progname);
3436881f68fSopenharmony_ci    printf("File-system specific options:\n"
3446881f68fSopenharmony_ci               "    --update-interval=<secs>  Update-rate of file system contents\n"
3456881f68fSopenharmony_ci               "    --no-notify            Disable kernel notifications\n"
3466881f68fSopenharmony_ci               "\n");
3476881f68fSopenharmony_ci}
3486881f68fSopenharmony_ci
3496881f68fSopenharmony_ciint main(int argc, char *argv[]) {
3506881f68fSopenharmony_ci    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3516881f68fSopenharmony_ci    struct fuse_session *se;
3526881f68fSopenharmony_ci    struct fuse_cmdline_opts opts;
3536881f68fSopenharmony_ci    struct fuse_loop_config config;
3546881f68fSopenharmony_ci    pthread_t updater;
3556881f68fSopenharmony_ci    int ret = -1;
3566881f68fSopenharmony_ci
3576881f68fSopenharmony_ci    if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
3586881f68fSopenharmony_ci        return 1;
3596881f68fSopenharmony_ci
3606881f68fSopenharmony_ci    if (fuse_parse_cmdline(&args, &opts) != 0)
3616881f68fSopenharmony_ci        return 1;
3626881f68fSopenharmony_ci    if (opts.show_help) {
3636881f68fSopenharmony_ci        show_help(argv[0]);
3646881f68fSopenharmony_ci        fuse_cmdline_help();
3656881f68fSopenharmony_ci        fuse_lowlevel_help();
3666881f68fSopenharmony_ci        ret = 0;
3676881f68fSopenharmony_ci        goto err_out1;
3686881f68fSopenharmony_ci    } else if (opts.show_version) {
3696881f68fSopenharmony_ci        printf("FUSE library version %s\n", fuse_pkgversion());
3706881f68fSopenharmony_ci        fuse_lowlevel_version();
3716881f68fSopenharmony_ci        ret = 0;
3726881f68fSopenharmony_ci        goto err_out1;
3736881f68fSopenharmony_ci    }
3746881f68fSopenharmony_ci
3756881f68fSopenharmony_ci    /* Initial contents */
3766881f68fSopenharmony_ci    update_fs();
3776881f68fSopenharmony_ci
3786881f68fSopenharmony_ci    se = fuse_session_new(&args, &tfs_oper,
3796881f68fSopenharmony_ci                          sizeof(tfs_oper), NULL);
3806881f68fSopenharmony_ci    if (se == NULL)
3816881f68fSopenharmony_ci        goto err_out1;
3826881f68fSopenharmony_ci
3836881f68fSopenharmony_ci    if (fuse_set_signal_handlers(se) != 0)
3846881f68fSopenharmony_ci        goto err_out2;
3856881f68fSopenharmony_ci
3866881f68fSopenharmony_ci    if (fuse_session_mount(se, opts.mountpoint) != 0)
3876881f68fSopenharmony_ci        goto err_out3;
3886881f68fSopenharmony_ci
3896881f68fSopenharmony_ci    fuse_daemonize(opts.foreground);
3906881f68fSopenharmony_ci
3916881f68fSopenharmony_ci    /* Start thread to update file contents */
3926881f68fSopenharmony_ci    ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
3936881f68fSopenharmony_ci    if (ret != 0) {
3946881f68fSopenharmony_ci        fprintf(stderr, "pthread_create failed with %s\n",
3956881f68fSopenharmony_ci                strerror(ret));
3966881f68fSopenharmony_ci        goto err_out3;
3976881f68fSopenharmony_ci    }
3986881f68fSopenharmony_ci
3996881f68fSopenharmony_ci    /* Block until ctrl+c or fusermount -u */
4006881f68fSopenharmony_ci    if (opts.singlethread)
4016881f68fSopenharmony_ci        ret = fuse_session_loop(se);
4026881f68fSopenharmony_ci    else {
4036881f68fSopenharmony_ci        config.clone_fd = opts.clone_fd;
4046881f68fSopenharmony_ci        config.max_idle_threads = opts.max_idle_threads;
4056881f68fSopenharmony_ci        ret = fuse_session_loop_mt(se, &config);
4066881f68fSopenharmony_ci    }
4076881f68fSopenharmony_ci
4086881f68fSopenharmony_ci    assert(retrieve_status != 1);
4096881f68fSopenharmony_ci    fuse_session_unmount(se);
4106881f68fSopenharmony_cierr_out3:
4116881f68fSopenharmony_ci    fuse_remove_signal_handlers(se);
4126881f68fSopenharmony_cierr_out2:
4136881f68fSopenharmony_ci    fuse_session_destroy(se);
4146881f68fSopenharmony_cierr_out1:
4156881f68fSopenharmony_ci    free(opts.mountpoint);
4166881f68fSopenharmony_ci    fuse_opt_free_args(&args);
4176881f68fSopenharmony_ci
4186881f68fSopenharmony_ci    return ret ? 1 : 0;
4196881f68fSopenharmony_ci}
4206881f68fSopenharmony_ci
4216881f68fSopenharmony_ci
4226881f68fSopenharmony_ci/**
4236881f68fSopenharmony_ci * Local Variables:
4246881f68fSopenharmony_ci * mode: c
4256881f68fSopenharmony_ci * indent-tabs-mode: nil
4266881f68fSopenharmony_ci * c-basic-offset: 4
4276881f68fSopenharmony_ci * End:
4286881f68fSopenharmony_ci */
429