#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "debug.h" #include "memory.h" #include "checkers.h" #include "vector.h" #include "structs.h" #include "log.h" size_t strchop(char *str) { int i; for (i=strlen(str)-1; i >=0 && isspace(str[i]); --i) ; str[++i] = '\0'; return strlen(str); } int basenamecpy (const char *src, char *dst, size_t size) { const char *p, *e; if (!src || !dst || !strlen(src)) return 0; p = basename(src); for (e = p + strlen(p) - 1; e >= p && isspace(*e); --e) ; if (e < p || (size_t)(e - p) > size - 2) return 0; strlcpy(dst, p, e - p + 2); return strlen(dst); } int filepresent (char * run) { struct stat buf; if(!stat(run, &buf)) return 1; return 0; } char *get_next_string(char **temp, char *split_char) { char *token = NULL; token = strsep(temp, split_char); while (token != NULL && !strcmp(token, "")) token = strsep(temp, split_char); return token; } int get_word (char * sentence, char ** word) { char * p; int len; int skip = 0; if (word) *word = NULL; while (*sentence == ' ') { sentence++; skip++; } if (*sentence == '\0') return 0; p = sentence; while (*p != ' ' && *p != '\0') p++; len = (int) (p - sentence); if (!word) return skip + len; *word = MALLOC(len + 1); if (!*word) { condlog(0, "get_word : oom"); return 0; } strncpy(*word, sentence, len); strchop(*word); condlog(5, "*word = %s, len = %i", *word, len); if (*p == '\0') return 0; return skip + len; } size_t strlcpy(char *dst, const char *src, size_t size) { size_t bytes = 0; char *q = dst; const char *p = src; char ch; while ((ch = *p++)) { if (bytes+1 < size) *q++ = ch; bytes++; } /* If size == 0 there is no space for a final null... */ if (size) *q = '\0'; return bytes; } size_t strlcat(char *dst, const char *src, size_t size) { size_t bytes = 0; char *q = dst; const char *p = src; char ch; while (bytes < size && *q) { q++; bytes++; } if (bytes == size) return (bytes + strlen(src)); while ((ch = *p++)) { if (bytes+1 < size) *q++ = ch; bytes++; } *q = '\0'; return bytes; } int devt2devname(char *devname, int devname_len, char *devt) { FILE *fd; unsigned int tmpmaj, tmpmin, major, minor; char dev[FILE_NAME_SIZE]; char block_path[PATH_SIZE]; struct stat statbuf; memset(block_path, 0, sizeof(block_path)); memset(dev, 0, sizeof(dev)); if (sscanf(devt, "%u:%u", &major, &minor) != 2) { condlog(0, "Invalid device number %s", devt); return 1; } if (devname_len > FILE_NAME_SIZE) devname_len = FILE_NAME_SIZE; if (stat("/sys/dev/block", &statbuf) == 0) { /* Newer kernels have /sys/dev/block */ sprintf(block_path,"/sys/dev/block/%u:%u", major, minor); dev[FILE_NAME_SIZE - 1] = '\0'; if (lstat(block_path, &statbuf) == 0) { if (S_ISLNK(statbuf.st_mode) && readlink(block_path, dev, FILE_NAME_SIZE-1) > 0) { char *p = strrchr(dev, '/'); if (!p) { condlog(0, "No sysfs entry for %s", block_path); return 1; } p++; strlcpy(devname, p, devname_len); return 0; } } condlog(4, "%s is invalid", block_path); return 1; } memset(block_path, 0, sizeof(block_path)); if (!(fd = fopen("/proc/partitions", "r"))) { condlog(0, "Cannot open /proc/partitions"); return 1; } while (!feof(fd)) { int r = fscanf(fd,"%u %u %*d %s",&tmpmaj, &tmpmin, dev); if (!r) { r = fscanf(fd,"%*s\n"); continue; } if (r != 3) continue; if ((major == tmpmaj) && (minor == tmpmin)) { if (safe_sprintf(block_path, "/sys/block/%s", dev)) { condlog(0, "device name %s is too long", dev); fclose(fd); return 1; } break; } } fclose(fd); if (strncmp(block_path,"/sys/block", 10)) { condlog(3, "No device found for %u:%u", major, minor); return 1; } if (stat(block_path, &statbuf) < 0) { condlog(0, "No sysfs entry for %s", block_path); return 1; } if (S_ISDIR(statbuf.st_mode) == 0) { condlog(0, "sysfs entry %s is not a directory", block_path); return 1; } basenamecpy((const char *)block_path, devname, devname_len); return 0; } /* This function returns a pointer inside of the supplied pathname string. * If is_path_device is true, it may also modify the supplied string */ char *convert_dev(char *name, int is_path_device) { char *ptr; if (!name) return NULL; if (is_path_device) { ptr = strstr(name, "cciss/"); if (ptr) { ptr += 5; *ptr = '!'; } } if (!strncmp(name, "/dev/", 5) && strlen(name) > 5) ptr = name + 5; else ptr = name; return ptr; } dev_t parse_devt(const char *dev_t) { int maj, min; if (sscanf(dev_t,"%d:%d", &maj, &min) != 2) return 0; return makedev(maj, min); } void setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached) { int ret; ret = pthread_attr_init(attr); assert(ret == 0); if (stacksize < PTHREAD_STACK_MIN) stacksize = PTHREAD_STACK_MIN; ret = pthread_attr_setstacksize(attr, stacksize); assert(ret == 0); if (detached) { ret = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED); assert(ret == 0); } } int systemd_service_enabled_in(const char *dev, const char *prefix) { char path[PATH_SIZE], file[PATH_MAX], service[PATH_SIZE]; DIR *dirfd; struct dirent *d; int found = 0; snprintf(service, PATH_SIZE, "multipathd.service"); snprintf(path, PATH_SIZE, "%s/systemd/system", prefix); condlog(3, "%s: checking for %s in %s", dev, service, path); dirfd = opendir(path); if (dirfd == NULL) return 0; while ((d = readdir(dirfd)) != NULL) { char *p; struct stat stbuf; if ((strcmp(d->d_name,".") == 0) || (strcmp(d->d_name,"..") == 0)) continue; if (strlen(d->d_name) < 6) continue; p = d->d_name + strlen(d->d_name) - 6; if (strcmp(p, ".wants")) continue; snprintf(file, sizeof(file), "%s/%s/%s", path, d->d_name, service); if (stat(file, &stbuf) == 0) { condlog(3, "%s: found %s", dev, file); found++; break; } } closedir(dirfd); return found; } int systemd_service_enabled(const char *dev) { int found = 0; found = systemd_service_enabled_in(dev, "/etc"); if (!found) found = systemd_service_enabled_in(dev, "/usr/lib"); if (!found) found = systemd_service_enabled_in(dev, "/lib"); if (!found) found = systemd_service_enabled_in(dev, "/run"); return found; } static int _linux_version_code; static pthread_once_t _lvc_initialized = PTHREAD_ONCE_INIT; /* Returns current kernel version encoded as major*65536 + minor*256 + patch, * so, for example, to check if the kernel is greater than 2.2.11: * * if (get_linux_version_code() > KERNEL_VERSION(2,2,11)) { } * * Copyright (C) 1999-2004 by Erik Andersen * Code copied from busybox (GPLv2 or later) */ static void _set_linux_version_code(void) { struct utsname name; char *t; int i, r; uname(&name); /* never fails */ t = name.release; r = 0; for (i = 0; i < 3; i++) { t = strtok(t, "."); r = r * 256 + (t ? atoi(t) : 0); t = NULL; } _linux_version_code = r; } int get_linux_version_code(void) { pthread_once(&_lvc_initialized, _set_linux_version_code); return _linux_version_code; } int parse_prkey(char *ptr, uint64_t *prkey) { if (!ptr) return 1; if (*ptr == '0') ptr++; if (*ptr == 'x' || *ptr == 'X') ptr++; if (*ptr == '\0' || strlen(ptr) > 16) return 1; if (strlen(ptr) != strspn(ptr, "0123456789aAbBcCdDeEfF")) return 1; if (sscanf(ptr, "%" SCNx64 "", prkey) != 1) return 1; return 0; } int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags) { char *flagstr; flagstr = strchr(ptr, ':'); *flags = 0; if (flagstr) { *flagstr++ = '\0'; if (strlen(flagstr) == 5 && strcmp(flagstr, "aptpl") == 0) *flags = MPATH_F_APTPL_MASK; } return parse_prkey(ptr, prkey); } int safe_write(int fd, const void *buf, size_t count) { while (count > 0) { ssize_t r = write(fd, buf, count); if (r < 0) { if (errno == EINTR) continue; return -errno; } count -= r; buf = (const char *)buf + r; } return 0; } void set_max_fds(rlim_t max_fds) { struct rlimit fd_limit; if (!max_fds) return; if (getrlimit(RLIMIT_NOFILE, &fd_limit) < 0) { condlog(0, "can't get open fds limit: %s", strerror(errno)); fd_limit.rlim_cur = 0; fd_limit.rlim_max = 0; } if (fd_limit.rlim_cur < max_fds) { fd_limit.rlim_cur = max_fds; if (fd_limit.rlim_max < max_fds) fd_limit.rlim_max = max_fds; if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0) { condlog(0, "can't set open fds limit to " "%lu/%lu : %s", fd_limit.rlim_cur, fd_limit.rlim_max, strerror(errno)); } else { condlog(3, "set open fds limit to %lu/%lu", fd_limit.rlim_cur, fd_limit.rlim_max); } } } void free_scandir_result(struct scandir_result *res) { int i; for (i = 0; i < res->n; i++) FREE(res->di[i]); FREE(res->di); } void close_fd(void *arg) { close((long)arg); }