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