Exemple #1
0
/**
 *  Check that FS path is the same as the last time.
 */
int CheckLastFS(  )
{
    int            rc;
    lmgr_t         lmgr;
    char           value[1024];

    rc = ListMgr_InitAccess( &lmgr );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, "CheckFS", "Error %d connecting to database", rc );
        return rc;
    }
    rc = ListMgr_GetVar( &lmgr, FS_PATH_VAR, value );
    if ( rc == DB_SUCCESS )
    {
        if ( strcmp( value, global_config.fs_path ) )
        {
            DisplayLog( LVL_CRIT, "CheckFS",
                        "Filesystem %s does not correspond to database content (%s)",
                        global_config.fs_path, value );
            DisplayLog( LVL_CRIT, "CheckFS", "Drop the database and restart the daemon." );
            rc = -1;
        }
        else
        {
            DisplayLog( LVL_DEBUG, "CheckFS", "%s matches database content.",
                        global_config.fs_path );
            rc = 0;
        }
    }
    else if ( rc == DB_NOT_EXISTS )
    {
        DisplayLog( LVL_FULL, "CheckFS", FS_PATH_VAR "='%s'.", global_config.fs_path );
        rc = ListMgr_SetVar( &lmgr, FS_PATH_VAR, global_config.fs_path );
        if ( rc )
            DisplayLog( LVL_CRIT, "CheckFS", "Error %d setting variable 'FS_path'", rc );
    }
    else
    {
        DisplayLog( LVL_CRIT, "CheckFS", "Error %d retrieving variable 'FS_path'", rc );
    }

    ListMgr_CloseAccess( &lmgr );
    return rc;
}
Exemple #2
0
/**
 * Main daemon routine
 */
int main( int argc, char **argv )
{
    int            c = 0;
    char          *bin = basename( argv[0] );
    int            rc;
    char           err_msg[4096];
    robinhood_config_t config;
    int chgd = 0;

    /* options */
    char           config_file[MAX_OPT_LEN] = "";
    char           badcfg[RBH_PATH_MAX];
    int            force_log_level = FALSE;
    int            log_level = 0;
    int            margin = 0;
    char           output_file[MAX_OPT_LEN] = "/tmp/lov_objid";

    lmgr_t         lmgr;
    FILE         * out;

    /* parse command line options */
    while ((c = getopt(argc, argv, OPT_STRING)) != -1)
    {
        switch (c)
        {
            case 'l':
                force_log_level = TRUE;
                log_level = str2debuglevel(optarg);
                if (log_level == -1)
                {
                    fprintf( stderr,
                             "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n",
                             optarg );
                    exit(1);
                }
                break;
            case 'f':
                rh_strncpy(config_file, optarg, MAX_OPT_LEN);
                break;
            case 'o':
                rh_strncpy(output_file, optarg, MAX_OPT_LEN);
                break;
            case 'm':
                margin = str2int(optarg);
                if (margin < 0)
                {
                    fprintf( stderr,
                             "Invalid parameter '%s' for '-m' option: positive integer expected\n",
                             optarg );
                    exit(1);
                }
                break;
            case ':':
            case '?':
            default:
                display_help(bin);
                exit( 1 );
                break;
        }
    }

    /* get default config file, if not specified */
    if (SearchConfig(config_file, config_file, &chgd, badcfg, MAX_OPT_LEN) != 0)
    {
        fprintf(stderr, "No config file (or too many) found matching %s\n", badcfg);
        exit(2);
    }
    else if (chgd)
    {
        fprintf(stderr, "Using config file '%s'.\n", config_file );
    }

    /* only read ListMgr config */

    if ( ReadRobinhoodConfig( 0, config_file, err_msg, &config, FALSE ) )
    {
        fprintf( stderr, "Error reading configuration file '%s': %s\n", config_file, err_msg );
        exit( 1 );
    }
    process_config_file = config_file;

    /* set global configuration */
    global_config = config.global_config;

    if ( force_log_level )
        config.log_config.debug_level = log_level;
    else
        config.log_config.debug_level = LVL_MAJOR; /* no event message */

    /* set logging to stderr for this tool */
    strcpy( config.log_config.log_file, "stderr" );
    strcpy( config.log_config.report_file, "stderr" );
    strcpy( config.log_config.alert_file, "stderr" );

    /* Initialize logging */
    rc = InitializeLogs( bin, &config.log_config );
    if ( rc )
    {
        fprintf( stderr, "Error opening log files: rc=%d, errno=%d: %s\n",
                 rc, errno, strerror( errno ) );
        exit( rc );
    }

    /* Initialize list manager */
    rc = ListMgr_Init( &config.lmgr_config, TRUE );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, TAG, "Error %d initializing list manager", rc );
        exit( rc );
    }
    else
        DisplayLog( LVL_DEBUG, TAG, "ListManager successfully initialized" );

    if ( CheckLastFS(  ) != 0 )
        exit( 1 );

    /* Create database access */
    rc = ListMgr_InitAccess( &lmgr );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, TAG, "Error %d: cannot connect to database", rc );
        exit( rc );
    }

    out = fopen(output_file, "w");
    if (!out)
    {
        DisplayLog(LVL_CRIT, TAG, "Failed to open '%s' for writting: %s", output_file,
                   strerror(errno));
        return errno;
    }

    /* direct SQL request to retrieve the max object index from DB */
    result_handle_t res;
    /* FIXME max on the low weight 32bits of the 'objid' 64bits value */
    rc = db_exec_sql(&lmgr.conn, "SELECT ostidx, max(hex(cast(reverse(cast(details as binary(8))) as binary(4)))) "
                     "FROM "STRIPE_ITEMS_TABLE" GROUP BY ostidx ORDER BY ostidx", &res);
    if (rc)
        goto db_error;

    int index = -1;
    do
    {
        char *resstr[2];
        unsigned int ostidx;
        unsigned int objid;
        unsigned long long objid_long;
        resstr[0] = resstr[1] = NULL;

        rc = db_next_record( &lmgr.conn, &res, resstr, 2 );
        if (rc == DB_END_OF_LIST)
            break;
        else if (rc != DB_SUCCESS)
            goto db_error;

        index ++;

        if (resstr[0] == NULL || resstr[1] == NULL)
        {
            DisplayLog(LVL_MAJOR, TAG, "ERROR: got NULL record from DB at index %u", index);
            rc = EINVAL;
            goto out;
        }

        /* resstr[0] is ost_idx */
        if (sscanf(resstr[0], "%u", &ostidx) != 1)
        {
            DisplayLog(LVL_MAJOR, TAG, "ERROR: cannot parse OST index '%s' at index %u", resstr[0], index);
            rc = EINVAL;
            goto out;
        }
        else if (ostidx != index)
        {
            DisplayLog(LVL_MAJOR, TAG, "Warning: OST index %u not found in database, assuming current objid=1",
                       index);
            objid_long = 1 + margin;
            printf("ostidx=%u, max objid=%016LX\n", ostidx, objid_long);
            fwrite(&objid_long, sizeof(objid_long), 1, out);
            continue;
        }

        /* resstr[1] is objid (hexa) */
        if (sscanf(resstr[1], "%X", &objid) != 1)
        {
            DisplayLog(LVL_MAJOR, TAG, "ERROR: cannot parse objid '%s' at index %u", resstr[1], index);
            rc = EINVAL;
            goto out;
        }

        objid_long = objid + margin;
        printf("ostidx=%u, objid=%016LX\n", ostidx, objid_long);
        fwrite(&objid_long, sizeof(objid_long), 1, out);

    } while(rc == 0);

    fclose(out);
    ListMgr_CloseAccess( &lmgr );
    return 0;

db_error:
    DisplayLog( LVL_CRIT, TAG, "Database error %d\n", rc);
out:
    ListMgr_CloseAccess( &lmgr );
    return rc;
}
Exemple #3
0
/**
 * Main daemon routine
 */
int main( int argc, char **argv )
{
    int            c, option_index = 0;
    char          *bin = basename( argv[0] );

    char           config_file[MAX_OPT_LEN] = "";
    int            force_log_level = FALSE;
    int            log_level = 0;
    int            rc;
    int            chgd = 0;
    char           err_msg[4096];
    int            neg = 0;
    char           badcfg[RBH_PATH_MAX];

    /* parse command line options */
    while ((c = getopt_long_only(argc, argv, SHORT_OPT_STRING, option_tab,
                            &option_index )) != -1)
    {
        switch ( c )
        {
        case '!':
            neg = 1;
            break;
        case 'u':
            toggle_option(match_user, "user");
            prog_options.user = optarg;
            prog_options.userneg = neg;
            neg = 0;
            break;
        case 'g':
            toggle_option(match_group, "group");
            prog_options.group = optarg;
            prog_options.groupneg = neg;
            neg = 0;
            break;
        case 'U': /* match numerical (non resolved) users */
            toggle_option(match_user, "user");
            prog_options.user = "******";
            prog_options.userneg = neg;
            neg = 0;
            break;
        case 'G': /* match numerical (non resolved) groups */
            toggle_option(match_group, "group");
            prog_options.group = "[0-9]*";
            prog_options.groupneg = neg;
            neg = 0;
            break;
        case 'n':
            toggle_option(match_name, "name");
            prog_options.name = optarg;
            prog_options.nameneg = neg;
            neg = 0;
            break;
#ifdef _LUSTRE
        case 'o':
            toggle_option(match_ost, "ost");
            prog_options.ost_idx = str2int(optarg);
            if (prog_options.ost_idx == (unsigned int)-1)
            {
                fprintf(stderr, "invalid ost index '%s': unsigned integer expected\n", optarg);
                exit(1);
            }
            if (neg) {
                fprintf(stderr, "! () is not supported for ost criteria\n");
                exit(1);
            }
            break;
        case 'P':
            toggle_option(match_pool, "pool");
            prog_options.pool = optarg;
            break;
        case 'O':
            prog_options.lsost = 1;
            prog_options.print = 0;
            disp_mask |= LSOST_DISPLAY_MASK;
            if (neg) {
                fprintf(stderr, "! (-not) unexpected before -lsost option\n");
                exit(1);
            }
            break;
#endif
        case 't':
            toggle_option(match_type, "type");
            prog_options.type = opt2type(optarg);
            if (prog_options.type == NULL)
            {
                fprintf(stderr, "invalid type '%s': expected types: "TYPE_HELP".\n", optarg);
                exit(1);
            }
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for type criteria\n");
                exit(1);
            }
            break;
        case 's':
            toggle_option(match_size, "size");
            if (set_size_filter(optarg))
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for size criteria\n");
                exit(1);
            }
            break;

        case 'A':
            toggle_option(match_atime, "atime/amin");
            if (set_time_filter(optarg, 0, TRUE, atime))
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for time criteria\n");
                exit(1);
            }
            break;

        case 'a':
            toggle_option(match_atime, "atime/amin");
            if (set_time_filter(optarg, 60, TRUE, atime))
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for time criteria\n");
                exit(1);
            }
            break;

        case 'C':
            toggle_option(match_crtime, "crtime");
            if (set_time_filter(optarg, 0, TRUE, rh_crtime))
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for time criteria\n");
                exit(1);
            }
            break;

        case 'M':
            toggle_option(match_mtime, "mtime/mmin/msec");
            if (set_time_filter(optarg, 0, TRUE, mtime))
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for time criteria\n");
                exit(1);
            }
            break;

        case 'm':
            toggle_option(match_mtime, "mtime/mmin/msec");
            if (set_time_filter(optarg, 60, FALSE, mtime)) /* don't allow suffix (multiplier is 1min) */
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for time criteria\n");
                exit(1);
            }
            break;

        case 'z':
            toggle_option(match_mtime, "mtime/mmin/msec");
            if (set_time_filter(optarg, 1, FALSE, mtime)) /* don't allow suffix (multiplier is 1sec) */
                exit(1);
            if (neg) {
                fprintf(stderr, "! (-not) is not supported for time criteria\n");
                exit(1);
            }
            break;


#ifdef ATTR_INDEX_status
        case 'S':
            toggle_option(match_status, "status");
            prog_options.status = status2dbval(optarg);
            if ( prog_options.status == (file_status_t)-1 )
            {
                fprintf(stderr, "Unknown status '%s'. Allowed status: %s.\n", optarg,
                        allowed_status());
                exit(1);
            }
            prog_options.statusneg = neg;
            neg = 0;
            break;
#endif
        case 'l':
            prog_options.ls = 1;
            prog_options.print = 0;
            disp_mask |= LS_DISPLAY_MASK;
            if (neg) {
                fprintf(stderr, "! (-not) unexpected before -ls option\n");
                exit(1);
            }
            break;
        case 'p':
            prog_options.print = 1;
            disp_mask |= LS_DISPLAY_MASK;
            if (neg) {
                fprintf(stderr, "! (-not) unexpected before -ls option\n");
                exit(1);
            }
            break;

        case 'E':
            toggle_option(exec, "exec");
            prog_options.exec_cmd = optarg;
            prog_options.print = 0;
            break;
        case 'f':
            rh_strncpy(config_file, optarg, MAX_OPT_LEN);
            if (neg) {
                fprintf(stderr, "! (-not) unexpected before -f option\n");
                exit(1);
            }
            break;
        case 'd':
            force_log_level = TRUE;
            log_level = str2debuglevel( optarg );
            if ( log_level == -1 )
            {
                fprintf(stderr,
                        "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n",
                        optarg);
                exit(1);
            }
            if (neg) {
                fprintf(stderr, "! (-not) unexpected before -d option\n");
                exit(1);
            }
            break;
        case 'b':
            prog_options.bulk = force_nobulk;
            break;
        case 'h':
            display_help( bin );
            exit( 0 );
            break;
        case 'V':
            display_version( bin );
            exit( 0 );
            break;
        case ':':
        case '?':
        default:
            display_help( bin );
            exit( 1 );
            break;
        }
    }

    /* get default config file, if not specified */
    if (SearchConfig(config_file, config_file, &chgd, badcfg, MAX_OPT_LEN) != 0)
    {
        fprintf(stderr, "No config file (or too many) found matching %s\n", badcfg);
        exit(2);
    }
    else if (chgd)
    {
        fprintf(stderr, "Using config file '%s'.\n", config_file );
    }

    /* only read ListMgr config */

    if ( ReadRobinhoodConfig( 0, config_file, err_msg, &config, FALSE ) )
    {
        fprintf( stderr, "Error reading configuration file '%s': %s\n", config_file, err_msg );
        exit( 1 );
    }
    process_config_file = config_file;

    /* set global configuration */
    global_config = config.global_config;

    /* set policies info */
    policies = config.policies;

    if ( force_log_level )
        config.log_config.debug_level = log_level;
    else
        config.log_config.debug_level = LVL_MAJOR; /* no event message */

    /* Set logging to stderr */
    strcpy( config.log_config.log_file, "stderr" );
    strcpy( config.log_config.report_file, "stderr" );
    strcpy( config.log_config.alert_file, "stderr" );

    /* Initialize logging */
    rc = InitializeLogs( bin, &config.log_config );
    if ( rc )
    {
        fprintf( stderr, "Error opening log files: rc=%d, errno=%d: %s\n",
                 rc, errno, strerror( errno ) );
        exit( rc );
    }

    /* Initialize filesystem access */
    rc = InitFS();
    if (rc)
        exit(rc);

    /* Initialize list manager */
    rc = ListMgr_Init( &config.lmgr_config, TRUE );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, FIND_TAG, "Error %d initializing list manager", rc );
        exit( rc );
    }
    else
        DisplayLog( LVL_DEBUG, FIND_TAG, "ListManager successfully initialized" );

    if (CheckLastFS(  ) != 0)
        exit(1);

    /* Create database access */
    rc = ListMgr_InitAccess(&lmgr);
    if (rc)
    {
        DisplayLog( LVL_CRIT, FIND_TAG, "Error %d: cannot connect to database", rc );
        exit(rc);
    }

    if (argc == optind)
    {
        /* no argument: default is root
         * => switch to bulk mode (unless nobulk is specified)
         */
        if (prog_options.bulk != force_nobulk)
        {
            DisplayLog(LVL_DEBUG, FIND_TAG, "Optimization: switching to bulk DB request mode");
            mkfilters(FALSE); /* keep dirs */
            return list_bulk();
        }
        else
        {
            char *id = config.global_config.fs_path;
            mkfilters(TRUE); /* exclude dirs */
            /* no path specified, list all entries */
            rc = list_contents(&id, 1);
        }
    }
    else
    {
        mkfilters(TRUE); /* exclude dirs */
        rc = list_contents(argv+optind, argc-optind);
    }

    ListMgr_CloseAccess( &lmgr );

    return rc;
}
Exemple #4
0
/**
 * Main daemon routine
 */
int main(int argc, char **argv)
{
    int            c, option_index = 0;
    const char    *bin;

    char           config_file[MAX_OPT_LEN] = "";

    bool           do_start = false;
    bool           do_reset = false;
    bool           do_resume = false;
    bool           do_complete = false;
    bool           do_status = false;

    int            list_state = -1;
    int            local_flags = 0;

    int            rc;
    char           err_msg[4096];
    robinhood_config_t config;
    struct sigaction act_sigterm;
    int             chgd = 0;
    char            badcfg[RBH_PATH_MAX];

    bin = rh_basename(argv[0]); /* supports NULL argument */

    /* parse command line options */
    while ((c =
            getopt_long(argc, argv, SHORT_OPT_STRING, option_tab,
                        &option_index)) != -1) {
        switch (c) {
        case 'S':
            do_start = true;
            break;
        case 's':
            do_status = true;
            break;
        case 'Z':
            do_reset = true;
            break;
        case 'c':
            do_complete = true;
            break;
        case 'r':
            do_resume = true;
            break;
        case 'L':
            if (!strcasecmp(optarg, "all"))
                list_state = RT_ALL;
            else if (!strcasecmp(optarg, "done"))
                list_state = RT_DONE;
            else if (!strcasecmp(optarg, "failed"))
                list_state = RT_FAILED;
            else if (!strcasecmp(optarg, "todo"))
                list_state = RT_TODO;
            else {
                fprintf(stderr,
                        "Invalid parameter for option --list: all, done, failed or todo expected.\n");
                exit(1);
            }
            break;
        case 'e':
            local_flags |= RETRY_ERRORS;
            break;
        case 'y':
            local_flags |= NO_CONFIRM;
            break;
        case 'f':
            rh_strncpy(config_file, optarg, MAX_OPT_LEN);
            break;
        case 'D':
            if (!optarg) {
                fprintf(stderr,
                        "Missing mandatory argument <path> for --dir\n");
                exit(1);
            } else {
                rh_strncpy(path_buff, optarg, MAX_OPT_LEN);
                path_filter = path_buff;
            }
            break;
        case 'o':
            if (!optarg) {
                fprintf(stderr,
                        "Missing mandatory argument <ost_index> for --ost\n");
                exit(1);
            }
            /* parse it as a set */
            if (lmgr_range2list(optarg, DB_UINT, &ost_list)) {
                fprintf(stderr,
                        "Invalid value '%s' for --ost option: integer or set expected (e.g. 2 or 3,5-8,10-12).\n",
                        optarg);
                exit(1);
            }
            /* copy arg to display it */
            rh_strncpy(ost_range_str, optarg, sizeof(ost_range_str));
            break;
        case 'b':
            if (!optarg) {
                fprintf(stderr,
                        "Missing mandatory argument <date_time> for --since\n");
                exit(1);
            }
            since_time = str2date(optarg);
            if (since_time == (time_t)-1) {
                fprintf(stderr,
                        "Invalid date format: yyyymmdd[HH[MM[SS]]] expected\n");
                exit(1);
            }
            break;
        case 'l':
        {
            int log_level = str2debuglevel(optarg);

            if (log_level == -1) {
                fprintf(stderr,
                        "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n",
                        optarg);
                exit(1);
            }
            force_debug_level(log_level);
            break;
        }
        case 'h':
            display_help(bin);
            exit(0);
            break;
        case 'V':
            display_version(bin);
            exit(0);
            break;
        case ':':
        case '?':
        default:
            display_help(bin);
            exit(1);
            break;
        }
    }

    /* check there is no extra arguments */
    if (optind != argc) {
        fprintf(stderr, "Error: unexpected argument on command line: %s\n",
                argv[optind]);
        exit(1);
    }

    rc = rbh_init_internals();
    if (rc != 0)
        exit(rc);

    /* get default config file, if not specified */
    if (SearchConfig(config_file, config_file, &chgd, badcfg,
                     MAX_OPT_LEN) != 0) {
        fprintf(stderr, "No config file (or too many) found matching %s\n",
                badcfg);
        exit(2);
    } else if (chgd) {
        fprintf(stderr, "Using config file '%s'.\n", config_file);
    }

    /* only read ListMgr config */

    if (ReadRobinhoodConfig(0, config_file, err_msg, &config, false)) {
        fprintf(stderr, "Error reading configuration file '%s': %s\n",
                config_file, err_msg);
        exit(1);
    }

    /* XXX HOOK: Set logging to stderr */
    strcpy(config.log_config.log_file, "stderr");
    strcpy(config.log_config.report_file, "stderr");
    strcpy(config.log_config.alert_file, "stderr");

    /* Initialize logging */
    rc = InitializeLogs(bin, &config.log_config);
    if (rc) {
        fprintf(stderr, "Error opening log files: rc=%d, errno=%d: %s\n",
                rc, errno, strerror(errno));
        exit(rc);
    }

    /* Initialize filesystem access */
    rc = InitFS();
    if (rc)
        exit(rc);

    /* Initialize status managers (XXX all or just the one used for
     * recovery?) */
    rc = smi_init_all(options.flags);
    if (rc)
        exit(rc);

    /* Initialize list manager */
    rc = ListMgr_Init(0);
    if (rc) {
        DisplayLog(LVL_CRIT, RECOV_TAG,
                   "Error initializing list manager: %s (%d)", lmgr_err2str(rc),
                   rc);
        exit(rc);
    } else
        DisplayLog(LVL_DEBUG, RECOV_TAG,
                   "ListManager successfully initialized");

    if (CheckLastFS() != 0)
        exit(1);

    /* Create database access */
    rc = ListMgr_InitAccess(&lmgr);
    if (rc) {
        DisplayLog(LVL_CRIT, RECOV_TAG, "Error %d: cannot connect to database",
                   rc);
        exit(rc);
    }
#ifdef _HSM_LITE
    rc = Backend_Start(&config.backend_config, 0);
    if (rc) {
        DisplayLog(LVL_CRIT, RECOV_TAG, "Error initializing backend");
        exit(1);
    }
#endif

    /* create signal handlers */
    memset(&act_sigterm, 0, sizeof(act_sigterm));
    act_sigterm.sa_flags = 0;
    act_sigterm.sa_handler = terminate_handler;
    if (sigaction(SIGTERM, &act_sigterm, NULL) == -1
        || sigaction(SIGINT, &act_sigterm, NULL) == -1) {
        DisplayLog(LVL_CRIT, RECOV_TAG,
                   "Error while setting signal handlers for SIGTERM and SIGINT: %s",
                   strerror(errno));
        exit(1);
    } else
        DisplayLog(LVL_VERB, RECOV_TAG,
                   "Signals SIGTERM and SIGINT (abort command) are ready to be used");

    if (do_status)
        rc = recov_status();
    else if (list_state != -1)
        rc = recov_list(list_state);
    else if (do_start)
        rc = recov_start();
    else if (do_reset)
        rc = recov_reset(local_flags & NO_CONFIRM);
    else if (do_resume)
        rc = recov_resume(local_flags & RETRY_ERRORS);
    else if (do_complete)
        rc = recov_complete();
    else {
        display_help(bin);
        rc = 1;
    }

    ListMgr_CloseAccess(&lmgr);

    return rc;
}
Exemple #5
0
/**
 * Main daemon routine
 */
int main( int argc, char **argv )
{
    int            c, option_index = 0;
    char          *bin = basename( argv[0] );

    char           config_file[MAX_OPT_LEN] = "";

    enum { ACTION_NONE, ACTION_LIST, ACTION_RESTORE } action = ACTION_NONE;
    int            force_log_level = FALSE;
    int            log_level = 0;

    int            rc;
    char           err_msg[4096];
    robinhood_config_t config;
    int chgd = 0;
    char    badcfg[RBH_PATH_MAX];

    /* parse command line options */
    while ( ( c = getopt_long( argc, argv, SHORT_OPT_STRING, option_tab,
                               &option_index ) ) != -1 )
    {
        switch ( c )
        {
        case 'L':
            if ( (action != ACTION_NONE) && (action != ACTION_LIST) )
                fprintf( stderr, "WARNING: only a single action (--list or --restore) is expected\n"
                                 "on command line. '--restore' will be ignored.\n" );
            action = ACTION_LIST;
            break;
        case 'R':
            if ( (action != ACTION_NONE) && (action != ACTION_RESTORE) )
                fprintf( stderr, "WARNING: only a single action (--list or --restore) is expected\n"
                                 "on command line. '--list' will be ignored.\n" );
            action = ACTION_RESTORE;
            break;
        case 'f':
            strncpy( config_file, optarg, MAX_OPT_LEN );
            break;
        case 'l':
            force_log_level = TRUE;
            log_level = str2debuglevel( optarg );
            if ( log_level == -1 )
            {
                fprintf( stderr,
                         "Unsupported log level '%s'. CRIT, MAJOR, EVENT, VERB, DEBUG or FULL expected.\n",
                         optarg );
                exit( 1 );
            }
            break;
        case 'h':
            display_help( bin );
            exit( 0 );
            break;
        case 'V':
            display_version( bin );
            exit( 0 );
            break;
        case ':':
        case '?':
        default:
            display_help( bin );
            exit( 1 );
            break;
        }
    }

    /* 1 expected argument: path */
    if ( optind != argc - 1 )
    {
        fprintf( stderr, "Error: missing mandatory argument on command line: <path|fid>\n" );
        exit( 1 );
    }
    strncpy( path_filter, argv[optind], RBH_PATH_MAX );

    /* get default config file, if not specified */
    if ( SearchConfig( config_file, config_file, &chgd, badcfg ) != 0 )
    {
        fprintf(stderr, "No config file found matching %s\n", badcfg);
        exit(2);
    }
    else if (chgd)
    {
        fprintf(stderr, "Using config file '%s'.\n", config_file );
    }

    /* only read ListMgr config */
    if ( ReadRobinhoodConfig( 0, config_file, err_msg, &config, FALSE ) )
    {
        fprintf( stderr, "Error reading configuration file '%s': %s\n", config_file, err_msg );
        exit( 1 );
    }
    process_config_file = config_file;

    /* set global configuration */
    global_config = config.global_config;

    /* set policies info */
    policies = config.policies;

    if ( force_log_level )
        config.log_config.debug_level = log_level;

    /* XXX HOOK: Set logging to stderr */
    strcpy( config.log_config.log_file, "stderr" );
    strcpy( config.log_config.report_file, "stderr" );
    strcpy( config.log_config.alert_file, "stderr" );

    /* Initialize logging */
    rc = InitializeLogs( bin, &config.log_config );
    if ( rc )
    {
        fprintf( stderr, "Error opening log files: rc=%d, errno=%d: %s\n",
                 rc, errno, strerror( errno ) );
        exit( rc );
    }

    /* Initialize Filesystem access */
    rc = InitFS();
    if (rc)
        exit(rc);

    /* Initialize list manager */
    rc = ListMgr_Init( &config.lmgr_config, FALSE );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, LOGTAG, "Error %d initializing list manager", rc );
        exit( rc );
    }
    else
        DisplayLog( LVL_DEBUG, LOGTAG, "ListManager successfully initialized" );

    if ( CheckLastFS(  ) != 0 )
        exit( 1 );

    /* Create database access */
    rc = ListMgr_InitAccess( &lmgr );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, LOGTAG, "Error %d: cannot connect to database", rc );
        exit( rc );
    }

#ifdef _HSM_LITE
    rc = Backend_Start( &config.backend_config, 0 );
    if ( rc )
    {
        DisplayLog( LVL_CRIT, LOGTAG, "Error initializing backend" );
        exit( 1 );
    }
#endif

    /* perform the action */
    switch( action )
    {
        case ACTION_LIST:
            rc= list_rm();
            break;
        case ACTION_RESTORE:
            rc = undo_rm();
            break;
        case ACTION_NONE:
            display_help( bin );
            rc = 1;
            break;
        default:
            fprintf(stderr, "Unexpected action (action code=%#x)\n", action );
            display_help( bin );
            rc = EINVAL;
            break;
    }

    ListMgr_CloseAccess( &lmgr );

    return rc;

}