Imported Upstream version 1.5.1

This commit is contained in:
Mario Fetka
2020-09-22 02:25:22 +02:00
commit 434d6067d9
2103 changed files with 928962 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
/*
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#include "fuse/fuse_operations.h"
#include "fuse/fuse_adapter.h"
#include "util/logging.h"
using namespace std;
using namespace xtreemfs::util;
xtreemfs::FuseAdapter* fuse_adapter = NULL;
int xtreemfs_fuse_getattr(const char *path, struct stat *statbuf) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "getattr on path " << path << endl;
}
return fuse_adapter->getattr(path, statbuf);
}
int xtreemfs_fuse_readlink(const char *path, char *link, size_t size) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_readlink on path " << path << endl;
}
return fuse_adapter->readlink(path, link, size);
}
int xtreemfs_fuse_mknod(const char *path, mode_t mode, dev_t dev) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_mknod on path "
<< path << endl;
}
return fuse_adapter->mknod(path, mode, dev);
}
int xtreemfs_fuse_mkdir(const char *path, mode_t mode) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_mkdir on path "
<< path << endl;
}
return fuse_adapter->mkdir(path, mode);
}
int xtreemfs_fuse_unlink(const char *path) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_unlink " << path
<< endl;
}
return fuse_adapter->unlink(path);
}
int xtreemfs_fuse_rmdir(const char *path) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_rmdir on path " << path
<< endl;
}
return fuse_adapter->rmdir(path);
}
int xtreemfs_fuse_symlink(const char *path, const char *link) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_symlink on path "
<< path << endl;
}
return fuse_adapter->symlink(path, link);
}
int xtreemfs_fuse_rename(const char *path, const char *newpath) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_rename on path " << path << " to " << newpath <<
endl;
}
return fuse_adapter->rename(path, newpath);
}
int xtreemfs_fuse_link(const char *path, const char *newpath) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_link on path " << path << " " << newpath << endl;
}
return fuse_adapter->link(path, newpath);
}
int xtreemfs_fuse_chmod(const char *path, mode_t mode) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_chmod on path " << path
<< endl;
}
return fuse_adapter->chmod(path, mode);
}
int xtreemfs_fuse_lock(const char* path,
struct fuse_file_info *fi,
int cmd,
struct flock* flock_) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
string log_command;
switch(cmd) {
case F_GETLK:
log_command = "check lock";
break;
case F_SETLK:
log_command = "set lock";
break;
case F_SETLKW:
log_command = "set lock and wait";
break;
default:
log_command = "unknown lock command";
break;
}
string log_type;
switch(flock_->l_type) {
case F_UNLCK:
log_type = "unlock";
break;
case F_RDLCK:
log_type = "read lock";
break;
case F_WRLCK:
log_type = "write lock";
break;
default:
log_type = "unknown lock type";
break;
}
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_lock on path " << path
<< " command: " << log_command << " type: " << log_type << " start: "
<< flock_->l_start << " length: "<< flock_->l_len << " pid: "
<< flock_->l_pid << endl;
}
return fuse_adapter->lock(path, fi, cmd, flock_);
}
int xtreemfs_fuse_chown(const char *path, uid_t uid, gid_t gid) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_chown on path " << path
<< endl;
}
return fuse_adapter->chown(path, uid, gid);
}
int xtreemfs_fuse_truncate(const char *path, off_t new_file_size) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_truncate on path " << path
<< " size:" << new_file_size << endl;
}
return fuse_adapter->truncate(path, new_file_size);
}
int xtreemfs_fuse_utime(const char *path, struct utimbuf *ubuf) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_utime on path " << path
<< endl;
}
return fuse_adapter->utime(path, ubuf);
}
int xtreemfs_fuse_utimens(const char *path, const struct timespec tv[2]) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_utimens on path "
<< path << endl;
}
return fuse_adapter->utimens(path, tv);
}
int xtreemfs_fuse_open(const char *path, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_open on path " << path
<< endl;
}
return fuse_adapter->open(path, fi);
}
int xtreemfs_fuse_release(const char *path, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_release " << path
<< endl;
}
return fuse_adapter->release(path, fi);
}
int xtreemfs_fuse_read(
const char *path, char *buf,
size_t size, off_t offset, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_read " << path
<< " s:" << size << " o:" << offset << endl;
}
int count = fuse_adapter->read(path, buf, size, offset, fi);
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_read finished " << path
<< " s:" << size << " o:" << offset << " r:" << count << endl;
}
return count;
}
int xtreemfs_fuse_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_write " << path
<< " s: " << size << " o:" << offset << endl;
}
int count = fuse_adapter->write(path, buf, size, offset, fi);
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_write finished " << path
<< " s:" << size << " o:" << offset << " w:" << count << endl;
}
return count;
}
int xtreemfs_fuse_statfs(const char *path, struct statvfs *statv) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_statfs " << path
<< endl;
}
return fuse_adapter->statfs(path, statv);
}
/** Unlink fsync(), flush() requests are NOT initiated from the user.
*
* Instead, flush() is a Fuse internal mechanism to avoid the problem that
* the return value of release() will be ignored.
*
* Therefore, a flush() will be called by Fuse with every close() executed by
* the user. Only errors returned by this flush() operation can be returned
* to the close() of the user.
*/
int xtreemfs_fuse_flush(const char *path, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_flush " << path
<< endl;
}
return fuse_adapter->flush(path, fi);
}
int xtreemfs_fuse_fsync(const char *path, int datasync,
struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_fsync " << path
<< endl;
}
// We ignore the datasync parameter as all metadata operations are
// synchronous and therefore never have to be flushed.
return fuse_adapter->flush(path, fi);
}
int xtreemfs_fuse_setxattr(
const char *path, const char *name,
const char *value, size_t size, int flags
#ifdef __APPLE__
, uint32_t position
#endif
) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_setxattr " << " " << path << " " << name << endl;
}
return fuse_adapter->setxattr(path, name, value, size, flags);
}
int xtreemfs_fuse_getxattr(
const char *path, const char *name, char *value, size_t size
#ifdef __APPLE__
, uint32_t position
#endif
) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_getxattr " << " " << path << " " << name << " "
<< size << endl;
}
return fuse_adapter->getxattr(path, name, value, size);
}
int xtreemfs_fuse_listxattr(const char *path, char *list, size_t size) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_listxattr " << path << " " << size << endl;
}
return fuse_adapter->listxattr(path, list, size);
}
int xtreemfs_fuse_removexattr(const char *path, const char *name) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_removexattr " << " " << path << " " << name << endl;
}
return fuse_adapter->removexattr(path, name);
}
int xtreemfs_fuse_opendir(const char *path, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_opendir " << path
<< endl;
}
return fuse_adapter->opendir(path, fi);
}
int xtreemfs_fuse_readdir(
const char *path, void *buf,
fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_readdir " << path
<< endl;
}
return fuse_adapter->readdir(path, buf, filler, offset, fi);
}
int xtreemfs_fuse_releasedir(const char *path, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG) && path != NULL) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_releasedir " << path
<< endl;
}
return fuse_adapter->releasedir(path, fi);
}
int xtreemfs_fuse_fsyncdir(
const char *path, int datasync, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_fsyncdir " << path
<< endl;
}
// Like fsync, but for directories - not required for XtreemFS.
return 0;
}
void *xtreemfs_fuse_init(struct fuse_conn_info *conn) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_init " << endl;
}
// http://sourceforge.net/apps/mediawiki/fuse/index.php?title=Fuse_file_info
// TODO(mberlin): Check for valid parameters.
conn->async_read = 5;
conn->max_readahead = 10 * 128 * 1024;
conn->max_write = 128 * 1024;
#if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8) // NOLINT
conn->capable
= FUSE_CAP_ASYNC_READ | FUSE_CAP_BIG_WRITES
| FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_POSIX_LOCKS;
conn->want
= FUSE_CAP_ASYNC_READ | FUSE_CAP_BIG_WRITES
| FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_POSIX_LOCKS;
#endif
struct fuse_context* context = fuse_get_context();
return context->private_data;
}
void xtreemfs_fuse_destroy(void *userdata) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_destroy " << endl;
}
}
/**
* This method will only be called by Fuse if "-o default_permissions" is not
* send to Fuse (for instance before changing the working directory).
*
* If "-o default_permissions" is enabled, Fuse does determine on its own, based
* on the result of the getattr, if the user is allowed to access the directory.
*/
int xtreemfs_fuse_access(const char *path, int mask) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_access " << path
<< endl;
}
return fuse_adapter->access(path, mask);
}
int xtreemfs_fuse_create(const char *path, mode_t mode,
struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "create on path " << path << endl;
}
return fuse_adapter->create(path, mode, fi);
}
int xtreemfs_fuse_ftruncate(
const char *path, off_t new_file_size, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG)
<< "xtreemfs_fuse_ftruncate on path " << path
<< " size:" << new_file_size << endl;
}
return fuse_adapter->ftruncate(path, new_file_size, fi);
}
int xtreemfs_fuse_fgetattr(
const char *path, struct stat *statbuf, struct fuse_file_info *fi) {
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "fgetattr on path " << path << endl;
}
return fuse_adapter->fgetattr(path, statbuf, fi);
}

View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#include "fuse/fuse_options.h"
#include <csignal>
#include <boost/lexical_cast.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <sstream>
#include "libxtreemfs/helper.h"
#include "libxtreemfs/xtreemfs_exception.h"
using namespace std;
namespace po = boost::program_options;
namespace style = boost::program_options::command_line_style;
namespace xtreemfs {
FuseOptions::FuseOptions() : Options(), fuse_descriptions_("Fuse Options") {
// Overwrite certain members of Options().
#ifndef __linux
// Interrupting read calls does not work with Linux Fuse.
max_read_tries = 0;
#endif
// Never give up to execute a request as we enabled interruption.
max_tries = 0;
max_write_tries = 0;
async_writes_max_request_size_kb = 128; // FUSE specific limit.
// Default Fuse options.
#ifdef __APPLE__
// We assume that the MacFuse default timeout is 60 seconds on Leopard.
daemon_timeout = 60;
// Always enable xattrs for Mac.
enable_xattrs = true;
// If we are under Leopard or newer, reduce the timeout values.
if (GetMacOSXKernelVersion() >= 9) {
max_tries = 3;
max_read_tries = 3;
max_write_tries = 3;
retry_delay_s = 15;
connect_timeout_s = 15;
// The detection of a timeout may take twice the time, i.e. up to 18 seconds
// resulting in a total time of 3 * 18 (< 60 seconds daemon_timeout default).
request_timeout_s = 9;
}
#else
enable_xattrs = false;
#endif // __APPLE__
foreground = false;
use_fuse_permission_checks = true;
fuse_permission_checks_explicitly_disabled = false;
fuse_descriptions_.add_options()
("foreground,f", po::value(&foreground)->zero_tokens(),
"Do not fork into background.")
("fuse_option,o",
po::value< vector<string> >(&fuse_options),
"Passes -o=<option> to Fuse if not recognized by mount.xtreemfs, "
"see 'Alternative Specification of options'.")
("no-default-permissions",
po::value(&fuse_permission_checks_explicitly_disabled)->zero_tokens(),
"Do not pass -o default_permissions to Fuse (disables local Fuse"
" permissions checks).");
po::options_description fuse_options_information(
"ACL and extended attributes Support:\n"
" -o xtreemfs_acl Enable the correct evaluation of XtreemFS ACLs.\n"
" (Note that you cannot use the system tools getfattr\n"
" and setfattr; use 'xtfsutil' instead to set and\n"
" retrieve ACLs.)"
#ifndef __APPLE__
"\n -o user_xattr Enable user defined extended attributes.");
#else
);
#endif // __APPLE__
fuse_descriptions_.add(fuse_options_information);
helptext_usage_ =
"mount.xtreemfs: Mounts an XtreemFS Volume.\n"
"\n"
"Usage: \n"
"\tmount.xtreemfs [options] [pbrpc[g|s]://]<dir-host>[:port]/<volume-name>"
" <mount point>\n"
"\n"
" Example: mount.xtreemfs localhost/myVolume ~/xtreemfs\n";
}
void FuseOptions::ParseCommandLine(int argc, char** argv) {
// Parse general options and retrieve unregistered options for own parsing.
vector<string> options = Options::ParseCommandLine(argc, argv);
// Read Volume URL and mount point from command line.
po::positional_options_description p;
p.add("dir_volume_url", 1);
p.add("mount_point", 1);
po::options_description mount("Mount options");
mount.add_options()
("dir_volume_url", po::value(&xtreemfs_url), "volume to mount")
("mount_point", po::value(&mount_point), "where to mount the volume");
// Parse command line.
po::options_description all_descriptions_;
all_descriptions_.add(mount).add(fuse_descriptions_);
po::variables_map vm;
try {
po::store(po::command_line_parser(options)
.options(all_descriptions_)
.positional(p)
.style(style::default_style & ~style::allow_guessing)
.run(), vm);
po::notify(vm);
} catch(const std::exception& e) {
// Rethrow boost errors due to invalid command line parameters.
throw InvalidCommandLineParametersException(string(e.what()));
}
// Do not check parameters if the help shall be shown.
if (show_help || empty_arguments_list || show_version) {
return;
}
// Split list of comma separated -o options and add them as extra options.
list<string> split_options;
for (int i = 0; i < fuse_options.size(); i++) {
typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
boost::char_separator<char> seperator(",");
tokenizer tokens(fuse_options[i], seperator);
// Check if there are at least two tokens and they have to be split up
tokenizer::iterator first_tokens = tokens.begin();
if (++first_tokens != tokens.end()) {
// Split tokens and add them to a temporary list.
for (tokenizer::iterator token = tokens.begin();
token != tokens.end();
++token) {
split_options.push_back(string(*token));
}
// Remove split tokens from fuse_options as they will be readded later.
fuse_options.erase(fuse_options.begin() + i);
i--;
}
}
// Readd split options.
for (list<string>::const_iterator iter = split_options.begin();
iter != split_options.end();
++iter) {
fuse_options.push_back(*iter);
}
// Evaluate certain Fuse options.
for (int i = 0; i < fuse_options.size(); i++) {
if (fuse_options[i] == "acl") {
throw InvalidCommandLineParametersException(
"The option -o acl is not supported. Specify -o xtreemfs_acl instead."
"\n\nWe do not allow -o acl because XtreemFS does not support the "
"getfacl and setfacl tools. You have to use 'xtfs_acl' instead "
"to set and retrieve ACLs.");
}
if (fuse_options[i] == "user_xattr") {
enable_xattrs = true;
// Don't send this option to Fuse.
fuse_options.erase(fuse_options.begin() + i);
i--;
continue;
}
if (fuse_options[i] == "xtreemfs_acl") {
// Fuse may prevent operations based on the evaluation of stat records
// although a user is allowed to due to further ACLs, so we disable this
// Fuse feature here.
use_fuse_permission_checks = false;
// Don't send this option to Fuse.
fuse_options.erase(fuse_options.begin() + i);
i--;
continue;
}
if (fuse_options[i] == "intr") {
// Don't send this option to Fuse.
fuse_options.erase(fuse_options.begin() + i);
i--;
throw InvalidCommandLineParametersException(
"The option -o intr will be ignored as command line parameter and"
" not passed through to Fuse. Use --interrupt-signal instead.");
}
if (fuse_options[i].substr(0, 12) == "intr_signal=") {
// Don't send this option to Fuse.
fuse_options.erase(fuse_options.begin() + i);
i--;
throw InvalidCommandLineParametersException(
"The option -o intr_signal will be ignored as command line "
"parameter and not passed through to Fuse. Use --interrupt-signal "
"instead.");
}
if (fuse_options[i] == "_netdev") {
// Don't send this option to Fuse, just ignore it, solves issue 276:
// https://code.google.com/p/xtreemfs/issues/detail?id=276
fuse_options.erase(fuse_options.begin() + i);
i--;
}
#ifdef __APPLE__
if (fuse_options[i].substr(0, 15) == "daemon_timeout=") {
try {
daemon_timeout = boost::lexical_cast<int>(fuse_options[i].substr(15));
continue;
} catch(const boost::bad_lexical_cast& e) {
throw InvalidCommandLineParametersException(
"The integer value after daemon_timeout could not be parsed: "
+ fuse_options[i].substr(15));
}
}
#endif
}
// Extract information from command line.
Options::ParseURL(kDIR);
// Check for required parameters.
if (service_addresses.empty()) {
throw InvalidCommandLineParametersException("missing DIR host.");
}
if (volume_name.empty()) {
throw InvalidCommandLineParametersException("missing volume name.");
}
if (mount_point.empty()) {
throw InvalidCommandLineParametersException("missing mount point.");
}
}
std::string FuseOptions::ShowCommandLineUsage() {
return helptext_usage_
+ "\nFor complete list of options, please specify -h or --help.\n";
}
std::string FuseOptions::ShowCommandLineHelp() {
ostringstream stream;
// No help text given in descriptions for positional mount options. Instead
// the usage is explained here.
stream << helptext_usage_
<< endl
// Descriptions of this class.
<< fuse_descriptions_
// Descriptions of the general options.
<< Options::ShowCommandLineHelp();
return stream.str();
}
} // namespace xtreemfs

View File

@@ -0,0 +1,283 @@
/*
* Copyright (c) 2010-2011 by Patrick Schaefer, Zuse Institute Berlin
* 2011 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#define FUSE_USE_VERSION 26
#include <errno.h>
#include <csignal>
#include <cstdio>
#include <cstring>
#include <fuse.h>
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include "util/logging.h"
#include "fuse/fuse_adapter.h"
#include "fuse/fuse_operations.h"
#include "fuse/fuse_options.h"
#include "libxtreemfs/xtreemfs_exception.h"
using namespace std;
using namespace xtreemfs::util;
int main(int argc, char **argv) {
// Parse command line options.
xtreemfs::FuseOptions options;
bool invalid_commandline_parameters = false;
try {
options.ParseCommandLine(argc, argv);
} catch(const xtreemfs::XtreemFSException& e) {
cout << "Invalid parameters found, error: " << e.what() << endl << endl;
invalid_commandline_parameters = true;
}
// Display help if needed.
if (options.empty_arguments_list || invalid_commandline_parameters) {
cout << options.ShowCommandLineUsage() << endl;
return 1;
}
if (options.show_help) {
cout << options.ShowCommandLineHelp() << endl;
return 1;
}
// Show only the version.
if (options.show_version) {
cout << options.ShowVersion("mount.xtreemfs") << endl;
return 1;
}
// In case of background operation: Fork before threads are created.
int fd[2];
int kErrorBufferSize = 1024;
char error_output[kErrorBufferSize];
memset(&error_output, 0, kErrorBufferSize);
if (!options.foreground) {
if (pipe(fd) < 0) {
cerr << "Failed to create pipe. (Needed to send process to background.)";
return 2;
}
pid_t pid = fork();
if (pid < 0) {
cerr << "Failed to fork(). (Needed to send process to background.)";
return 3;
}
// Evaluate pipe from daemonized thread.
if (pid > 0) { // Parent
// Cleanup the static memory in the parent to pass the valgrind
// leak check.
google::protobuf::ShutdownProtobufLibrary();
signal(SIGINT, SIG_IGN); // Ignore interrupt signals in parent.
// Close write end.
close(fd[1]);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(fd[0], &read_fds);
// Wait until there is something to read at the other end.
select(fd[0]+1, &read_fds, NULL, NULL, NULL);
int count = read(fd[0], error_output, kErrorBufferSize);
if (count == 0) {
// No error found, exiting.
return 0;
} else {
printf("mount.xtreemfs failed: %s\n", error_output);
return 4;
}
} else { // Child.
// Close read end of pipe.
close(fd[0]);
}
}
// Child only from here.
// Run client and open volume.
list<char*> required_fuse_options;
try {
fuse_adapter = new xtreemfs::FuseAdapter(&options);
fuse_adapter->Start(&required_fuse_options);
} catch(const xtreemfs::XtreemFSException& e) {
if (options.foreground) {
cerr << "mount.xtreemfs failed: " << e.what() << endl;
} else {
// Tell parent about error: write error to pipe and exit.
write(fd[1], e.what(), min(static_cast<int>(strlen(e.what()) + 1),
kErrorBufferSize));
}
fuse_adapter->Stop();
delete fuse_adapter;
return 5;
}
// Setup fuse and pass client and volume objects.
struct fuse_chan* fuse_channel = NULL;
struct fuse* fuse_ = NULL;
char* mount_point = NULL;
// Fill in operations.
struct fuse_operations xtreemfs_fuse_ops = {0};
xtreemfs_fuse_ops.getattr = xtreemfs_fuse_getattr;
xtreemfs_fuse_ops.readlink = xtreemfs_fuse_readlink;
xtreemfs_fuse_ops.mknod = xtreemfs_fuse_mknod;
xtreemfs_fuse_ops.mkdir = xtreemfs_fuse_mkdir;
xtreemfs_fuse_ops.unlink = xtreemfs_fuse_unlink;
xtreemfs_fuse_ops.rmdir = xtreemfs_fuse_rmdir;
xtreemfs_fuse_ops.symlink = xtreemfs_fuse_symlink;
xtreemfs_fuse_ops.rename = xtreemfs_fuse_rename;
xtreemfs_fuse_ops.link = xtreemfs_fuse_link;
xtreemfs_fuse_ops.chmod = xtreemfs_fuse_chmod;
xtreemfs_fuse_ops.chown = xtreemfs_fuse_chown;
xtreemfs_fuse_ops.truncate = xtreemfs_fuse_truncate;
xtreemfs_fuse_ops.utime = xtreemfs_fuse_utime;
xtreemfs_fuse_ops.open = xtreemfs_fuse_open;
xtreemfs_fuse_ops.read = xtreemfs_fuse_read;
xtreemfs_fuse_ops.write = xtreemfs_fuse_write;
xtreemfs_fuse_ops.statfs = xtreemfs_fuse_statfs;
xtreemfs_fuse_ops.flush = xtreemfs_fuse_flush;
xtreemfs_fuse_ops.release = xtreemfs_fuse_release;
xtreemfs_fuse_ops.fsync = xtreemfs_fuse_fsync;
xtreemfs_fuse_ops.setxattr = xtreemfs_fuse_setxattr;
xtreemfs_fuse_ops.getxattr = xtreemfs_fuse_getxattr;
xtreemfs_fuse_ops.listxattr = xtreemfs_fuse_listxattr;
xtreemfs_fuse_ops.removexattr = xtreemfs_fuse_removexattr;
xtreemfs_fuse_ops.opendir = xtreemfs_fuse_opendir;
xtreemfs_fuse_ops.readdir = xtreemfs_fuse_readdir;
xtreemfs_fuse_ops.releasedir = xtreemfs_fuse_releasedir;
xtreemfs_fuse_ops.fsyncdir = xtreemfs_fuse_fsyncdir;
xtreemfs_fuse_ops.init = xtreemfs_fuse_init;
xtreemfs_fuse_ops.destroy = xtreemfs_fuse_destroy;
xtreemfs_fuse_ops.access = xtreemfs_fuse_access;
xtreemfs_fuse_ops.create = xtreemfs_fuse_create;
xtreemfs_fuse_ops.ftruncate = xtreemfs_fuse_ftruncate;
xtreemfs_fuse_ops.fgetattr = xtreemfs_fuse_fgetattr;
xtreemfs_fuse_ops.lock = xtreemfs_fuse_lock;
xtreemfs_fuse_ops.utimens = xtreemfs_fuse_utimens;
#if FUSE_MAJOR_VERSION > 2 || ( FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8 ) // NOLINT
// We cannot work on unlinked files in case -ohard_remove was specified, so
// a null path is not okay.
xtreemfs_fuse_ops.flag_nullpath_ok = 0;
#endif // >= FUSE 2.8
#if FUSE_MAJOR_VERSION > 2 || ( FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9 ) // NOLINT
// We require Fuse to calculate the "path" for all file handle operations.
xtreemfs_fuse_ops.flag_nopath = 0;
#endif // >= FUSE 2.8
// Forward args.
vector<char*> fuse_opts;
// Fuse does not parse the first parameter, thus set it to "mount.xtreemfs".
fuse_opts.push_back((strdup("mount.xtreemfs")));
for (int i = 0; i < options.fuse_options.size(); i++) {
// Prepend "-o" to every Fuse option.
fuse_opts.push_back(strdup(
(string("-o") + options.fuse_options[i]).c_str()));
}
for (list<char*>::iterator it = required_fuse_options.begin();
it != required_fuse_options.end(); ++it) {
fuse_opts.push_back((*it));
}
struct fuse_args fuse_args = FUSE_ARGS_INIT(
static_cast<int>(fuse_opts.size()), &fuse_opts[0]);
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
Logging::log->getLog(LEVEL_DEBUG) << "About to call fuse_mount using "
<< fuse_opts.size() << " parameters: " << endl;
for (int i = 0; i < fuse_opts.size(); i++) {
Logging::log->getLog(LEVEL_DEBUG) << "\t" << fuse_opts[i] << endl;
}
}
// Create Fuse channel (mount_point will be freed by fuse_teardown()).
mount_point = strdup(options.mount_point.c_str());
struct stat mount_point_stat;
stat(mount_point, &mount_point_stat);
if((mount_point_stat.st_mode & S_IFMT) != S_IFDIR) {
cerr << mount_point << " is not a directory." << endl;
return 1;
}
// Fuse docu: "manually add arguments to the struct fuse_args list"
fuse_opt_parse(&fuse_args, NULL, NULL, NULL);
fuse_channel = fuse_mount(mount_point, &fuse_args);
if (fuse_channel == NULL) {
fuse_opt_free_args(&fuse_args);
for (int i = 0; i < fuse_opts.size(); i++) {
free(fuse_opts[i]);
}
free(mount_point);
// Stop FuseAdapter.
fuse_adapter->Stop();
delete fuse_adapter;
return errno;
}
// Create Fuse filesystem.
fuse_ = fuse_new(
fuse_channel,
&fuse_args,
&xtreemfs_fuse_ops,
sizeof(xtreemfs_fuse_ops),
NULL);
fuse_opt_free_args(&fuse_args);
if (fuse_ == NULL) {
// Avoid "Transport endpoint is not connected" in case fuse_new failed.
fuse_unmount(mount_point, fuse_channel);
for (int i = 0; i < fuse_opts.size(); i++) {
free(fuse_opts[i]);
}
free(mount_point);
// Stop FuseAdapter.
fuse_adapter->Stop();
delete fuse_adapter;
return errno;
}
// Send to background.
if (!options.foreground) {
// Close write end of pipe as no error was encountered.
close(fd[1]);
// Daemonize. (Do everything (except for the fork()), the regular daemon()
// would have done, too.)
// 1. Change the file mode mask.
umask(0);
// 2. Create a new SID for the child process.
if (setsid() < 0) {
return 6;
}
// 3. Change the current working directory. This prevents the current
// directory from being locked; hence not being able to remove it.
if ((chdir("/")) < 0) {
return 7;
}
// 4. Redirect standard files to /dev/null.
freopen( "/dev/null", "r", stdin);
freopen( "/dev/null", "w", stdout);
freopen( "/dev/null", "w", stderr);
}
// Run fuse.
fuse_set_signal_handlers(fuse_get_session(fuse_));
fuse_adapter->SetInterruptQueryFunction();
fuse_loop_mt(fuse_);
// Cleanup
fuse_teardown(fuse_, mount_point);
for (int i = 0; i < fuse_opts.size(); i++) {
free(fuse_opts[i]);
}
// Stop FuseAdapter.
fuse_adapter->Stop();
delete fuse_adapter;
return 0;
}