int fskit_fuse_chown(const char *path, uid_t new_uid, gid_t new_gid) { struct fskit_fuse_state* state = fskit_fuse_get_state(); if( (state->callbacks & FSKIT_FUSE_CHOWN) == 0 ) { return -ENOSYS; } fskit_debug("chown(%s, %d, %d)\n", path, new_uid, new_gid ); uid_t uid = fskit_fuse_get_uid( state ); gid_t gid = fskit_fuse_get_gid( state ); int rc = fskit_chown( state->core, path, uid, gid, new_uid, new_gid ); fskit_debug("chown(%s, %d, %d) rc = %d\n", path, new_uid, new_gid, rc ); return rc; }
// initialize the filesystem front-end // call after vdev_init // return 0 on success // return -ENOMEM on OOM // return negative on error int vdevfs_init( struct vdevfs* vdev, int argc, char** argv ) { int rc = 0; int rh = 0; struct fskit_core* core = NULL; int fuse_argc = 0; char** fuse_argv = NULL; int dirfd = 0; // library setup vdev_setup_global(); struct fskit_fuse_state* fs = VDEV_CALLOC( struct fskit_fuse_state, 1 ); if( fs == NULL ) { return -ENOMEM; } fuse_argv = VDEV_CALLOC( char*, argc + 5 ); if( fuse_argv == NULL ) { free( fs ); return -ENOMEM; } // load config vdev->config = VDEV_CALLOC( struct vdev_config, 1 ); if( vdev->config == NULL ) { free( fs ); free( fuse_argv ); return -ENOMEM; } // init config rc = vdev_config_init( vdev->config ); if( rc != 0 ) { vdev_error("vdev_config_init rc = %d\n", rc ); vdevfs_shutdown( vdev ); free( fs ); free( fuse_argv ); return rc; } // parse opts rc = vdev_config_load_from_args( vdev->config, argc, argv, &fuse_argc, fuse_argv ); if( rc != 0 ) { vdev_error("vdev_opts_parse rc = %d\n", rc ); vdev_config_usage( argv[0] ); free( fs ); free( fuse_argv ); vdevfs_shutdown( vdev ); return rc; } // get the mountpoint, but from FUSE if( vdev->config->mountpoint != NULL ) { free( vdev->config->mountpoint ); } rc = vdev_get_mountpoint( fuse_argc, fuse_argv, &vdev->config->mountpoint ); if( rc != 0 ) { vdev_error("vdev_get_mountpoint rc = %d\n", rc ); vdev_config_usage( argv[0] ); free( fs ); free( fuse_argv ); return rc; } vdev_set_debug_level( vdev->config->debug_level ); vdev_set_error_level( vdev->config->error_level ); vdev_debug("Config file: %s\n", vdev->config->config_path ); rc = vdev_config_load( vdev->config->config_path, vdev->config ); if( rc != 0 ) { vdev_error("vdev_config_load('%s') rc = %d\n", vdev->config->config_path, rc ); vdevfs_shutdown( vdev ); free( fs ); free( fuse_argv ); return rc; } vdev_debug("vdev ACLs dir: %s\n", vdev->config->acls_dir ); // force -odev, since we'll create device nodes fuse_argv[fuse_argc] = (char*)vdev_fuse_odev; fuse_argc++; // force -oallow_other, since we'll want to expose this to everyone fuse_argv[fuse_argc] = (char*)vdev_fuse_allow_other; fuse_argc++; // force -ononempty, since we'll want to import the underlying filesystem fuse_argv[fuse_argc] = (char*)vdev_fuse_ononempty; fuse_argc++; vdev->mountpoint = vdev_strdup_or_null( vdev->config->mountpoint ); if( vdev->mountpoint == NULL ) { vdev_error("Failed to set mountpoint, config.mountpount = '%s'\n", vdev->config->mountpoint ); vdevfs_shutdown( vdev ); free( fuse_argv ); free( fs ); return -EINVAL; } else { vdev_debug("mountpoint: %s\n", vdev->mountpoint ); } vdev->argc = argc; vdev->argv = argv; vdev->fuse_argc = fuse_argc; vdev->fuse_argv = fuse_argv; fskit_set_debug_level( vdev->config->debug_level ); fskit_set_error_level( vdev->config->error_level ); // get mountpoint directory dirfd = open( vdev->mountpoint, O_DIRECTORY ); if( dirfd < 0 ) { rc = -errno; vdev_error("open('%s') rc = %d\n", vdev->mountpoint, rc ); free( fs ); vdevfs_shutdown( vdev ); return rc; } vdev->mountpoint_dirfd = dirfd; // set up fskit rc = fskit_fuse_init( fs, vdev ); if( rc != 0 ) { vdev_error("fskit_fuse_init rc = %d\n", rc ); free( fs ); vdevfs_shutdown( vdev ); return rc; } // load ACLs rc = vdev_acl_load_all( vdev->config->acls_dir, &vdev->acls, &vdev->num_acls ); if( rc != 0 ) { vdev_error("vdev_acl_load_all('%s') rc = %d\n", vdev->config->acls_dir, rc ); fskit_fuse_shutdown( fs, NULL ); free( fs ); vdevfs_shutdown( vdev ); return rc; } // make sure the fs can access its methods through the VFS fskit_fuse_setting_enable( fs, FSKIT_FUSE_SET_FS_ACCESS ); core = fskit_fuse_get_core( fs ); // add handlers. rh = fskit_route_readdir( core, FSKIT_ROUTE_ANY, vdevfs_readdir, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_readdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_stat( core, FSKIT_ROUTE_ANY, vdevfs_stat, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_stat(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_mknod( core, FSKIT_ROUTE_ANY, vdevfs_mknod, FSKIT_CONCURRENT ); if( rc < 0 ) { vdev_error("fskit_route_mknod(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_mkdir( core, FSKIT_ROUTE_ANY, vdevfs_mkdir, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_mkdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_create( core, FSKIT_ROUTE_ANY, vdevfs_create, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_create(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_open( core, FSKIT_ROUTE_ANY, vdevfs_open, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_open(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_read( core, FSKIT_ROUTE_ANY, vdevfs_read, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_read(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_write( core, FSKIT_ROUTE_ANY, vdevfs_write, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_write(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_close( core, FSKIT_ROUTE_ANY, vdevfs_close, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_close(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_sync( core, FSKIT_ROUTE_ANY, vdevfs_sync, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_sync(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } rh = fskit_route_detach( core, FSKIT_ROUTE_ANY, vdevfs_detach, FSKIT_CONCURRENT ); if( rh < 0 ) { vdev_error("fskit_route_detach(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); goto vdev_route_fail; } vdev->fs = fs; vdev->close_rh = rh; // set the root to be owned by the effective UID and GID of user fskit_chown( core, "/", 0, 0, geteuid(), getegid() ); // import the underlying filesystem once we're mounted, but before taking requests. rc = fskit_fuse_postmount_callback( fs, vdevfs_dev_import, vdev ); if( rc != 0 ) { vdev_error("fskit_fuse_postmount_callback() rc = %d\n", rc ); vdev->fs = NULL; goto vdev_route_fail; } return 0; vdev_route_fail: fskit_fuse_shutdown( fs, NULL ); free( fs ); vdevfs_shutdown( vdev ); return rh; }