示例#1
0
文件: match.c 项目: bjb/vdev
// parse a regex and append it to a list of regexes and strings
// return 0 on success
// return -EINVAL if the regex is invalid
// return -ENOMEM if we're out of memory
int vdev_match_regex_append( char*** strings, regex_t** regexes, size_t* len, char const* next ) {
   
   // verify that this is a valid regex 
   regex_t reg;
   int rc = 0;
   
   memset( &reg, 0, sizeof(regex_t) );
   
   rc = regcomp( &reg, next, REG_EXTENDED | REG_NEWLINE | REG_NOSUB );
   if( rc != 0 ) {
      
      vdev_error("regcomp(%s) rc = %d\n", next, rc );
      return -EINVAL;
   }
   
   char** new_strings = (char**)realloc( *strings, sizeof(char**) * (*len + 2) );
   regex_t* new_regexes = (regex_t*)realloc( *regexes, sizeof(regex_t) * (*len + 1) );
   
   if( new_strings == NULL || new_regexes == NULL ) {
      return -ENOMEM;
   }
   
   new_strings[*len] = vdev_strdup_or_null( next );
   new_strings[*len + 1] = NULL;
   
   new_regexes[*len] = reg;
   
   *strings = new_strings;
   *regexes = new_regexes;
   
   *len = *len + 1;
   
   return 0;
}
示例#2
0
文件: fs.cpp 项目: 8l/vdev
// 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;
}
示例#3
0
文件: fs.cpp 项目: 8l/vdev
// load the filesystem with metadata from under the mountpoint
// return 0 on success 
// return -ENOMEM on OOM
static int vdevfs_dev_import( struct fskit_fuse_state* fs, void* arg ) {
   
   struct vdevfs* vdev = (struct vdevfs*)arg;
   int rc = 0;
   queue<int> dirfds;           // directory descriptors
   queue<char*> dirpaths;       // relative paths to the mountpoint 
   struct fskit_entry* dir_ent = NULL;
   
   struct vdevfs_scandirat_context scan_context;
   
   char* root = vdev_strdup_or_null("/");
   if( root == NULL ) {
      return -ENOMEM;
   }
   
   int root_fd = dup( vdev->mountpoint_dirfd );
   if( root_fd < 0 ) {
      
      vdev_error("dup(%d) rc = %d\n", vdev->mountpoint_dirfd, rc );
      rc = -errno;
      free( root );
      return rc;
   }
   
   // start at the mountpoint
   try {
      
      dirfds.push( root_fd );
      dirpaths.push( root );
   }
   catch( bad_alloc& ba ) {
      
      free( root );
      return -ENOMEM;
   }
   
   while( dirfds.size() > 0 ) {
      
      // next directory 
      int dirfd = dirfds.front();
      char* dirpath = dirpaths.front();
      
      dirfds.pop();
      dirpaths.pop();
      
      // look up this entry 
      dir_ent = fskit_entry_resolve_path( fskit_fuse_get_core( vdev->fs ), dirpath, 0, 0, true, &rc );
      if( rc != 0 ) {
         
         // shouldn't happen--we're going breadth-first 
         vdev_error("fskit_entry_resolve_path('%s') rc = %d\n", dirpath, rc );
         
         close( dirfd );
         free( dirpath );
         dirpath = NULL;
        
         break;
      }
      
      // make a scan context 
      vdevfs_scandirat_context_init( &scan_context, fskit_fuse_get_core( vdev->fs ), dir_ent, dirpath, &dirfds, &dirpaths );
      
      // scan this directory 
      rc = vdev_load_all_at( dirfd, vdevfs_scandirat_context_callback, &scan_context );
      
      fskit_entry_unlock( dir_ent );
      
      if( rc != 0 ) {
         
         // failed
         vdev_error("vdev_load_all_at(%d, '%s') rc = %d\n", dirfd, dirpath, rc );
      }
      
      close( dirfd );
      free( dirpath );
      dirpath = NULL;
      
      if( rc != 0 ) {
         break;
      }
   }
   
   // free any remaining directory state 
   size_t num_dirfds = dirfds.size();
   for( unsigned int i = 0; i < num_dirfds; i++ ) {
      
      int next_dirfd = dirfds.front();
      dirfds.pop();
      
      close( next_dirfd );
   }
   
   size_t num_dirpaths = dirpaths.size();
   for( unsigned int i = 0; i < num_dirpaths; i++ ) {
      
      char* path = dirpaths.front();
      dirpaths.pop();
      
      free( path );
   }
   
   return rc;
}
示例#4
0
文件: linux.c 项目: 8l/vdev
// parse a uevent, and use the information to fill in a device request.
// nlbuf must be a contiguous concatenation of null-terminated KEY=VALUE strings.
// return 0 on success
static int vdev_linux_parse_request( struct vdev_linux_context* ctx, struct vdev_device_request* vreq, char* nlbuf, ssize_t buflen ) {
   
   char* buf = nlbuf;
   char* key = NULL;
   char* value = NULL;
   int offset = 0;
   int rc = 0;
   unsigned int major = 0;
   unsigned int minor = 0;
   bool have_major = false;
   bool have_minor = false;
   mode_t dev_mode = 0;
   int line_count = 0;
   bool not_param = false;      // if set to true, add as an OS-specific parameter to the vreq
   
   char* devpath = NULL;        // sysfs devpath 
   char* subsystem = NULL;      // sysfs subsystem 
   char* devname = (char*)VDEV_DEVICE_PATH_UNKNOWN;        // DEVNAME from uevent
   
   vdev_device_request_t reqtype = VDEV_DEVICE_INVALID;
   
   vdev_debug("%p: uevent buffer\n", vreq );
   vdev_linux_debug_uevent( nlbuf, buflen );
   
   // sanity check: if the first line is $action@$devpath, then skip it (since the information 
   // contained in the uevent will encode the very same bits of information)
   if( strchr(buf, '@') != NULL ) { 
         
      // advance to the next line
      offset += strlen(buf) + 1;
   }
   
   // get key/value pairs
   while( offset < buflen ) {
      
      line_count++;
      not_param = false;
      
      rc = vdev_keyvalue_next( buf + offset, &key, &value );
      
      if( rc < 0 ) {
         
         vdev_error("Invalid line %d (byte %d): '%s'\n", line_count, offset, buf + offset );
         vdev_linux_error_uevent( nlbuf, buflen );
         
         return -EINVAL;
      }
      
      offset += rc + 1;         // count the \0 at the end
      rc = 0;
      
      // is this the action to take?
      if( strcmp(key, "ACTION") == 0 ) {
         
         reqtype = vdev_linux_parse_device_request_type( value );
         
         if( reqtype == VDEV_DEVICE_INVALID ) {
            
            vdev_error("Invalid ACTION '%s'\n", value );
            vdev_linux_error_uevent( nlbuf, buflen );
            
            return -EINVAL;
         }
         
         vdev_device_request_set_type( vreq, reqtype );
         
         not_param = true;
      }
      
      // is this the sysfs device path?
      else if( strcmp(key, "DEVPATH") == 0 ) {
         
         devpath = value;
      }
      
      // is this the devname?
      else if( strcmp(key, "DEVNAME") == 0 ) {
         
         devname = value;
      }
      
      // subsystem given?
      else if( strcmp(key, "SUBSYSTEM") == 0 ) {
         
         subsystem = vdev_strdup_or_null( value );
      }
      
      // is this the major device number?
      else if( strcmp(key, "MAJOR") == 0 && !have_major ) {
         
         char* tmp = NULL;
         major = (int)strtol( value, &tmp, 10 );
         
         if( *tmp != '\0' ) {
            
            vdev_error("Invalid 'MAJOR' value '%s'\n", value);
            vdev_linux_error_uevent( nlbuf, buflen );
            
            return -EINVAL;
         }
         
         have_major = true;
         not_param = true;
      }
      
      // is this the minor device number?
      else if( strcmp(key, "MINOR") == 0 && !have_minor ) {
         
         char* tmp = NULL;
         minor = (int)strtol( value, &tmp, 10 ) ;
         
         if( *tmp != '\0' ) {
            
            vdev_error("Invalid 'MINOR' value '%s'\n", value );
            vdev_linux_error_uevent( nlbuf, buflen );
            
            return -EINVAL;
         }
         
         have_minor = true;
         not_param = true;
      }
      
      if( !not_param ) {
         
         // add to OS params 
         rc = vdev_device_request_add_param( vreq, key, value );
         if( rc != 0 ) {
            
            // could be OOM 
            if( subsystem != NULL ) {
               free( subsystem );
            }
            
            return rc;
         }
      }
   }
   
   if( reqtype == VDEV_DEVICE_INVALID ) {
      
      vdev_error("%s", "No ACTION given\n");
      vdev_linux_error_uevent( nlbuf, buflen );
      
      if( subsystem != NULL ) {
         free( subsystem );
      }
      
      return -EINVAL;
   }
   
   if( (!have_major && have_minor) || (have_major && !have_minor) ) {
      
      vdev_error("Missing device information: major=%d, minor=%d\n", have_major, have_minor );
      vdev_linux_error_uevent( nlbuf, buflen );
      
      if( subsystem != NULL ) {
         free( subsystem );
      }
      
      return -EINVAL;
   }
   
   if( have_major && have_minor ) {
      
      // explicit major and minor device numbers given 
      vdev_device_request_set_dev( vreq, makedev(major, minor) );
   }
   
   if( devname != NULL ) {
      
      // use this as the device's path 
      vdev_device_request_set_path( vreq, devname );
   }
   
   if( devpath != NULL ) {
      
      // get any remaining information from sysfs 
      // check major/minor?
      if( !have_major || !have_minor ) {
         
         // see if we have major/minor device numbers for this device...
         rc = vdev_linux_sysfs_read_dev_nums( ctx, devpath, &major, &minor );
         
         if( rc == 0 ) {
            
            // yup!
            vdev_device_request_set_dev( vreq, makedev(major, minor) );
            
            have_major = true;
            have_minor = true;
         }
         else {
            
            // it's okay to not have dev numbers
            rc = 0;
         }
      }
      
      // subsystem?
      if( subsystem == NULL ) {
         
         // see if we have a subsystem 
         rc = vdev_linux_sysfs_read_subsystem( ctx, devpath, &subsystem );
         
         if( rc == 0 ) {
            
            // yup!
            rc = vdev_device_request_add_param( vreq, "SUBSYSTEM", subsystem );
            if( rc != 0 ) {
               
               // OOM
               free( subsystem );
               return rc;
            }
         }
         else if( rc != -ENOMEM ) {
            
            // this is weird...
            vdev_warn("no subsystem found for '%s'\n", devpath );
            rc = 0;
         }
      }
   }
   
   if( have_major && have_minor ) {
      
      if( subsystem != NULL && strcasecmp(subsystem, "block") == 0 ) {
         
         // this is a block 
         dev_mode = S_IFBLK;
      }
      
      else {
         
         // this is a character device--we have major/minor numbers
         dev_mode = S_IFCHR;
      }
   
      vdev_device_request_set_mode( vreq, dev_mode );
   }
   
   vdev_debug("subsystem = '%s', have_major=%d, major = %u, have_minor=%d, minor = %u, mode = %o\n", subsystem, have_major, major, have_minor, minor, dev_mode );
   
   if( subsystem != NULL ) {
      free( subsystem );
   }
   
   // tell helpers where /sys is mounted 
   rc = vdev_device_request_add_param( vreq, "SYSFS_MOUNTPOINT", ctx->sysfs_mountpoint );
   if( rc != 0 ) {
      
      // OOM 
      return rc;
   }
   
   return rc;
}