/* Copyright (c) 2016 Red Hat, Inc. This file is part of gluster-block. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ # ifndef _UTILS_H # define _UTILS_H 1 # define _GNU_SOURCE /* See feature_test_macros(7) */ # include # include # include # include # include # include # include # include # include # include # define GB_LOGDIR DATADIR "/log/gluster-block" # define GB_INFODIR DATADIR "/run" # define GB_LOCK_FILE GB_INFODIR "/gluster-blockd.lock" # define GB_UNIX_ADDRESS GB_INFODIR "/gluster-blockd.socket" # define GB_TCP_PORT 24010 # define GFAPI_LOG_LEVEL 7 # define DEVNULLPATH "/dev/null" # define GB_METADIR "/block-meta" # define GB_STOREDIR "/block-store" # define GB_TXLOCKFILE "meta.lock" # define GB_MAX_LOGFILENAME 64 /* max strlen of file name */ # define SUN_PATH_MAX (sizeof(struct sockaddr_un) - sizeof(unsigned short int)) /*sun_family*/ # define GB_TIME_STRING_BUFLEN \ (4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 6 + 1 + 5) /* Yr Mon Day Hour Min Sec Ms NULL Round-off(32) 2017 - 06 - 01 ' ' 18 : 58 : 29 . 695147 '\0' Power^2 2017-06-01 18:58:29.695147 */ /* Target Create */ # define FAILED_CREATE "failed in create" # define FAILED_REMOTE_CREATE "failed in remote create" # define FAILED_REMOTE_AYNC_CREATE "failed in remote async create" # define FAILED_CREATING_FILE "failed while creating block file in gluster volume" # define FAILED_CREATING_META "failed while creating block meta file from volume" /* Target List */ # define FAILED_LIST "failed in list" /* Target Info */ # define FAILED_INFO "failed in info" /* Target Modify */ # define FAILED_MODIFY "failed in modify" # define FAILED_REMOTE_MODIFY "failed in remote modify" # define FAILED_REMOTE_AYNC_MODIFY "failed in remote async modify" /* Target Delete */ # define FAILED_DELETE "failed in delete" # define FAILED_REMOTE_DELETE "failed in remote delete" # define FAILED_REMOTE_AYNC_DELETE "failed in remote async delete" # define FAILED_DELETING_FILE "failed while deleting block file from gluster volume" # define FAILED_DELETING_META "failed while deleting block meta file from volume" # define FAILED_DEPENDENCY "failed dependency, check if you have targetcli and tcmu-runner installed" # define FMT_WARN(fmt...) do { if (0) printf (fmt); } while (0) # define GB_ASPRINTF(ptr, fmt...) ({FMT_WARN (fmt); \ int __ret=asprintf(ptr, ##fmt);__ret;}) # define LOCK(x) \ do { \ pthread_mutex_lock(&x); \ } while (0) # define UNLOCK(x) \ do { \ pthread_mutex_unlock(&x); \ } while (0) # define ERROR(fmt, ...) \ do { \ fprintf(stderr, "Error: " fmt " [at %s+%d :<%s>]\n", \ __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__); \ } while (0) # define MSG(fmt, ...) \ do { \ fprintf(stdout, fmt, __VA_ARGS__); \ } while (0) struct gbConf { int logLevel; char logDir[PATH_MAX]; char daemonLogFile[PATH_MAX]; char cliLogFile[PATH_MAX]; char gfapiLogFile[PATH_MAX]; char configShellLogFile[PATH_MAX]; }; extern struct gbConf gbConf; # define LOG(str, level, fmt, ...) \ do { \ FILE *fd; \ char timestamp[GB_TIME_STRING_BUFLEN] = {0}; \ if (level <= gbConf.logLevel) { \ if (!strcmp(str, "mgmt")) \ fd = fopen (gbConf.daemonLogFile, "a"); \ else if (!strcmp(str, "cli")) \ fd = fopen (gbConf.cliLogFile, "a"); \ else if (!strcmp(str, "gfapi")) \ fd = fopen (gbConf.gfapiLogFile, "a"); \ else \ fd = stderr; \ if (fd == NULL) { \ fprintf(stderr, "Error opening log file: %s\n" \ "Logging to stderr.\n", \ strerror(errno)); \ fd = stderr; \ } \ logTimeNow(timestamp, GB_TIME_STRING_BUFLEN); \ fprintf(fd, "[%s] %s: " fmt " [at %s+%d :<%s>]\n", \ timestamp, LogLevelLookup[level], \ __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__); \ if (fd != stderr) \ fclose(fd); \ } \ } while (0) # define GB_METALOCK_OR_GOTO(lkfd, volume, errCode, errMsg, label) \ do { \ struct flock lock = {0, }; \ lock.l_type = F_WRLCK; \ if (glfs_posix_lock (lkfd, F_SETLKW, &lock)) { \ LOG("mgmt", GB_LOG_ERROR, "glfs_posix_lock() on " \ "volume %s failed[%s]", volume, strerror(errno)); \ errCode = errno; \ if (!errMsg) { \ GB_ASPRINTF (&errMsg, "Not able to acquire " \ "lock on %s[%s]", volume, strerror(errCode));\ } \ goto label; \ } \ } while (0) # define GB_METAUPDATE_OR_GOTO(lock, glfs, fname, \ volume, ret, errMsg, label,...) \ do { \ char *write; \ struct glfs_fd *tgmfd; \ LOCK(lock); \ ret = glfs_chdir (glfs, GB_METADIR); \ if (ret) { \ GB_ASPRINTF(&errMsg, "Failed to update transaction log " \ "for %s/%s[%s]", volume, fname, strerror(errno)); \ LOG("gfapi", GB_LOG_ERROR, "glfs_chdir(%s) on " \ "volume %s failed[%s]", GB_METADIR, volume, \ strerror(errno)); \ UNLOCK(lock); \ ret = -1; \ goto label; \ } \ tgmfd = glfs_creat(glfs, fname, \ O_WRONLY | O_APPEND | O_SYNC, \ S_IRUSR | S_IWUSR); \ if (!tgmfd) { \ GB_ASPRINTF(&errMsg, "Failed to update transaction log " \ "for %s/%s[%s]", volume, fname, strerror(errno)); \ LOG("mgmt", GB_LOG_ERROR, "glfs_creat(%s): on " \ "volume %s failed[%s]", fname, volume, \ strerror(errno)); \ UNLOCK(lock); \ ret = -1; \ goto label; \ } \ if (GB_ASPRINTF(&write, __VA_ARGS__) < 0) { \ ret = -1; \ } \ if (!ret) { \ if(glfs_write (tgmfd, write, strlen(write), 0) < 0) { \ GB_ASPRINTF(&errMsg, "Failed to update transaction log "\ "for %s/%s[%s]", volume, fname, strerror(errno)); \ LOG("mgmt", GB_LOG_ERROR, "glfs_write(%s): on " \ "volume %s failed[%s]", fname, volume, \ strerror(errno)); \ ret = -1; \ } \ GB_FREE(write); \ } \ if (tgmfd && glfs_close(tgmfd) != 0) { \ GB_ASPRINTF(&errMsg, "Failed to update transaction log " \ "for %s/%s[%s]", volume, fname, strerror(errno)); \ LOG("mgmt", GB_LOG_ERROR, "glfs_close(%s): on " \ "volume %s failed[%s]", fname, volume, \ strerror(errno)); \ UNLOCK(lock); \ ret = -1; \ goto label; \ } \ UNLOCK(lock); \ if (ret) { \ goto label; \ } \ } while (0) # define GB_METAUNLOCK(lkfd, volume, ret, errMsg) \ do { \ struct flock lock = {0, }; \ lock.l_type = F_UNLCK; \ if (glfs_posix_lock(lkfd, F_SETLK, &lock)) { \ if (!errMsg) { \ GB_ASPRINTF (&errMsg, "Not able to acquire " \ "lock on %s[%s]", volume, strerror(errno)); \ } \ LOG("mgmt", GB_LOG_ERROR, "glfs_posix_lock() on " \ "volume %s failed[%s]", volume, strerror(errno)); \ ret = -1; \ } \ } while (0) # define GB_CMD_EXEC_AND_VALIDATE(cmd, sr, blk, vol, opt) \ do { \ FILE *fp; \ char tmp[1024]; \ LOG("mgmt", GB_LOG_DEBUG, "command, %s", cmd); \ fp = popen(cmd, "r"); \ snprintf(tmp, 1024, "%s/%s", vol?vol:"", blk->block_name); \ if (fp) { \ size_t newLen = fread(sr->out, sizeof(char), 8192, fp); \ if (ferror( fp ) != 0) \ LOG("mgmt", GB_LOG_ERROR, \ "reading command %s output for %s failed(%s)", tmp,\ cmd, strerror(errno)); \ else \ sr->out[newLen++] = '\0'; \ sr->exit = blockValidateCommandOutput(sr->out, opt, \ (void*)blk); \ pclose(fp); \ } else { \ LOG("mgmt", GB_LOG_ERROR, \ "popen(): for %s executing command %s failed(%s)", \ tmp, cmd, strerror(errno)); \ } \ LOG("mgmt", GB_LOG_DEBUG, "raw output, %s", sr->out); \ LOG("mgmt", GB_LOG_INFO, "command exit code, %d", \ sr->exit); \ } while (0) # define GB_OUT_VALIDATE_OR_GOTO(out, label, errStr, blk, vol, ...) \ do { \ char *tmp; \ char vol_blk[1024]; \ snprintf(vol_blk, 1024, "%s/%s", vol?vol:"", \ blk->block_name); \ if (GB_ASPRINTF(&tmp, __VA_ARGS__) == -1) \ goto label; \ if (!strstr(out, tmp)) { \ GB_FREE(tmp); \ LOG("mgmt", GB_LOG_ERROR, errStr, vol_blk); \ goto label; \ } \ GB_FREE(tmp); \ } while (0) # define CALLOC(x) \ calloc(1, x) # define GB_ALLOC(ptr) \ gbAlloc(&(ptr), sizeof(*(ptr)), \ __FILE__, __FUNCTION__, __LINE__) # define GB_ALLOC_N(ptr, count) \ gbAllocN(&(ptr), sizeof(*(ptr)), (count), \ __FILE__, __FUNCTION__, __LINE__) \ # define xalloc_oversized(n, s) \ ((size_t) (sizeof(ptrdiff_t) <= sizeof(size_t) ? -1 : -2) / (s) < (n)) # define GB_REALLOC_N(ptr, count) \ gbReallocN(&(ptr), sizeof(*(ptr)), (count), \ __FILE__, __FUNCTION__, __LINE__) # define GB_STRDUP(dst, src) \ gbStrdup(&(dst), src, \ __FILE__, __FUNCTION__, __LINE__) # define GB_FREE(ptr) \ gbFree(1 ? (void *) &(ptr) : (ptr)) typedef enum gbCliCmdlineOption { GB_CLI_UNKNOWN = 0, GB_CLI_CREATE = 1, GB_CLI_LIST = 2, GB_CLI_INFO = 3, GB_CLI_DELETE = 4, GB_CLI_MODIFY = 5, GB_CLI_HELP = 6, GB_CLI_HYPHEN_HELP = 7, GB_CLI_VERSION = 8, GB_CLI_HYPHEN_VERSION = 9, GB_CLI_USAGE = 10, GB_CLI_HYPHEN_USAGE = 11, GB_CLI_OPT_MAX } gbCliCmdlineOption; static const char *const gbCliCmdlineOptLookup[] = { [GB_CLI_UNKNOWN] = "NONE", [GB_CLI_CREATE] = "create", [GB_CLI_LIST] = "list", [GB_CLI_INFO] = "info", [GB_CLI_DELETE] = "delete", [GB_CLI_MODIFY] = "modify", [GB_CLI_HELP] = "help", [GB_CLI_HYPHEN_HELP] = "--help", [GB_CLI_VERSION] = "version", [GB_CLI_HYPHEN_VERSION] = "--version", [GB_CLI_USAGE] = "usage", [GB_CLI_HYPHEN_USAGE] = "--usage", [GB_CLI_OPT_MAX] = NULL, }; typedef enum gbDaemonCmdlineOption { GB_DAEMON_UNKNOWN = 0, GB_DAEMON_HELP = 1, GB_DAEMON_VERSION = 2, GB_DAEMON_USAGE = 3, GB_DAEMON_GLFS_LRU_COUNT = 4, GB_DAEMON_LOG_LEVEL = 5, GB_DAEMON_OPT_MAX } gbDaemonCmdlineOption; static const char *const gbDaemonCmdlineOptLookup[] = { [GB_DAEMON_UNKNOWN] = "NONE", [GB_DAEMON_HELP] = "help", [GB_DAEMON_VERSION] = "version", [GB_DAEMON_USAGE] = "usage", [GB_DAEMON_GLFS_LRU_COUNT] = "glfs-lru-count", [GB_DAEMON_LOG_LEVEL] = "log-level", [GB_DAEMON_OPT_MAX] = NULL, }; typedef enum LogLevel { GB_LOG_NONE = 0, GB_LOG_ERROR = 1, GB_LOG_WARNING = 2, GB_LOG_INFO = 3, GB_LOG_DEBUG = 4, GB_LOG_TRACE = 5, GB_LOG_MAX } LogLevel; static const char *const LogLevelLookup[] = { [GB_LOG_NONE] = "NONE", [GB_LOG_ERROR] = "ERROR", [GB_LOG_WARNING] = "WARNING", [GB_LOG_INFO] = "INFO", [GB_LOG_DEBUG] = "DEBUG", [GB_LOG_TRACE] = "TRACE", [GB_LOG_MAX] = NULL, }; typedef enum Metakey { GB_META_VOLUME = 0, GB_META_GBID = 1, GB_META_SIZE = 2, GB_META_HA = 3, GB_META_ENTRYCREATE = 4, GB_META_ENTRYDELETE = 5, GB_META_PASSWD = 6, GB_METAKEY_MAX } Metakey; static const char *const MetakeyLookup[] = { [GB_META_VOLUME] = "VOLUME", [GB_META_GBID] = "GBID", [GB_META_SIZE] = "SIZE", [GB_META_HA] = "HA", [GB_META_ENTRYCREATE] = "ENTRYCREATE", [GB_META_ENTRYDELETE] = "ENTRYDELETE", [GB_META_PASSWD] = "PASSWORD", [GB_METAKEY_MAX] = NULL }; typedef enum MetaStatus { GB_CONFIG_SUCCESS = 0, GB_CONFIG_FAIL = 1, GB_CONFIG_INPROGRESS = 2, GB_AUTH_ENFORCEING = 3, GB_AUTH_ENFORCED = 4, GB_AUTH_ENFORCE_FAIL = 5, GB_AUTH_CLEAR_ENFORCEING = 6, GB_AUTH_CLEAR_ENFORCED = 7, GB_AUTH_CLEAR_ENFORCE_FAIL = 8, GB_CLEANUP_SUCCESS = 9, GB_CLEANUP_FAIL = 10, GB_CLEANUP_INPROGRESS = 11, GB_METASTATUS_MAX } MetaStatus; static const char *const MetaStatusLookup[] = { [GB_CONFIG_SUCCESS] = "CONFIGSUCCESS", [GB_CONFIG_FAIL] = "CONFIGFAIL", [GB_CONFIG_INPROGRESS] = "CONFIGINPROGRESS", [GB_AUTH_ENFORCEING] = "AUTHENFORCEING", [GB_AUTH_ENFORCED] = "AUTHENFORCED", [GB_AUTH_ENFORCE_FAIL] = "AUTHENFORCEFAIL", [GB_AUTH_CLEAR_ENFORCEING] = "AUTHCLEARENFORCEING", [GB_AUTH_CLEAR_ENFORCED] = "AUTHCLEARENFORCED", [GB_AUTH_CLEAR_ENFORCE_FAIL] = "AUTHCLEARENFORCEFAIL", [GB_CLEANUP_INPROGRESS] = "CLEANUPINPROGRESS", [GB_CLEANUP_SUCCESS] = "CLEANUPSUCCESS", [GB_CLEANUP_FAIL] = "CLEANUPFAIL", [GB_METASTATUS_MAX] = NULL, }; typedef enum RemoteCreateResp { GB_BACKEND_RESP = 0, GB_IQN_RESP = 1, GB_TPG_NO_RESP = 2, GB_LUN_NO_RESP = 3, GB_IP_PORT_RESP = 4, GB_PORTAL_RESP = 5, GB_FAILED_RESP = 6, GB_REMOTE_CREATE_RESP_MAX } RemoteCreateResp; static const char *const RemoteCreateRespLookup[] = { [GB_BACKEND_RESP] = "Created user-backed storage object ", [GB_IQN_RESP] = "Created target ", [GB_TPG_NO_RESP] = "Created TPG ", [GB_LUN_NO_RESP] = "Created LUN ", [GB_IP_PORT_RESP] = "Using default IP port ", [GB_PORTAL_RESP] = "Created network portal ", [GB_FAILED_RESP] = "failed to configure on ", [GB_REMOTE_CREATE_RESP_MAX] = NULL, }; int glusterBlockCLIOptEnumParse(const char *opt); int glusterBlockDaemonOptEnumParse(const char *opt); int blockLogLevelEnumParse(const char *opt); int blockMetaKeyEnumParse(const char *opt); int blockMetaStatusEnumParse(const char *opt); int blockRemoteCreateRespEnumParse(const char *opt); void logTimeNow(char* buf, size_t bufSize); int initLogging(void); int gbRunnerExitStatus(int exitStatus); int gbRunner(char *cmd); int gbAlloc(void *ptrptr, size_t size, const char *filename, const char *funcname, size_t linenr); int gbAllocN(void *ptrptr, size_t size, size_t count, const char *filename, const char *funcname, size_t linenr); int gbReallocN(void *ptrptr, size_t size, size_t count, const char *filename, const char *funcname, size_t linenr); int gbStrdup(char **dest, const char *src, const char *filename, const char *funcname, size_t linenr); void gbFree(void *ptrptr); #endif /* _UTILS_H */