diff --git a/configure.ac b/configure.ac index 9448bd6da..29a029fa3 100644 --- a/configure.ac +++ b/configure.ac @@ -113,6 +113,7 @@ CFLAGS="$CFLAGS $GLIB2_CFLAGS $GTHREAD2_CFLAGS" LDFLAGS="$LDFLAGS $GLIB2_LIBS $GTHREAD2_LIBS" # debug flags + AX_ENABLE_FLAG([debug-db], [enables debug traces for database operations], [-D_DEBUG_DB]) AX_ENABLE_FLAG([debug-parsing], [enables debug traces for configuration file parsing], [-D_DEBUG_PARSING]) AM_CONDITIONAL(DEBUG_PARSING, test "x$enable_debug_parsing" == "xyes" ) @@ -147,6 +148,7 @@ build_lustre="OFF" build_backup="OFF" build_lhsm="OFF" build_shook="OFF" +build_panfs="OFF" AC_ARG_ENABLE([lustre], AS_HELP_STRING([--disable-lustre], [Disable all lustre specific features]), @@ -154,10 +156,23 @@ AC_ARG_ENABLE([lustre], AS_HELP_STRING([--disable-lustre], AC_ARG_ENABLE([shook], AS_HELP_STRING([--disable-shook], [Disable build of shook specific modules]), [support_shook="$enableval"],[support_shook="yes"]) +AC_ARG_ENABLE([panfs], AS_HELP_STRING([--enable-panfs], + [enable PanFS-specific features]), + [support_panfs="yes"],[support_panfs="no"]) # default input option is --scan INPUT_OPT="--scan" +# Panasas File System +if test "x$support_panfs" = "xyes" ; then + AC_DEFINE(_PANFS, 1, [panfs is available]) + AM_CONDITIONAL( PANFS, test "x$support_panfs" = "xyes" ) + AC_SUBST(PANFS) + build_panfs="ON" +else + AM_CONDITIONAL(PANFS, test 0 = 1 ) +fi + # shook requires Lustre + FID support + shook library # hsm_lite requires Lustre + FID support # lustre_hsm requires Lustre >= 2.5 @@ -490,6 +505,7 @@ AC_SUBST(ac_configure_args) AC_OUTPUT AC_MSG_NOTICE([Summary:]) +AC_MSG_NOTICE([PanFS support is $build_panfs]) AC_MSG_NOTICE([Lustre support is $build_lustre]) AC_MSG_NOTICE([Backup support is $build_backup]) AC_MSG_NOTICE([Lustre/HSM support is $build_lhsm]) diff --git a/src/cfg_parsing/rbh_cfg.c b/src/cfg_parsing/rbh_cfg.c index e38ec65ef..7a5d645f2 100644 --- a/src/cfg_parsing/rbh_cfg.c +++ b/src/cfg_parsing/rbh_cfg.c @@ -33,6 +33,7 @@ #include "policy_rules.h" #include "policy_run.h" #include "status_manager.h" +#include "panfs_config.h" char config_file[RBH_PATH_MAX] = ""; @@ -43,6 +44,9 @@ struct mod_cfgs { {&global_cfg_hdlr, MODULE_MASK_ALWAYS}, {&log_cfg_hdlr, MODULE_MASK_ALWAYS}, {&updt_params_hdlr, MODULE_MASK_ALWAYS}, +#ifdef _PANFS + {&panfs_cfg_hdlr, MODULE_MASK_ALWAYS}, +#endif {&lmgr_cfg_hdlr, MODULE_MASK_ALWAYS}, {&entry_proc_cfg_hdlr, MODULE_MASK_ENTRY_PROCESSOR}, {&fs_scan_cfg_hdlr, MODULE_MASK_FS_SCAN}, @@ -144,7 +148,7 @@ static int rbh_cfg_read_set(int module_mask, char *file_path, char *err_msg_out, /* just free the top level handler */ free(cfg); } - + config_free: /* free config file resources */ rh_config_Free(syntax_tree); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 5b8233501..750f5958c 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -6,6 +6,9 @@ noinst_LTLIBRARIES=libcommontools.la if LUSTRE FS_SRC=lustre_tools.c endif +if PANFS +FS_SRC=panfs_config.c +endif if MNTENTCOMPAT COMPAT_SRC=mntent_compat.c mntent_compat.h endif diff --git a/src/common/panfs_config.c b/src/common/panfs_config.c new file mode 100644 index 000000000..11aa3de7c --- /dev/null +++ b/src/common/panfs_config.c @@ -0,0 +1,179 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=4:tabstop=4: + */ +/* + * Copyright (C) 2008, 2009 CEA/DAM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the CeCILL License. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license (http://www.cecill.info) and that you + * accept its terms. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "panfs_config.h" +#include "rbh_cfg_helpers.h" +#include "rbh_misc.h" +#include "rbh_logs.h" +#include + +#define PANFS_CONFIG_BLOCK "Panasas" + +/* exported variable available to all modules */ +panfs_config_t panfs_config; + +static void panfs_cfg_set_default(void *module_config) +{ + panfs_config_t *conf = (panfs_config_t *)module_config; + rh_strncpy(conf->snap_delta_path, "", RBH_PATH_MAX); + rh_strncpy(conf->snap_delta_results_path, "", RBH_PATH_MAX); + rh_strncpy(conf->volume, "", FILENAME_MAX); + conf->update_interval = 600;//10 min +} + +static void panfs_cfg_write_default(FILE *output) +{ + print_begin_block(output, 0, PANFS_CONFIG_BLOCK, NULL); + print_line(output, 1, "snap_delta_path : PATH"); + print_line(output, 1, "snap_delta_results_path : PATH"); + print_line(output, 1, "volume : volumeName"); + print_line(output, 1, "# Interval for updating database"); + print_line(output, 1, "update_interval = 10min ;"); + fprintf(output, "\n"); + print_end_block(output, 0); +} + +static int panfs_cfg_read(config_file_t config, void *module_config, + char *msg_out) +{ + panfs_config_t *conf = (panfs_config_t *)module_config; + config_item_t panfs_block; + int rc; + + static const char * const allowed_params[] = { + "snap_delta_path", "snap_delta_results_path", "volume", "update_interval", NULL + }; + const cfg_param_t cfg_params[] = { + {"snap_delta_path", PT_STRING, PFLG_MANDATORY | + PFLG_REMOVE_FINAL_SLASH | PFLG_NO_WILDCARDS, conf->snap_delta_path, + sizeof(conf->snap_delta_path)} + , + {"snap_delta_results_path", PT_STRING, PFLG_MANDATORY | + PFLG_REMOVE_FINAL_SLASH | PFLG_NO_WILDCARDS, conf->snap_delta_results_path, + sizeof(conf->snap_delta_results_path)} + , + {"volume", PT_STRING, + PFLG_MANDATORY | + PFLG_NO_WILDCARDS, conf->volume, sizeof(conf->volume)} + , + {"update_interval", PT_DURATION, PFLG_POSITIVE | PFLG_NOT_NULL, + &conf->update_interval, 0} + , + + END_OF_PARAMS + }; + + /* get PANASAS block */ + rc = get_cfg_block(config, PANFS_CONFIG_BLOCK, &panfs_block, msg_out); + if (rc) + return rc; + + /* retrieve std parameters */ + rc = read_scalar_params(panfs_block, PANFS_CONFIG_BLOCK, cfg_params, + msg_out); + if (rc) + return rc; + + /* check unknown parameters */ + CheckUnknownParameters(panfs_block, PANFS_CONFIG_BLOCK, allowed_params); + + return 0; +} + +static int panfs_cfg_set(void *module_config, bool reload) +{ + panfs_config_t *conf = (panfs_config_t *) module_config; + + if (!reload) { + /* copy the whole structure content */ + panfs_config = *conf; + return 0; + } + + if (strcmp(conf->snap_delta_path, panfs_config.snap_delta_path)){ + DisplayLog(LVL_MAJOR, "PanasasConfig", + PANFS_CONFIG_BLOCK + "::Path to pan_snap_delta updated"); + strcpy(panfs_config.snap_delta_path,conf->snap_delta_path); + + } + if (strcmp(conf->snap_delta_results_path, panfs_config.snap_delta_results_path)){ + DisplayLog(LVL_MAJOR, "PanasasConfig", + PANFS_CONFIG_BLOCK + "::Path to pan_snap_delta results updated"); + strcpy(panfs_config.snap_delta_results_path,conf->snap_delta_results_path); + + } + if (strcmp(conf->volume, panfs_config.volume)){ + DisplayLog(LVL_MAJOR, "PanasasConfig", + PANFS_CONFIG_BLOCK + "::Volume's name changed in config file, but cannot be modified dynamically. If you need to change it, drop the database and run it one more time."); + exit(1); + } + if (panfs_config.update_interval != conf->update_interval) { + DisplayLog(LVL_MAJOR, "PanasasConfig", + PANFS_CONFIG_BLOCK "::update_interval modified: " + "'%" PRI_TT "'->'%" PRI_TT "'", + panfs_config.update_interval, conf->update_interval); + panfs_config.update_interval = conf->update_interval; + } + return 0; +} + +static void panfs_cfg_write_template(FILE *output) +{ + print_begin_block(output, 0, PANFS_CONFIG_BLOCK, NULL); + print_line(output, 1, + "# Path to pan_snap_delta binary"); + print_line(output, 1, "snap_delta_path = \"/panfs/\" ;"); + fprintf(output, "\n"); + print_line(output, 1, + "# Path to pan_snap_delta results"); + print_line(output, 1, "snap_delta_results_path = \"/tmp/\" ;"); + fprintf(output, "\n"); + print_line(output, 1, "# Name of the volume"); + print_line(output, 1, "volume = home;"); + fprintf(output, "\n"); + print_line(output, 1, + "# Time between checks to see if there are newer snapshots to process"); + + print_line(output, 1, " update_interval=10m;"); + print_end_block(output, 0); +} + +static void *panfs_cfg_new(void) +{ + return calloc(1, sizeof(panfs_config_t)); +} + +static void panfs_cfg_free(void *cfg) +{ + if (cfg != NULL) + free(cfg); +} + +/** structure with config handling functions */ +mod_cfg_funcs_t panfs_cfg_hdlr = { + .module_name = "panasas", + .new = panfs_cfg_new, + .free = panfs_cfg_free, + .set_default = panfs_cfg_set_default, + .read = panfs_cfg_read, + .set_config = panfs_cfg_set, + .write_default = panfs_cfg_write_default, + .write_template = panfs_cfg_write_template +}; diff --git a/src/common/rbh_misc.c b/src/common/rbh_misc.c index 80da85a22..f1d8b212e 100644 --- a/src/common/rbh_misc.c +++ b/src/common/rbh_misc.c @@ -39,6 +39,15 @@ #include #include +#ifdef _PANFS +#include +#include +#include +#include /* for gettimeofday */ +#include +#include +#endif + #ifndef HAVE_GETMNTENT_R #include "mntent_compat.h" #else @@ -2174,11 +2183,42 @@ int path2id(const char *path, entry_id_t *id, const struct stat *st) path, strerror(-rc)); return rc; } +#ifdef _PANFS st = &stn; + ssize_t vallentmp; + char *valtmp; + char *key; + vallentmp = lgetxattr(path, "system.panfs.obj_id", NULL, 0); + if (vallentmp == -1){ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. lgetxattr doesn't return any size for path %s. Error number = %d.\n",path,errno); + exit(1); + } + else if (vallentmp > 0) { + valtmp = malloc(vallentmp + 1); + if(valtmp!=NULL){ + vallentmp = lgetxattr(path, "system.panfs.obj_id", valtmp, vallentmp); + valtmp[vallentmp] = 0; + key=strchr(valtmp, 'U')+1; + free(valtmp); + id->inode =strtoull(key,&key,16); + id->fs_key = get_fskey(); + } + else{ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. Out of space.\n"); + exit(1); + } + } + else if (vallentmp == 0){ + DisplayLog(LVL_MAJOR, "StatgetxattrErr","Fatal Error. No value for size of lgetxattr."); + exit(1); + } +#endif + } + else{ + /* build id from dev/inode */ + id->inode = st->st_ino; + id->fs_key = get_fskey(); } - /* build id from dev/inode */ - id->inode = st->st_ino; - id->fs_key = get_fskey(); #endif return 0; } diff --git a/src/fs_scan/fs_scan.c b/src/fs_scan/fs_scan.c index dab7f31e4..7363e27bc 100644 --- a/src/fs_scan/fs_scan.c +++ b/src/fs_scan/fs_scan.c @@ -45,6 +45,10 @@ #include #include +#ifdef _PANFS +#include +#include +#endif fs_scan_config_t fs_scan_config; run_flags_t fsscan_flags = 0; const char *partial_scan_root = NULL; @@ -464,10 +468,12 @@ static int TerminateScan(int scan_complete, time_t end) g_strfreev(cmd); } } - +#ifdef _PANFS + signal_scan_finished(); +#else if (fsscan_once) signal_scan_finished(); - +#endif FlushLogs(); return 0; @@ -795,6 +801,35 @@ static int stat_entry(const char *path, const char *name, int parentfd, if (parentfd != -1) { if (fstatat(parentfd, name, inode, AT_SYMLINK_NOFOLLOW) == -1) return -errno; +#ifdef _PANFS + ssize_t vallentmp; + char *valtmp; + char *key; + + vallentmp = lgetxattr(path, "system.panfs.obj_id", NULL, 0); + if (vallentmp == -1){ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. lgetxattr doesn't return any size for path %s. Error number = %d.\n",path,errno); + exit(1); + } + else if (vallentmp > 0) { + valtmp = malloc(vallentmp + 1); + if(valtmp!=NULL){ + vallentmp = lgetxattr(path, "system.panfs.obj_id", valtmp, vallentmp); + valtmp[vallentmp] = 0; + key=strchr(valtmp, 'U')+1; + free(valtmp); + } + else{ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. Out of space.\n"); + exit(1); + } + } + else if (vallentmp == 0){ + DisplayLog(LVL_MAJOR, "StatgetxattrErr","Fatal Error. No value for size of lgetxattr."); + exit(1); + } + inode->st_ino=strtoull(key,&key,16); +#endif } else #endif #if defined(_LUSTRE) && defined(_MDS_STAT_SUPPORT) @@ -810,6 +845,37 @@ static int stat_entry(const char *path, const char *name, int parentfd, if (lstat(path, inode) == -1) return -errno; +#ifdef _PANFS + else{ + ssize_t vallentmp; + char *valtmp; + char *key; + + vallentmp = lgetxattr(path, "system.panfs.obj_id", NULL, 0); + if (vallentmp == -1){ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. lgetxattr doesn't return any size for path %s. Error number = %d.\n",path,errno); + exit(1); + } + else if (vallentmp > 0) { + valtmp = malloc(vallentmp + 1); + if(valtmp!=NULL){ + vallentmp = lgetxattr(path, "system.panfs.obj_id", valtmp, vallentmp); + valtmp[vallentmp] = 0; + key=strchr(valtmp, 'U')+1; + free(valtmp); + inode->st_ino=strtoull(key,&key,16); + } + else{ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. Out of space.\n"); + exit(1); + } + } + else{ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. Out of space.\n"); + exit(1); + } + } +#endif return 0; } @@ -1207,6 +1273,36 @@ static int push_dir_list(robinhood_task_t *parent_task) return rc; } +#ifdef _PANFS + size_t vallentmp; + char *valtmp; + char *key; + + vallentmp = lgetxattr(new_task_path, "system.panfs.obj_id", NULL, 0); + if (vallentmp == -1){ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. lgetxattr doesn't return any size for path %s. Error number = %d.\n" + ,new_task_path,errno); + exit(1); + } + else if (vallentmp > 0) { + valtmp = malloc(vallentmp + 1); + if(valtmp!=NULL){ + vallentmp = lgetxattr(new_task_path, "system.panfs.obj_id", valtmp, vallentmp); + valtmp[vallentmp] = 0; + key=strchr(valtmp, 'U')+1; + free(valtmp); + inode.st_ino =strtoull(key,&key,16); + } + else{ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. Out of space.\n"); + exit(1); + } + } + else if (vallentmp == 0){ + DisplayLog(LVL_MAJOR, "StatgetxattrErr","Fatal Error. No value for size of lgetxattr."); + exit(1); + } +#endif DisplayLog(LVL_FULL, FSSCAN_TAG, "Pushing dir '%s' to reach " "sub-tree '%s'", new_task_path, fs_scan_config.dir_list[i]); @@ -1246,6 +1342,36 @@ static int process_one_task(robinhood_task_t *p_task, "Error accessing filesystem: exiting"); Exit(1); } +#ifdef _PANFS + ssize_t vallentmp; + char *valtmp; + char *key; + + vallentmp = lgetxattr(p_task->path, "system.panfs.obj_id", NULL, 0); + if (vallentmp == -1){ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. lgetxattr doesn't return any size for path %s. Error number = %d.\n" + ,p_task->path,errno); + exit(1); + } + else if (vallentmp > 0) { + valtmp = malloc(vallentmp + 1); + if(valtmp!=NULL){ + vallentmp = lgetxattr(p_task->path, "system.panfs.obj_id", valtmp, vallentmp); + valtmp[vallentmp] = 0; + key=strchr(valtmp, 'U')+1; + free(valtmp); + p_task->dir_md.st_ino=strtoull(key,&key,16); + } + else{ + DisplayLog(LVL_CRIT, "StatGetxattrErr","Fatal Error. Out of space.\n"); + exit(1); + } + } + else if (vallentmp == 0){ + DisplayLog(LVL_MAJOR, "StatgetxattrErr","Fatal Error. No value for size of lgetxattr."); + exit(1); + } +#endif if (check_entry_dev(p_task->dir_md.st_dev, &fsdev, p_task->path, true)) p_task->dir_md.st_dev = fsdev; /* just updated */ diff --git a/src/fs_scan/fs_scan_main.c b/src/fs_scan/fs_scan_main.c index 9e75ea2f9..328a322ac 100644 --- a/src/fs_scan/fs_scan_main.c +++ b/src/fs_scan/fs_scan_main.c @@ -39,6 +39,14 @@ static void *scan_starter(void *arg) DisplayLog(LVL_VERB, FSSCAN_TAG, "Launching FS Scan starter thread"); +#ifdef _PANFS + rc = Robinhood_CheckScanDeadlines(); + if (rc) + DisplayLog(LVL_CRIT, FSSCAN_TAG, "Error %d checking FS Scan status", + rc); + pthread_exit(NULL); + return NULL; +#else if (fsscan_flags & RUNFLG_ONCE) { rc = Robinhood_CheckScanDeadlines(); if (rc) @@ -59,6 +67,7 @@ static void *scan_starter(void *arg) rh_sleep(fs_scan_config.spooler_check_interval); } +#endif return NULL; } diff --git a/src/include/list_mgr.h b/src/include/list_mgr.h index 68c9e1067..66e2983c8 100644 --- a/src/include/list_mgr.h +++ b/src/include/list_mgr.h @@ -1074,6 +1074,10 @@ void ListMgr_CloseProfile(struct lmgr_profile_t *p_iter); // Scan statistics #define LAST_SCAN_START_TIME "LastScanStartTime" +#ifdef _PANFS +#define SNAPSHOT_PATH "SnapPath" +#define SNAPSHOT_DONE "SnapDone" +#endif #define LAST_SCAN_END_TIME "LastScanEndTime" #define LAST_SCAN_PROCESSING_END_TIME "LastScanProcessingEndTime" #define LAST_SCAN_STATUS "LastScanStatus" diff --git a/src/include/panfs_config.h b/src/include/panfs_config.h new file mode 100644 index 000000000..69635967c --- /dev/null +++ b/src/include/panfs_config.h @@ -0,0 +1,47 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=4:tabstop=4: + */ +/* + * Copyright (C) 2008, 2009 CEA/DAM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the CeCILL License. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license (http://www.cecill.info) and that you + * accept its terms. + */ + +/** + * \file panfs_config.h + * \brief Panasas configuration parameters + */ +#ifndef _PANFS_CFG_H +#define _PANFS_CFG_H + +#include "config_parsing.h" +#include "rbh_cfg.h" +#include "rbh_const.h" +#include /* for RBH_PATH_MAX */ +#include +#include + +/** + * General Panasas configuration + */ +typedef struct panfs_config_t { + /* filesystem description */ + char snap_delta_path[RBH_PATH_MAX]; + char snap_delta_results_path[RBH_PATH_MAX]; + char volume[FILENAME_MAX]; + time_t update_interval; + +} panfs_config_t; + +/** panasas config structure available to all modules */ +extern panfs_config_t panfs_config; + +/** handlers for panasas config */ +extern mod_cfg_funcs_t panfs_cfg_hdlr; + +#endif diff --git a/src/robinhood/rbh_daemon.c b/src/robinhood/rbh_daemon.c index 2ec3af65c..f8cbc9032 100644 --- a/src/robinhood/rbh_daemon.c +++ b/src/robinhood/rbh_daemon.c @@ -41,6 +41,27 @@ #include /* for open flags */ #include +#ifdef _PANFS +#include "../list_mgr/database.h" +#include "global_config.h" +#include "panfs_config.h" +#include "rbh_misc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + #ifdef _LUSTRE #include "lustre_extended_types.h" #endif @@ -190,7 +211,11 @@ static struct option option_tab[] = { {NULL, 0, NULL, 0} }; -#define SHORT_OPT_STRING "SrCt:IOdf:T:DL:l:hVp:F" +#ifdef _PANFS + #define SHORT_OPT_STRING "SrCt:IOdf:T:DL:l:hVp:FU:" +#else + #define SHORT_OPT_STRING "SrCt:IOdf:T:DL:l:hVp:F:" +#endif #define SHORT_OPT_DEPRECATED "PMRi" #define MAX_OPT_LEN 1024 @@ -216,6 +241,10 @@ typedef struct rbh_options { int mdtidx; enum lmgr_init_flags db_flags; +#ifdef _PANFS + char firstSnapshot[MAX_OPT_LEN]; + bool Pan_FTW; +#endif } rbh_options; #define TGT_NOT_SET -1.0 @@ -355,6 +384,12 @@ static const char *misc_help = " " _B "-p" B_ " " _U "pidfile" U_ ", " _B "--pid-file=" B_ _U "pidfile" U_ "\n" " Pid file (used for service management).\n"; +#ifdef _PANFS +static const char *panfs_help = + _B "Panasas options:" B_ "\n" + " " _B "-U" B_ " " _U "Snapshot_Name" U_", " _B "--snap-name=" B_ _U "snapshot" U_ "\n" + " If this is the first run you should pass the name of first snapshot\n"; +#endif static inline void display_help(const char *bin_name) { printf(cmd_help, bin_name); @@ -366,6 +401,9 @@ static inline void display_help(const char *bin_name) printf("%s\n", behavior_help); printf("%s\n", config_help); printf("%s\n", log_help); +#ifdef _PANFS + printf("%s\n", panfs_help); +#endif printf("%s", misc_help); } @@ -1096,6 +1134,12 @@ static int rh_read_parameters(const char *bin, int argc, char **argv, opt->pid_file = true; rh_strncpy(opt->pid_filepath, optarg, MAX_OPT_LEN); break; +#ifdef _PANFS + case 'U': + rh_strncpy(opt->firstSnapshot, optarg, sizeof(opt->firstSnapshot)); + fprintf(stderr,"firstsnapshot= '%s'.\n",optarg); + break; +#endif case 'h': display_help(bin); return -1; @@ -1556,10 +1600,639 @@ static int parse_policy_runs(run_item_t **runs, unsigned int *count, return 0; } - +#ifdef _PANFS /** - * Main daemon routine + * Update Functions for Panasas File System + * */ +int cntInsEnt=0,cntDelEnt=0,cntInsSym=0,cntDelSym=0; +GString *delEnt= NULL,*delNames=NULL,*delSym=NULL; +GString *insEnt= NULL,*insNames=NULL,*insSym=NULL,*panSnap=NULL; +lmgr_t lmgr_test; +bool sp=false; +#define MAXDEL 1000 +#define MAXINS 3000 + + + +/** + * Function for generating MySQL delete commands for removing the deleted files from DB. + * The number of deletion in each command can be altered by changing MAXDEL. + * If the deletion string is equal to NULL, it will create a delete statement("Delete from ..."), and then append the needed attributes to the statement. + * If the number of attributes in our command is equal to MAXDEL, it will execute this command on the DB and after that it will free the delete statement. +*/ +static void DeleteMySQL(struct stat inode,char *Name,ino_t PID,bool isSym) +{ + if(cntDelEnt==0 && isSym){ + delSym=g_string_new("DELETE FROM ANNEX_INFO WHERE (id) IN ("); + g_string_append_printf(delSym,"('%lX:%lX')", get_fskey(),inode.st_ino); + cntDelSym++; + } + else if(cntDelEnt!=MAXDEL && cntDelSym && isSym){ + g_string_append_printf(delSym,",('%lX:%lX')", get_fskey(),inode.st_ino); + cntDelSym++; + } + else if(cntDelEnt!=MAXDEL && isSym){ + delSym=g_string_new("DELETE FROM ANNEX_INFO WHERE (id) IN ("); + g_string_append_printf(delSym,"('%lX:%lX')", get_fskey(),inode.st_ino); + cntDelSym++; + } + + if(cntDelEnt==0){ + delEnt=g_string_new("DELETE FROM ENTRIES WHERE (id) IN ("); + delNames=g_string_new("DELETE FROM NAMES WHERE (pkn) IN ("); + g_string_append_printf(delEnt, "('%lX:%lX')", get_fskey(),inode.st_ino); + g_string_append_printf(delNames,"(sha1(\"%lX:%lX/%s\"))", get_fskey(),PID,Name); + cntDelEnt++; + } + else if(cntDelEnt!=MAXDEL){ + g_string_append_printf(delEnt, ",('%lX:%lX')", get_fskey(),inode.st_ino); + g_string_append_printf(delNames,",(sha1(\"%lX:%lX/%s\"))", get_fskey(),PID,Name); + cntDelEnt++; + } + else{ + g_string_append_printf(delEnt, ",('%lX:%lX'));\n", get_fskey(),inode.st_ino); + g_string_append_printf(delNames,",(sha1(\"%lX:%lX/%s\")));\n", get_fskey(),PID,Name); + db_exec_sql(&lmgr_test.conn, delEnt->str, NULL); + db_exec_sql(&lmgr_test.conn, delNames->str, NULL); + cntDelEnt=0; + if(isSym && cntDelSym){ + g_string_append_printf(delSym,",('%lX:%lX'));\n", get_fskey(),inode.st_ino); + db_exec_sql(&lmgr_test.conn, delSym->str, NULL); + cntDelSym=0; + g_string_free(delSym, TRUE); + } + else if(isSym){ + delSym=g_string_new("DELETE FROM ANNEX_INFO WHERE (id) IN ("); + g_string_append_printf(delSym,"('%lX:%lX'));\n", get_fskey(),inode.st_ino); + db_exec_sql(&lmgr_test.conn, delSym->str, NULL); + g_string_free(delSym, TRUE); + } + else if(cntDelSym){ + g_string_append_printf(delSym,");\n"); + db_exec_sql(&lmgr_test.conn, delSym->str, NULL); + cntDelSym=0; + g_string_free(delSym, TRUE); + } + g_string_free(delEnt, TRUE); + g_string_free(delNames, TRUE); + } +} + +/** + * Function for generating MySQL insert commands for newly added symbolic links files. + * If we want to insert the attributes of a symbolic link file, we need to update ENTRIES, NAMES, and ANNEX_INFO. + * The number of insertion in each command can be altered by changing MAXINS. + * If the insertion string is equal to NULL, it will create a insert statement for each table("insert into ..."), and then append the needed attributes to the statement. + * If the number of attributes in our command is equal to MAXINS, it will execute this command on the DB and after that it will free the insert statement. +*/ + +static void InsertMySQLSymlink(struct stat inode,char *Name,ino_t PID,char *sympath) +{ + char *updateEntries="ON DUPLICATE KEY UPDATE id=VALUES(id),uid=VALUES(uid),gid=VALUES(gid),size=VALUES(size),blocks=VALUES(blocks),creation_time=VALUES(creation_time),last_access=VALUES(last_access),last_mod=VALUES(last_mod),last_mdchange=VALUES(last_mdchange),type=VALUES(type),mode=VALUES(mode),nlink=VALUES(nlink),md_update=VALUES(md_update),invalid=VALUES(invalid),fileclass=VALUES(fileclass),class_update=VALUES(fileclass);"; + char uid[RBH_LOGIN_MAX],gid[RBH_LOGIN_MAX]; + uid2str(inode.st_uid,uid); + gid2str(inode.st_gid,gid); + + if(cntInsEnt==0){ + insEnt=g_string_new("INSERT IGNORE INTO ENTRIES(id,uid,gid,size,blocks,creation_time,last_access,last_mod,last_mdchange,type,mode,nlink,md_update,invalid) VALUES"); + insNames=g_string_new("INSERT INTO NAMES(id,parent_id,name,path_update,pkn) VALUES"); + insSym=g_string_new("INSERT IGNORE INTO ANNEX_INFO(id,link) VALUES"); + g_string_append_printf(insEnt, "('%lX:%lX','%s','%s',%lld,%lld,%d,%d,%d,%d,", get_fskey(),inode.st_ino,uid, gid,(long long) inode.st_size,(long long) inode.st_blocks, + (int)inode.st_ctime,(int)inode.st_atime,(int)inode.st_mtime,(int)inode.st_ctime); + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + g_string_append_printf(insEnt,"'blk',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFCHR: + g_string_append_printf(insEnt,"'chr',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFDIR: + g_string_append_printf(insEnt,"'dir',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFIFO: + g_string_append_printf(insEnt,"'fifo',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFLNK: + g_string_append_printf(insEnt,"'symlink',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFREG: + g_string_append_printf(insEnt,"'file',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFSOCK: + g_string_append_printf(insEnt,"'sock',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + default: + break; + } + + g_string_append_printf(insNames,"('%lX:%lX','%lX:%lX',\"%s\",%d,sha1(\"%lX:%lX/%s\"))", get_fskey(),inode.st_ino, get_fskey(),PID,Name,(int)inode.st_mtime, get_fskey(),PID,Name); + g_string_append_printf(insSym,"('%lX:%lX',\"%s\")", get_fskey(),inode.st_ino,sympath); + cntInsEnt++; + cntInsSym++; + } + else if(cntInsEnt!=MAXINS){ + g_string_append_printf(insEnt, ",('%lX:%lX','%s','%s',%lld,%lld,%d,%d,%d,%d,", get_fskey(),inode.st_ino,uid, gid,(long long) inode.st_size,(long long) inode.st_blocks, + (int)inode.st_ctime,(int)inode.st_atime,(int)inode.st_mtime,(int)inode.st_ctime); + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + g_string_append_printf(insEnt,"'blk',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFCHR: + g_string_append_printf(insEnt,"'chr',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFDIR: + g_string_append_printf(insEnt,"'dir',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFIFO: + g_string_append_printf(insEnt,"'fifo',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFLNK: + g_string_append_printf(insEnt,"'symlink',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFREG: + g_string_append_printf(insEnt,"'file',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFSOCK: + g_string_append_printf(insEnt,"'sock',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + default: + break; + } + + if(cntInsSym==0){ + insSym=g_string_new("INSERT IGNORE INTO ANNEX_INFO(id,link) VALUES"); + g_string_append_printf(insSym,"('%lX:%lX',\"%s\")", get_fskey(),inode.st_ino,sympath); + } + else + g_string_append_printf(insSym,",('%lX:%lX',\"%s\")", get_fskey(),inode.st_ino,sympath); + + g_string_append_printf(insNames,",('%lX:%lX','%lX:%lX',\"%s\",%d,sha1(\"%lX:%lX/%s\"))", get_fskey(),inode.st_ino, get_fskey(),PID,Name,(int)inode.st_mtime, get_fskey(),PID,Name); + cntInsEnt++; + cntInsSym++; + } + else{ + + g_string_append_printf(insEnt, ",('%lX:%lX','%s','%s',%lld,%lld,%d,%d,%d,%d,", get_fskey(),inode.st_ino,uid, gid,(long long) inode.st_size,(long long) inode.st_blocks, + (int)inode.st_ctime,(int)inode.st_atime,(int)inode.st_mtime,(int)inode.st_ctime); + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + g_string_append_printf(insEnt,"'blk',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFCHR: + g_string_append_printf(insEnt,"'chr',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFDIR: + g_string_append_printf(insEnt,"'dir',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFIFO: + g_string_append_printf(insEnt,"'fifo',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFLNK: + g_string_append_printf(insEnt,"'symlink',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFREG: + g_string_append_printf(insEnt,"'file',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFSOCK: + g_string_append_printf(insEnt,"'sock',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + default: + break; + } + + if(cntInsSym==0){ + insSym=g_string_new("INSERT IGNORE INTO ANNEX_INFO(id,link) VALUES"); + g_string_append_printf(insSym,"('%lX:%lX',\"%s\");\n", get_fskey(),inode.st_ino,sympath); + } + else + g_string_append_printf(insSym,",('%lX:%lX',\"%s\");\n", get_fskey(),inode.st_ino,sympath); + g_string_append_printf(insNames,",('%lX:%lX','%lX:%lX',\"%s\",%d,sha1(\"%lX:%lX/%s\")) ON DUPLICATE KEY UPDATE id=VALUES(id),parent_id=VALUES(parent_id),name=VALUES(name),path_update=VALUES(path_update);\n", + get_fskey(),inode.st_ino, get_fskey(),PID,Name,(int)inode.st_mtime, get_fskey(),PID,Name); + + cntInsEnt=0; + cntInsSym=0; + db_exec_sql(&lmgr_test.conn, insEnt->str, NULL); + db_exec_sql(&lmgr_test.conn, insNames->str, NULL); + db_exec_sql(&lmgr_test.conn, insSym->str, NULL); + g_string_free(insEnt, TRUE); + g_string_free(insNames, TRUE); + g_string_free(insSym, TRUE); + } +} + + +/** + * Function for generating MySQL insert commands for newly added files that are not symlink. + * If we want to insert the attributes of a file that is not a symbolic link, we need to update ENTRIES, NAMES. + * The number of insertion in each command can be altered by changing MAXINS. + * If the insertion string is equal to NULL, it will create a insert statement for each table("insert into ..."), and then append the needed attributes to the statement. + * If the number of attributes in our command is equal to MAXINS, it will execute this command on the DB and after that it will free the insert statement. + * For executing the Insert commands, first, we checks whether a String is null or not. +*/ +static void InsertMySQLReqular(struct stat inode,char *Name,ino_t PID) +{ + char *updateEntries="ON DUPLICATE KEY UPDATE id=VALUES(id),uid=VALUES(uid),gid=VALUES(gid),size=VALUES(size),blocks=VALUES(blocks),creation_time=VALUES(creation_time),last_access=VALUES(last_access),last_mod=VALUES(last_mod),last_mdchange=VALUES(last_mdchange),type=VALUES(type),mode=VALUES(mode),nlink=VALUES(nlink),md_update=VALUES(md_update),invalid=VALUES(invalid),fileclass=VALUES(fileclass),class_update=VALUES(fileclass);"; + char uid[RBH_LOGIN_MAX],gid[RBH_LOGIN_MAX]; + uid2str(inode.st_uid,uid); + gid2str(inode.st_gid,gid); + if(cntInsEnt==0){ + insEnt=g_string_new("INSERT IGNORE INTO ENTRIES(id,uid,gid,size,blocks,creation_time,last_access,last_mod,last_mdchange,type,mode,nlink,md_update,invalid) VALUES"); + insNames=g_string_new("INSERT INTO NAMES(id,parent_id,name,path_update,pkn) VALUES"); + + g_string_append_printf(insEnt, "('%lX:%lX','%s','%s',%lld,%lld,%d,%d,%d,%d,", get_fskey(),inode.st_ino,uid, gid,(long long) inode.st_size,(long long) inode.st_blocks, + (int)inode.st_ctime,(int)inode.st_atime,(int)inode.st_mtime,(int)inode.st_ctime); + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + g_string_append_printf(insEnt,"'blk',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFCHR: + g_string_append_printf(insEnt,"'chr',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFDIR: + g_string_append_printf(insEnt,"'dir',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFIFO: + g_string_append_printf(insEnt,"'fifo',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFLNK: + g_string_append_printf(insEnt,"'symlink',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFREG: + g_string_append_printf(insEnt,"'file',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFSOCK: + g_string_append_printf(insEnt,"'sock',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + default: + break; + } + g_string_append_printf(insNames,"('%lX:%lX','%lX:%lX',\"%s\",%d,sha1(\"%lX:%lX/%s\"))", get_fskey(),inode.st_ino, get_fskey(),PID,Name,(int)inode.st_mtime, get_fskey(),PID,Name); + cntInsEnt++; + } + else if(cntInsEnt!=MAXINS){ + + g_string_append_printf(insEnt, ",('%lX:%lX','%s','%s',%lld,%lld,%d,%d,%d,%d,", get_fskey(),inode.st_ino,uid, gid,(long long) inode.st_size,(long long) inode.st_blocks, + (int)inode.st_ctime,(int)inode.st_atime,(int)inode.st_mtime,(int)inode.st_ctime); + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + g_string_append_printf(insEnt,"'blk',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFCHR: + g_string_append_printf(insEnt,"'chr',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFDIR: + g_string_append_printf(insEnt,"'dir',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFIFO: + g_string_append_printf(insEnt,"'fifo',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFLNK: + g_string_append_printf(insEnt,"'symlink',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFREG: + g_string_append_printf(insEnt,"'file',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + case S_IFSOCK: + g_string_append_printf(insEnt,"'sock',%d,%ld,%ld,0)",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL)); + break; + default: + break; + } + g_string_append_printf(insNames,",('%lX:%lX','%lX:%lX',\"%s\",%d,sha1(\"%lX:%lX/%s\"))", get_fskey(),inode.st_ino, get_fskey(),PID,Name,(int)inode.st_mtime, get_fskey(),PID,Name); + cntInsEnt++; + } + else{ + g_string_append_printf(insEnt, ",('%lX:%lX','%s','%s',%lld,%lld,%d,%d,%d,%d,", get_fskey(),inode.st_ino,uid, gid,(long long) inode.st_size,(long long) inode.st_blocks, + (int)inode.st_ctime,(int)inode.st_atime,(int)inode.st_mtime,(int)inode.st_ctime); + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + g_string_append_printf(insEnt,"'blk',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFCHR: + g_string_append_printf(insEnt,"'chr',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFDIR: + g_string_append_printf(insEnt,"'dir',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFIFO: + g_string_append_printf(insEnt,"'fifo',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFLNK: + g_string_append_printf(insEnt,"'symlink',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFREG: + g_string_append_printf(insEnt,"'file',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + case S_IFSOCK: + g_string_append_printf(insEnt,"'sock',%d,%ld,%ld,0) %s;\n",inode.st_mode & 07777,(long) inode.st_nlink,time(NULL),updateEntries); + break; + default: + break; + } + + g_string_append_printf(insNames,",('%lX:%lX','%lX:%lX',\"%s\",%d,sha1(\"%lX:%lX/%s\")) ON DUPLICATE KEY UPDATE id=VALUES(id),parent_id=VALUES(parent_id),name=VALUES(name),path_update=VALUES(path_update);\n", + get_fskey(),PID, get_fskey(),PID,Name,(int)inode.st_mtime, get_fskey(),PID,Name); + if(cntInsSym){ + g_string_append_printf(insSym,";\n"); + db_exec_sql(&lmgr_test.conn, insEnt->str, NULL); + db_exec_sql(&lmgr_test.conn, insNames->str, NULL); + db_exec_sql(&lmgr_test.conn, insSym->str, NULL); + g_string_free(insSym, TRUE); + } + else{ + db_exec_sql(&lmgr_test.conn, insEnt->str, NULL); + db_exec_sql(&lmgr_test.conn, insNames->str, NULL); + } + cntInsEnt=0; + cntInsSym=0; + + g_string_free(insEnt, TRUE); + g_string_free(insNames, TRUE); + } +} + +/** + * Function for getting relative path to a symlink file. + * It will use readlink function and if there is an error in one of the function, it will generate the error. +*/ +static char * symlinkPath(char * path, off_t st_size) +{ + ssize_t nbytes, bufsiz; + bufsiz = st_size + 1; + if (st_size == 0) + bufsiz = 4096; + + char *buf = malloc(bufsiz); + if (buf == NULL) { + DisplayLog(LVL_MAJOR, "PansasSymlinkError","Fatal Error. Out of space."); + exit(1); + } + nbytes = readlink(path, buf, bufsiz); + if (nbytes == -1) { + DisplayLog(LVL_MAJOR, "PansasSymlinkError","Fatal Error. Readlink is not working."); + exit(1); + } + else{ + buf[nbytes]='\0'; + } + if (nbytes == bufsiz) + DisplayLog(LVL_MAJOR, "PansasSymlinkError","Fatal Error. Returned buffer may have been truncated\n"); + exit(1); + + return buf; +} + +/** + * Main function for updating the DB. + * This function gets the needed information for updating the DB, and then using InsertMySQLReqular, InsertMySQLSymlink, and DeleteMySQL, it will update the DB. + * pan_snap_delta produces 8 different results. For updating the DB, we only need to check five of them. + * In this function, first it will open the file and then based on the type of file it will choose whether to insert to DB or delete from it. + * Then using stat and lgetxattr, we will get the needed attributes. If the file is symbolic link, we also need to know where our file is pointing to. + * We will get it using symlinkPath, and then using insert and delete functions we will update the DB. +*/ + +static void PanUp(char *snap1Path,char *snap2Path) +{ + FILE * fp; + int index=-1,i,j; + // Variables for showing the type of a command + int delete,sym; + // Variables for generating the correct path. + char * line = NULL,*modifiedLine=NULL,*defLine=NULL; + ssize_t read; + // Size of diferent variables + size_t fullpathsz=0,linesz=0,len = 0; + // Variables for stat result and parent ID. + struct stat inode; + ino_t PID; + // Temp variables for getting the information from getxattr. + ssize_t objPidSize, objIdSize; + char *objPid, *objId; + char *key,*keyPar; + //Temp variables + GString *specialCase=NULL; + char *symPath,*Name; + int count=0; + char fullpath[PATH_MAX]; + GString *fileOpen=NULL; + + for (i=1;i<=5;i++){ + switch (i) { + case 1: + delete=1; + fileOpen=g_string_new(""); + g_string_append_printf(fileOpen,"%s/out.delete_file",panfs_config.snap_delta_results_path); + fp = fopen(fileOpen->str, "r"); + g_string_free(fileOpen, TRUE); + break; + case 2: + delete=1; + fileOpen=g_string_new(""); + g_string_append_printf(fileOpen,"%s/out.move_stage_file",panfs_config.snap_delta_results_path); + fp = fopen(fileOpen->str, "r"); + g_string_free(fileOpen, TRUE); + break; + case 3: + delete=1; + fileOpen=g_string_new(""); + g_string_append_printf(fileOpen,"%s/out.delete_or_move_stage_dir",panfs_config.snap_delta_results_path); + fp = fopen(fileOpen->str, "r"); + g_string_free(fileOpen, TRUE); + break; + case 4: + delete=0; + fileOpen=g_string_new(""); + g_string_append_printf(fileOpen,"%s/out.sync",panfs_config.snap_delta_results_path); + fp = fopen(fileOpen->str, "r"); + g_string_free(fileOpen, TRUE); + break; + case 5: + delete=0; + fileOpen=g_string_new(""); + g_string_append_printf(fileOpen,"%s/out.link_file",panfs_config.snap_delta_results_path); + fp = fopen(fileOpen->str, "r"); + g_string_free(fileOpen, TRUE); + break; + } + if (fp == NULL){ + fprintf(stderr, "Error Opening %d",i); + exit(EXIT_FAILURE); + } + while ((read = getline(&line, &len, fp)) != -1) { + sp=false; + line[strlen(line)-1]='\0'; + if(i==2 || i==3 || i==4 || i==5) + for(j = 0; j <= strlen(line); j++){ + if(line[j] == 30) { + modifiedLine=line+j+1; + break; + } + } + else + modifiedLine=line; + + char *pch = strstr(modifiedLine, "\\\\"); + if (pch){ + defLine=modifiedLine; + specialCase=g_string_new(modifiedLine); + pch = strstr(specialCase->str, "\\\\"); + while(pch){ + g_string_erase(specialCase,(int)(pch-specialCase->str),1); + pch = strstr(specialCase->str, "\\\\"); + } + modifiedLine=specialCase->str; + sp=true; + } + + if (strcmp(modifiedLine,"")==0){ + count++; + continue; + } + linesz=strlen(modifiedLine); + + if (i<=3){ + fullpathsz=strlen(snap1Path)+linesz+1; + strcpy(fullpath,snap1Path); + } + else{ + fullpathsz=strlen(snap2Path)+linesz+1; + strcpy(fullpath,snap2Path); + } + strcat(fullpath,"/"); + strcat(fullpath,modifiedLine); + + fullpath[fullpathsz]='\0'; + + for(j = 0; j <= strlen(fullpath); j++){ + if (fullpath[j] == '/'){ + index = j; + } + } + + objIdSize = lgetxattr(fullpath, "system.panfs.obj_id", NULL, 0); + lstat(fullpath,&inode); + fullpath[index]='\0'; + objPidSize = lgetxattr(fullpath, "system.panfs.obj_id", NULL, 0); + + if (objIdSize > 0 && objPidSize > 0 ) { + + objId = malloc(objIdSize + 1); + objPid = malloc(objPidSize + 1); + if(objId==NULL){ + fprintf(stderr, "Error Malloc ID"); + exit(1); + } + if(objPid==NULL){ + fprintf(stderr, "Error Malloc PID"); + exit(1); + } + + objPidSize = lgetxattr(fullpath, "system.panfs.obj_id", objPid, objPidSize); + fullpath[index]='/'; + objIdSize = lgetxattr(fullpath, "system.panfs.obj_id", objId, objIdSize); + + if (objPidSize == -1 || objIdSize==-1){ + fprintf(stderr, "Error getting ID"); + exit(1); + } + else { + objPid[objPidSize] = 0; + objId[objIdSize] = 0; + key=strchr(objId, 'U')+1; + keyPar=strchr(objPid, 'U')+1; + } + inode.st_ino=strtoull(key,&key,16); + PID=strtoull(keyPar,&keyPar,16); + + if(sp) + Name=strrchr(defLine,'/')+1; + else + Name=strrchr(fullpath,'/')+1; + + free(objId); + free(objPid); + } + + else { + fprintf(stderr, "Error getting size of ID or PID"); + exit(1); + } + + + switch (inode.st_mode & S_IFMT) { + case S_IFBLK: + sym=0; break; + case S_IFCHR: + sym=0; break; + case S_IFDIR: + sym=0; break; + case S_IFIFO: + sym=0; break; + case S_IFLNK: + symPath=symlinkPath(fullpath,inode.st_size); + sym=1; break; + case S_IFREG: + sym=0; break; + case S_IFSOCK: + sym=0; break; + default: + sym=0; break; + } + if(delete) + DeleteMySQL(inode,Name,PID,sym); + else if(sym) + InsertMySQLSymlink(inode,Name,PID,symPath); + else + InsertMySQLReqular(inode,Name,PID); + } + + if(i==3 && cntDelEnt){ + g_string_append_printf(delEnt, ");\n"); + g_string_append_printf(delNames,");\n"); + db_exec_sql(&lmgr_test.conn, delEnt->str, NULL); + db_exec_sql(&lmgr_test.conn, delNames->str, NULL); + cntDelEnt=0; + g_string_free(delEnt, TRUE); + g_string_free(delNames, TRUE); + + if(cntDelSym){ + g_string_append_printf(delSym,");\n"); + db_exec_sql(&lmgr_test.conn, delSym->str, NULL); + cntDelSym=0; + g_string_free(delSym, TRUE); + } + } + else if(i==5 && cntInsEnt){ + g_string_append_printf(insEnt, " ON DUPLICATE KEY UPDATE id=VALUES(id),uid=VALUES(uid),gid=VALUES(gid),size=VALUES(size),blocks=VALUES(blocks),creation_time=VALUES(creation_time),last_access=VALUES(last_access),last_mod=VALUES(last_mod),last_mdchange=VALUES(last_mdchange),type=VALUES(type),mode=VALUES(mode),nlink=VALUES(nlink),md_update=VALUES(md_update),invalid=VALUES(invalid),fileclass=VALUES(fileclass),class_update=VALUES(fileclass);\n"); + g_string_append_printf(insNames," ON DUPLICATE KEY UPDATE id=VALUES(id),parent_id=VALUES(parent_id),name=VALUES(name),path_update=VALUES(path_update);\n"); + db_exec_sql(&lmgr_test.conn, insEnt->str, NULL); + db_exec_sql(&lmgr_test.conn, insNames->str, NULL); + + cntInsEnt=0; + g_string_free(insEnt, TRUE); + g_string_free(insNames, TRUE); + + if(cntInsSym){ + g_string_append_printf(insSym,";\n"); + db_exec_sql(&lmgr_test.conn, insSym->str, NULL); + cntInsSym=0; + g_string_free(insSym, TRUE); + } + } + } + fclose(fp); + if (line) + free(line); +} + +#endif int main(int argc, char **argv) { int rc; @@ -1626,6 +2299,84 @@ int main(int argc, char **argv) exit(1); } +#ifdef _PANFS + char firstSnap[1024],secondSnap[1024],snapDone[1024]; + char *firstSnapName, *secondSnapName,*pos; + char fs_path_pan[RBH_PATH_MAX]; + GString *lastSnap= NULL,*dirCom= NULL,*dirRm= NULL,*srtDelFile=NULL,*srtMvFile=NULL,*srtDelDir=NULL,*srtSync=NULL,*srtLink=NULL; + dirCom=g_string_new("mkdir -p "); + g_string_append_printf(dirCom,"%s",panfs_config.snap_delta_results_path); + + srtDelFile=g_string_new("sort -t $'\031' -k 1,1 "); + g_string_append_printf(srtDelFile,"%s/res.delete_file -o %s/out.delete_file",panfs_config.snap_delta_results_path,panfs_config.snap_delta_results_path); + + srtMvFile=g_string_new("sort -t $'\031' -k 2,2 "); + g_string_append_printf(srtMvFile,"%s/res.move_stage_file -o %s/out.move_stage_file",panfs_config.snap_delta_results_path,panfs_config.snap_delta_results_path); + + srtDelDir=g_string_new("sort -t $'\031' -k 1,1nr "); + g_string_append_printf(srtDelDir,"%s/res.delete_or_move_stage_dir -o %s/out.delete_or_move_stage_dir",panfs_config.snap_delta_results_path,panfs_config.snap_delta_results_path); + + srtSync=g_string_new("sort -t $'\031' -k 1,1nr -k 2,2 "); + g_string_append_printf(srtSync,"%s/res.sync -o %s/out.sync",panfs_config.snap_delta_results_path,panfs_config.snap_delta_results_path); + + srtLink=g_string_new("sort -t $'\031' -k 1,1nr -k 2,2 "); + g_string_append_printf(srtLink,"%s/res.link_file -o %s/out.link_file",panfs_config.snap_delta_results_path,panfs_config.snap_delta_results_path); + + dirRm=g_string_new("rm -rf "); + g_string_append_printf(dirRm,"%s/*",panfs_config.snap_delta_results_path); + + rc = ListMgr_InitAccess(&lmgr_test); + if (rc) { + DisplayLog(LVL_CRIT, "Initialization","Failed"); + exit(1); + } + + rc = ListMgr_GetVar(&lmgr_test,SNAPSHOT_PATH , firstSnap, sizeof(firstSnap)); + rc = ListMgr_GetVar(&lmgr_test,SNAPSHOT_DONE , snapDone, sizeof(snapDone)); + lastSnap=g_string_new("ls -d "); + g_string_append_printf(lastSnap,"%s%s* | tail -n 1",global_config.fs_path,"/.snapshot/"); + strcpy(fs_path_pan,global_config.fs_path); + + if(strcmp(snapDone,"done")==0 && strcmp(options.firstSnapshot, "")==0){ + + FILE *resFile=popen(lastSnap->str,"r"); + fgets(secondSnap, sizeof(secondSnap), resFile); + + if ((pos=strchr(secondSnap, '\n')) != NULL) + *pos = '\0'; + DisplayLog(LVL_CRIT,"Panasas File System","Full Tree Walk is not needed"); + + firstSnapName=strrchr(firstSnap,'/')+1; + secondSnapName=strrchr(secondSnap,'/')+1; + panSnap=g_string_new(""); + g_string_append_printf(panSnap,"%s --volume=%s --result_format=1 --result=%s/res --older_snap=%s --newer_snap=%s", + panfs_config.snap_delta_path, panfs_config.volume, panfs_config.snap_delta_results_path, firstSnapName, secondSnapName); + pclose(resFile); + options.Pan_FTW=0; + } + else if(strcmp(snapDone,"done")==0 && strcmp(options.firstSnapshot, "")){ + DisplayLog(LVL_CRIT, MAIN_TAG,"ERROR: the base Snapshot is already available in database"); + exit(1); + } + else if(strcmp(snapDone,"")==0 && strcmp(options.firstSnapshot, "")==0){ + DisplayLog(LVL_CRIT, MAIN_TAG,"ERROR: Please provide a snapshot name for the first run"); + exit(1); + } + else if(strcmp(snapDone,"")==0 && strcmp(options.firstSnapshot, "")){ + strcat(global_config.fs_path,"/.snapshot/"); + strcat(global_config.fs_path,options.firstSnapshot); + DisplayLog(LVL_CRIT,"Panasas File System","Full Tree Walk is needed"); + options.Pan_FTW=1; + } + else if(strcmp(snapDone,"undone")==0){ + DisplayLog(LVL_CRIT, MAIN_TAG,"ERROR: Previous run was not completed correctly. Please drop the database and run first run again"); + exit(1); + + } + ListMgr_CloseAccess(&lmgr_test); + +#endif + if (options.test_syntax) { printf("Configuration file '%s' has been read successfully\n", options.config_file); @@ -1761,12 +2512,53 @@ int main(int argc, char **argv) "EntryProcessor successfully initialized"); } +#ifdef _PANFS + rc = ListMgr_InitAccess(&lmgr_test); + if (rc) { + DisplayLog(LVL_CRIT, "Initialization","Failed"); + exit(1); + } + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "undone"); + rc = ListMgr_SetVar(&lmgr_test,FS_PATH_VAR, fs_path_pan); + ListMgr_CloseAccess(&lmgr_test); +#endif + /* Note: in 'one-shot' mode, we must take care of performing action in * the correct order: * first scan, then process changelogs, then migrate, then purge, etc. */ if (!terminate_sig && action_mask & ACTION_MASK_SCAN) { +#ifdef _PANFS + if(options.Pan_FTW==0){ + if(strcmp(firstSnap,secondSnap)<0 ){ + rc = ListMgr_InitAccess(&lmgr_test); + if (rc) { + DisplayLog(LVL_CRIT, "Initialization","Failed"); + exit(1); + } + DisplayLog(LVL_CRIT, "PanasasUpdate","Newer snapshot is found. Newer snapshot= %s\n",secondSnap); + + system(dirCom->str); + system(dirRm->str); + system(panSnap->str); + system(srtDelFile->str); + system(srtMvFile->str); + system(srtDelDir->str); + system(srtSync->str); + system(srtLink->str); + PanUp(firstSnap,secondSnap); + ListMgr_CloseAccess(&lmgr_test); + g_string_free(panSnap, TRUE); + + goto PAN; + } + else{ + DisplayLog(LVL_CRIT, "PanasasUpdate","Newer snapshot is not available.\n"); + goto PAN; + } + } +#endif /* Start FS scan */ if (options.partial_scan) @@ -1790,6 +2582,10 @@ int main(int argc, char **argv) else running_mask |= MODULE_MASK_FS_SCAN | MODULE_MASK_ENTRY_PROCESSOR; +#ifdef _PANFS + FSScan_Wait(); + DisplayLog(LVL_MAJOR, MAIN_TAG, "FS Scan finished"); +#else if (options.flags & RUNFLG_ONCE) { FSScan_Wait(); DisplayLog(LVL_MAJOR, MAIN_TAG, "FS Scan finished"); @@ -1798,7 +2594,13 @@ int main(int argc, char **argv) if (terminate_sig) pthread_mutex_lock(&shutdown_mtx); } +#endif } + +#ifdef _PANFS +PAN: +#endif + #ifdef HAVE_CHANGELOGS if (!terminate_sig && action_mask & ACTION_MASK_HANDLE_EVENTS) { @@ -1837,6 +2639,26 @@ int main(int argc, char **argv) /* Pipeline must be flushed */ EntryProcessor_Terminate(true); +#ifdef _PANFS + rc = ListMgr_InitAccess(&lmgr_test); + if (rc) { + DisplayLog(LVL_CRIT, "Initialization","Failed"); + exit(1); + } + if(options.Pan_FTW==0 && strcmp(firstSnap,secondSnap)<0){ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_PATH , secondSnap); + } + else if(options.Pan_FTW==0 && strcmp(firstSnap,secondSnap)>=0){ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + } + else{ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_PATH , global_config.fs_path); + } + ListMgr_CloseAccess(&lmgr_test); +#endif + #ifdef HAVE_CHANGELOGS if (action_mask & ACTION_MASK_HANDLE_EVENTS) { /* Ack last changelog records. */ @@ -1894,7 +2716,96 @@ int main(int argc, char **argv) if (!(options.flags & RUNFLG_ONCE) && (policy_run_mask != 0)) running_mask |= MODULE_MASK_POLICY_RUN; } +#ifdef _PANFS + if (!(options.flags & RUNFLG_ONCE)) { + rc = ListMgr_InitAccess(&lmgr_test); + if (rc) { + DisplayLog(LVL_CRIT, "Initialization","Failed"); + exit(1); + } + + if(options.Pan_FTW==0 && strcmp(firstSnap,secondSnap)<0){ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_PATH , secondSnap); + } + else if(options.Pan_FTW==0 && strcmp(firstSnap,secondSnap)>=0){ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + } + else{ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_PATH , global_config.fs_path); + } + EntryProcessor_Terminate(true); + FlushLogs(); + while (!terminate_sig) { + rh_sleep(panfs_config.update_interval > 0 ? panfs_config.update_interval : 1); + rc = ListMgr_GetVar(&lmgr_test,SNAPSHOT_PATH , firstSnap, sizeof(firstSnap)); + rc = ListMgr_GetVar(&lmgr_test,SNAPSHOT_DONE , snapDone, sizeof(snapDone)); + + if(strcmp(snapDone,"done")==0){ + FILE *resFile=popen(lastSnap->str,"r"); + fgets(secondSnap, sizeof(secondSnap), resFile); + if ((pos=strchr(secondSnap, '\n')) != NULL) + *pos = '\0'; + + firstSnapName=strrchr(firstSnap,'/')+1; + secondSnapName=strrchr(secondSnap,'/')+1; + + if(strcmp(firstSnap,secondSnap)<0){ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "undone"); + panSnap=g_string_new(""); + g_string_append_printf(panSnap,"%s --volume=%s --result_format=1 --result=%s/res --older_snap=%s --newer_snap=%s", + panfs_config.snap_delta_path, panfs_config.volume, panfs_config.snap_delta_results_path, firstSnapName, secondSnapName); + system(dirCom->str); + system(dirRm->str); + system(panSnap->str); + system(srtDelFile->str); + system(srtMvFile->str); + system(srtDelDir->str); + system(srtSync->str); + system(srtLink->str); + PanUp(firstSnap,secondSnap); + fprintf(stderr, "New snapshot is found. Snapshot=%s\n",secondSnap); + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_PATH , secondSnap); + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + g_string_free(panSnap, TRUE); + + } + else{ + rc = ListMgr_SetVar(&lmgr_test,SNAPSHOT_DONE , "done"); + fprintf(stderr, "New snapshot is not found. Going to sleep!\n"); + } + pclose(resFile); + } + else{ + DisplayLog(LVL_CRIT, MAIN_TAG,"ERROR: Previous run was not completed correctly. Please drop the database and run first run again"); + exit(1); + } + } + g_string_free(lastSnap, TRUE); + g_string_free(dirCom, TRUE); + g_string_free(dirRm, TRUE); + g_string_free(srtDelFile, TRUE); + g_string_free(srtMvFile, TRUE); + g_string_free(srtDelDir, TRUE); + g_string_free(srtSync, TRUE); + g_string_free(srtLink, TRUE); + ListMgr_CloseAccess(&lmgr_test); + exit(0); + } + else{ + g_string_free(dirCom, TRUE); + g_string_free(dirRm, TRUE); + g_string_free(srtDelFile, TRUE); + g_string_free(srtMvFile, TRUE); + g_string_free(srtDelDir, TRUE); + g_string_free(srtSync, TRUE); + g_string_free(srtLink, TRUE); + DisplayLog(LVL_MAJOR, MAIN_TAG, "All tasks done! Exiting."); + exit(0); + } +#endif if (!(options.flags & RUNFLG_ONCE)) { char tmpstr[1024]; diff --git a/src/robinhood/rbh_find.c b/src/robinhood/rbh_find.c index 808099df4..7274c699e 100644 --- a/src/robinhood/rbh_find.c +++ b/src/robinhood/rbh_find.c @@ -21,6 +21,9 @@ #include "config.h" #endif +#ifdef _PANFS +#include "panfs_config.h" +#endif #include "list_mgr.h" #include "cmd_helpers.h" #include "rbh_cfg.h"