Parsing the Command Line and Initializing FUSE

You actually have to do very little command-line parsing: FUSE understands a large number of command-line arguments, and parses them itself. Most importantly, FUSE expects the mountpoint to be one of the members of the argv[] array.

However, if there are arguments that your code needs to parse and understand, you need to parse them before starting FUSE. We can see an example of this in BBFS: the underlying directory that is being watched is interacted with by BBFS, not by FUSE. Consequently, I need to examine the command-line arguments and find that file. Borrowing from the mount command, I decided that the underlying directory should be the first argument on the line that didn't have a dash in front of it. The code for this is in main(); it looks like this:

for (i = 1; (i < argc) && (argv[i][0] == '-'); i++)
    if (argv[i][1] == 'o') i++; // -o takes a parameter; need to
  			        // skip it too.  This doesn't
				// handle "squashed" parameters
    
if ((argc - i) != 2) bb_usage();

bb_data->rootdir = realpath(argv[i], NULL);

argv[i] = argv[i+1];
argc--;

fprintf(stderr, "about to call fuse_main\n");
fuse_stat = fuse_main(argc, argv, &bb_oper, bb_data);

The for-loop goes past any options, assuming libfuse will know what to do with them. If I had any options interpreted by my code (for instance, if I allowed the user to change the name of the log file), this is where I'd parse them. For that matter, if the parsing were even slightly more complicated than this I'd use getopt()).

Once I'm past the options, I should have exactly two arguments left: the root directory and the mountpoint. If I don't, I print a usage message and exit. If I do, I call the C library realpath() function to canonicalize the directory name, and point bb_data->rootdir to it (of course, bb_data has been calloc()ed before this code is reached).

After I've done that, I remove the root directory from the argument vector and reduce the argument count. I don't need to look for the mountpoint, since FUSE will find that for itself.

Once I'm ready to start the filesystem, I call fuse_main(). Its parameters are argc and argv (as modified by my main() function), the bb_oper struct containing pointers to my re-implementations of the POSIX file operations, and a struct bb_data, used for storing private data. Private data will be discussed in the next section.

fuse_main() parses the rest of the command line, mounts the directory specified on the command line, and performs other initializations. Then, it calls an initialization function to perform any initialization defined by my code. bb_oper->init points to my bb_init() function, so it is called next. My bb_init() function is really small; all it does is calls a function called log_open() and then log the fact that it has been called. log_open() depends heavily on the private data I passed in bb_data, so we'll wait to duscuss it until the next section.

Next: Private Data
Last modified: Mon Jan 10 17:42:23 MST 2011