int main()

in src/s3fs.cpp [4774:5176]


int main(int argc, char* argv[])
{
    int ch;
    int fuse_res;
    int option_index = 0; 
    struct fuse_operations s3fs_oper;
    time_t incomp_abort_time = (24 * 60 * 60);
    S3fsLog singletonLog;

    static const struct option long_opts[] = {
        {"help",                 no_argument,       NULL, 'h'},
        {"version",              no_argument,       0,     0},
        {"debug",                no_argument,       NULL, 'd'},
        {"incomplete-mpu-list",  no_argument,       NULL, 'u'},
        {"incomplete-mpu-abort", optional_argument, NULL, 'a'}, // 'a' is only identifier and is not option.
        {NULL, 0, NULL, 0}
    };

    // init xml2
    xmlInitParser();
    LIBXML_TEST_VERSION

    init_sysconf_vars();

    // get program name - emulate basename
    program_name = argv[0];
    size_t found = program_name.find_last_of('/');
    if(found != std::string::npos){
        program_name.replace(0, found+1, "");
    }

    // set credential object
    //
    ps3fscred = new S3fsCred();
    if(!ps3fscred) {
      S3FS_PRN_EXIT("Failed to new S3fsCred.");
      exit(EXIT_FAILURE);
    }

    if(!S3fsCurl::InitCredentialObject(ps3fscred)){
        S3FS_PRN_EXIT("Failed to setup credential object to ossfs curl.");
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    printf("[NOTICE] OSS signature V1 service will not be available for new uids since March 1st, 2025. It is recommended to mount with OSS signature V4:\n\t ossfs [oss-bucket] [mount-path] [options] -osigv4 -oregion=[your-region-id]\n");

    while((ch = getopt_long(argc, argv, "dho:fsu", long_opts, &option_index)) != -1){
        switch(ch){
            case 0:
                if(strcmp(long_opts[option_index].name, "version") == 0){
                    show_version();
                    delete ps3fscred;
                    exit(EXIT_SUCCESS);
                }
                break;
            case 'h':
                show_help();
                delete ps3fscred;
                exit(EXIT_SUCCESS);
            case 'o':
                break;
            case 'd':
                break;
            case 'f':
                foreground = true;
                break;
            case 's':
                break;
            case 'u':   // --incomplete-mpu-list
                if(NO_UTILITY_MODE != utility_mode){
                    S3FS_PRN_EXIT("already utility mode option is specified.");
                    delete ps3fscred;
                    exit(EXIT_FAILURE);
                }
                utility_mode = INCOMP_TYPE_LIST;
                break;
            case 'a':   // --incomplete-mpu-abort
                if(NO_UTILITY_MODE != utility_mode){
                    S3FS_PRN_EXIT("already utility mode option is specified.");
                    delete ps3fscred;
                    exit(EXIT_FAILURE);
                }
                utility_mode = INCOMP_TYPE_ABORT;

                // check expire argument
                if(NULL != optarg && 0 == strcasecmp(optarg, "all")){ // all is 0s
                    incomp_abort_time = 0;
                }else if(NULL != optarg){
                    if(!convert_unixtime_from_option_arg(optarg, incomp_abort_time)){
                        S3FS_PRN_EXIT("--incomplete-mpu-abort option argument is wrong.");
                        delete ps3fscred;
                        exit(EXIT_FAILURE);
                    }
                }
                // if optarg is null, incomp_abort_time is 24H(default)
                break;
            default:
                delete ps3fscred;
                exit(EXIT_FAILURE);
        }
    }
    // print launch message
    print_launch_message(argc, argv);

    // Load SSE environment
    if(!S3fsCurl::LoadEnvSse()){
        S3FS_PRN_EXIT("something wrong about SSE environment.");
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // ssl init
    if(!s3fs_init_global_ssl()){
        S3FS_PRN_EXIT("could not initialize for ssl libraries.");
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // mutex for xml
    if(!init_parser_xml_lock()){
        S3FS_PRN_EXIT("could not initialize mutex for xml parser.");
        s3fs_destroy_global_ssl();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // init curl (without mime types)
    //
    // [NOTE]
    // The curl initialization here does not load mime types.
    // The mime types file parameter are dynamic values according
    // to the user's environment, and are analyzed by the my_fuse_opt_proc
    // function.
    // The my_fuse_opt_proc function is executed after this curl
    // initialization. Because the curl method is used in the
    // my_fuse_opt_proc function, then it must be called here to
    // initialize. Fortunately, the processing using mime types
    // is only PUT/POST processing, and it is not used until the
    // call of my_fuse_opt_proc function is completed. Therefore,
    // the mime type is loaded just after calling the my_fuse_opt_proc
    // function.
    // 
    if(!S3fsCurl::InitS3fsCurl()){
        S3FS_PRN_EXIT("Could not initiate curl library.");
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // clear this structure
    memset(&s3fs_oper, 0, sizeof(s3fs_oper));

    // This is the fuse-style parser for the arguments
    // after which the bucket name and mountpoint names
    // should have been set
    struct fuse_args custom_args = FUSE_ARGS_INIT(argc, argv);
    if(0 != fuse_opt_parse(&custom_args, NULL, NULL, my_fuse_opt_proc)){
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    if (S3fsCurl::GetSignatureType() == V4_ONLY && !is_specified_region) {
        S3FS_PRN_EXIT("Using OSSV4 signature requires specifying the region");
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // init mime types for curl
    if(!S3fsCurl::InitMimeType(mimetype_file)){
        S3FS_PRN_WARN("Missing MIME types prevents setting Content-Type on uploaded objects.");
    }

    // [NOTE]
    // exclusive option check here.
    //
    if(strcasecmp(S3fsCurl::GetStorageClass().c_str(), "REDUCED_REDUNDANCY") == 0 && !S3fsCurl::IsSseDisable()){
        S3FS_PRN_EXIT("use_sse option could not be specified with storage class reduced_redundancy.");
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }
    if(!S3fsCurl::FinalCheckSse()){
        S3FS_PRN_EXIT("something wrong about SSE options.");
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    if(S3fsCurl::GetSignatureType() == V1_ONLY && S3fsCurl::GetUnsignedPayload()){
        S3FS_PRN_WARN("Ignoring enable_unsigned_payload with sigv1");
    }

    if(!FdEntity::GetNoMixMultipart() && max_dirty_data != -1){
        S3FS_PRN_WARN("Setting max_dirty_data to -1 when nomixupload is enabled");
        max_dirty_data = -1;
    }

    //
    // Check the combination of parameters for credential
    //
    if(!ps3fscred->CheckAllParams()){
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // The second plain argument is the mountpoint
    // if the option was given, we all ready checked for a
    // readable, non-empty directory, this checks determines
    // if the mountpoint option was ever supplied
    if(NO_UTILITY_MODE == utility_mode){
        if(mountpoint.empty()){
            S3FS_PRN_EXIT("missing MOUNTPOINT argument.");
            show_usage();
            S3fsCurl::DestroyS3fsCurl();
            s3fs_destroy_global_ssl();
            destroy_parser_xml_lock();
            delete ps3fscred;
            exit(EXIT_FAILURE);
        }
    }

    // check tmp dir permission
    if(!FdManager::CheckTmpDirExist()){
        S3FS_PRN_EXIT("temporary directory doesn't exists.");
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // check cache dir permission
    if(!FdManager::CheckCacheDirExist() || !FdManager::CheckCacheTopDir() || !CacheFileStat::CheckCacheFileStatTopDir()){
        S3FS_PRN_EXIT("could not allow cache directory permission, check permission of cache directories.");
        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(EXIT_FAILURE);
    }

    // set fake free disk space
    if(-1 != fake_diskfree_size){
        FdManager::InitFakeUsedDiskSize(fake_diskfree_size);
    }

    // set user agent
    S3fsCurl::InitUserAgent();

    // There's room for more command line error checking

    // Check to see if the bucket name contains periods and https (SSL) is
    // being used. This is a known limitation:
    // https://docs.amazonwebservices.com/AmazonS3/latest/dev/
    // The Developers Guide suggests that either use HTTP of for us to write
    // our own certificate verification logic.
    // For now, this will be unsupported unless we get a request for it to
    // be supported. In that case, we have a couple of options:
    // - implement a command line option that bypasses the verify host 
    //   but doesn't bypass verifying the certificate
    // - write our own host verification (this might be complex)
    // See issue #128strncasecmp
    /* 
    if(1 == S3fsCurl::GetSslVerifyHostname()){
        found = S3fsCred::GetBucket().find_first_of('.');
        if(found != std::string::npos){
            found = s3host.find("https:");
            if(found != std::string::npos){
                S3FS_PRN_EXIT("Using https and a bucket name with periods is unsupported.");
                exit(1);
            }
        }
    }
    */

    if(NO_UTILITY_MODE != utility_mode){
        int exitcode = s3fs_utility_processing(incomp_abort_time);

        S3fsCurl::DestroyS3fsCurl();
        s3fs_destroy_global_ssl();
        destroy_parser_xml_lock();
        delete ps3fscred;
        exit(exitcode);
    }

    // Check multipart / copy api for mix multipart uploading
    if(nomultipart || nocopyapi || norenameapi){
        FdEntity::SetNoMixMultipart();
        max_dirty_data = -1;
    }

    // check free disk space
    if(!FdManager::IsSafeDiskSpace(NULL, S3fsCurl::GetMultipartSize() * S3fsCurl::GetMaxParallelCount())){
        // clean cache dir and retry
        S3FS_PRN_WARN("No enough disk space for ossfs, try to clean cache dir");
        FdManager::get()->CleanupCacheDir();
        if(!FdManager::IsSafeDiskSpaceWithLog(nullptr, S3fsCurl::GetMultipartSize() * S3fsCurl::GetMaxParallelCount())){
            S3fsCurl::DestroyS3fsCurl();
            s3fs_destroy_global_ssl();
            destroy_parser_xml_lock();
            delete ps3fscred;
            exit(EXIT_FAILURE);
        }
    }

    // check readdir_optimize 
    if(is_readdir_optimize){
        if(is_use_xattr){
            S3FS_PRN_EXIT("readdir_optimize option could not be specified with use_xattr option.");
            S3fsCurl::DestroyS3fsCurl();
            s3fs_destroy_global_ssl();
            destroy_parser_xml_lock();
            delete ps3fscred;
            exit(EXIT_FAILURE);
        }
        is_refresh_fakemeta = true;
        StatCache::getStatCacheData()->SetNoExtendedMeta(true, readdir_check_size);
        S3FS_PRN_INFO("Readdir optimize, flag(%d, %lld)", is_refresh_fakemeta, static_cast<long long int>(readdir_check_size));
    }

    // try to check s3fs service
    if (EXIT_SUCCESS != s3fs_check_service()) {
        exit(EXIT_FAILURE);
    }

    s3fs_oper.getattr     = s3fs_getattr;
    s3fs_oper.readlink    = s3fs_readlink;
    s3fs_oper.mknod       = s3fs_mknod;
    s3fs_oper.mkdir       = s3fs_mkdir;
    s3fs_oper.unlink      = s3fs_unlink;
    s3fs_oper.rmdir       = s3fs_rmdir;
    s3fs_oper.symlink     = s3fs_symlink;
    s3fs_oper.rename      = s3fs_rename;
    s3fs_oper.link        = s3fs_link;
    if(!nocopyapi){
        s3fs_oper.chmod   = s3fs_chmod;
        s3fs_oper.chown   = s3fs_chown;
        s3fs_oper.utimens = s3fs_utimens;
    }else{
        s3fs_oper.chmod   = s3fs_chmod_nocopy;
        s3fs_oper.chown   = s3fs_chown_nocopy;
        s3fs_oper.utimens = s3fs_utimens_nocopy;
    }
    s3fs_oper.truncate    = s3fs_truncate;
    s3fs_oper.open        = s3fs_open;
    s3fs_oper.read        = s3fs_read;
    s3fs_oper.write       = s3fs_write;
    s3fs_oper.statfs      = s3fs_statfs;
    s3fs_oper.flush       = s3fs_flush;
    s3fs_oper.fsync       = s3fs_fsync;
    s3fs_oper.release     = s3fs_release;
    s3fs_oper.opendir     = s3fs_opendir;
    s3fs_oper.readdir     = s3fs_readdir;
    s3fs_oper.init        = s3fs_init;
    s3fs_oper.destroy     = s3fs_destroy;
    s3fs_oper.access      = s3fs_access;
    s3fs_oper.create      = s3fs_create;
    // extended attributes
    if(is_use_xattr){
        s3fs_oper.setxattr    = s3fs_setxattr;
        s3fs_oper.getxattr    = s3fs_getxattr;
        s3fs_oper.listxattr   = s3fs_listxattr;
        s3fs_oper.removexattr = s3fs_removexattr;
    }

    s3fs_oper.flag_utime_omit_ok = true;

    // now passing things off to fuse, fuse will finish evaluating the command line args
    fuse_res = fuse_main(custom_args.argc, custom_args.argv, &s3fs_oper, NULL);
    if(fuse_res == 0){
        fuse_res = s3fs_init_deferred_exit_status;
    }
    fuse_opt_free_args(&custom_args);

    // Destroy curl
    if(!S3fsCurl::DestroyS3fsCurl()){
        S3FS_PRN_WARN("Could not release curl library.");
    }
    s3fs_destroy_global_ssl();
    destroy_parser_xml_lock();
    delete ps3fscred;

    // cleanup xml2
    xmlCleanupParser();
    S3FS_MALLOCTRIM(0);

    exit(fuse_res);
}