#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
-
+#include <limits.h>
/*
* following taken from linux/blkpg.h because they aren't
int parse_layout_faulty(char *layout)
{
+ int ln, mode;
+ char *m;
+
if (!layout)
return -1;
+
/* Parse the layout string for 'faulty' */
- int ln = strcspn(layout, "0123456789");
- char *m = xstrdup(layout);
- int mode;
+ ln = strcspn(layout, "0123456789");
+ m = xstrdup(layout);
m[ln] = 0;
mode = map_name(faultylayout, m);
+ free(m);
+
if (mode == UnSet)
return -1;
}
-char *fname_from_uuid(struct supertype *st, struct mdinfo *info,
- char *buf, char sep)
+/**
+ * fname_from_uuid() - generate uuid string. Should not be used with super1.
+ * @info: info with uuid
+ * @buf: buf to fill.
+ *
+ * This routine should not be used with super1. See detail_fname_from_uuid() for details. It does
+ * not use superswitch swapuuid as it should be 0 but it has to do UUID conversion if host is big
+ * endian- left for backward compatibility.
+ */
+char *fname_from_uuid(struct mdinfo *info, char *buf)
{
- // dirty hack to work around an issue with super1 superblocks...
- // super1 superblocks need swapuuid set in order for assembly to
- // work, but can't have it set if we want this printout to match
- // all the other uuid printouts in super1.c, so we force swapuuid
- // to 1 to make our printout match the rest of super1
#if __BYTE_ORDER == BIG_ENDIAN
- return __fname_from_uuid(info->uuid, 1, buf, sep);
+ return __fname_from_uuid(info->uuid, true, buf, ':');
#else
- return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 :
- st->ss->swapuuid, buf, sep);
+ return __fname_from_uuid(info->uuid, false, buf, ':');
#endif
}
return 1;
}
+/**
+ * ask() - prompt user for "yes/no" dialog.
+ * @mesg: message to be printed, without '?' sign.
+ * Returns: 1 if 'Y/y', 0 otherwise.
+ *
+ * The default value is 'N/n', thus the caps on "N" on prompt.
+ */
int ask(char *mesg)
{
- char *add = "";
- int i;
- for (i = 0; i < 5; i++) {
- char buf[100];
- fprintf(stderr, "%s%s", mesg, add);
- fflush(stderr);
- if (fgets(buf, 100, stdin)==NULL)
- return 0;
- if (buf[0]=='y' || buf[0]=='Y')
- return 1;
- if (buf[0]=='n' || buf[0]=='N')
- return 0;
- add = "(y/n) ";
+ char buf[3] = {0};
+
+ fprintf(stderr, "%s [y/N]? ", mesg);
+ fflush(stderr);
+ if (fgets(buf, 3, stdin) == NULL)
+ return 0;
+ if (strlen(buf) == 1) {
+ pr_err("assuming no.\n");
+ return 0;
}
- pr_err("assuming 'no'\n");
+ if (buf[1] != '\n')
+ goto bad_option;
+ if (toupper(buf[0]) == 'Y')
+ return 1;
+ if (toupper(buf[0]) == 'N')
+ return 0;
+bad_option:
+ pr_err("bad option.\n");
return 0;
}
return 0;
}
+/**
+ * is_devname_numbered() - helper for numbered devname verification.
+ * @devname: path or name to check.
+ * @pref: expected devname prefix.
+ * @pref_len: prefix len.
+ */
+static bool is_devname_numbered(const char *devname, const char *pref, const int pref_len)
+{
+ int val;
+
+ assert(devname && pref);
+
+ if (strncmp(devname, pref, pref_len) != 0)
+ return false;
+
+ if (parse_num(&val, devname + pref_len) != 0)
+ return false;
+
+ if (val > 127)
+ return false;
+
+ return true;
+}
+
+/**
+ * is_devname_md_numbered() - check if &devname is numbered MD device (md).
+ * @devname: path or name to check.
+ */
+bool is_devname_md_numbered(const char *devname)
+{
+ return is_devname_numbered(devname, DEV_NUM_PREF, DEV_NUM_PREF_LEN);
+}
+
+/**
+ * is_devname_md_d_numbered() - check if &devname is secondary numbered MD device (md_d).
+ * @devname: path or name to check.
+ */
+bool is_devname_md_d_numbered(const char *devname)
+{
+ static const char d_dev[] = DEV_NUM_PREF "_d";
+
+ return is_devname_numbered(devname, d_dev, sizeof(d_dev) - 1);
+}
+
/**
* get_md_name() - Get main dev node of the md device.
* @devnm: Md device name or path.
return st;
}
-int dev_size_from_id(dev_t id, unsigned long long *size)
-{
- char buf[20];
- int fd;
-
- sprintf(buf, "%d:%d", major(id), minor(id));
- fd = dev_open(buf, O_RDONLY);
- if (fd < 0)
- return 0;
- if (get_dev_size(fd, NULL, size)) {
- close(fd);
- return 1;
- }
- close(fd);
- return 0;
-}
-
-int dev_sector_size_from_id(dev_t id, unsigned int *size)
-{
- char buf[20];
- int fd;
-
- sprintf(buf, "%d:%d", major(id), minor(id));
- fd = dev_open(buf, O_RDONLY);
- if (fd < 0)
- return 0;
- if (get_dev_sector_size(fd, NULL, size)) {
- close(fd);
- return 1;
- }
- close(fd);
- return 0;
-}
-
struct supertype *dup_super(struct supertype *orig)
{
struct supertype *st;
/* Remove the disk given by 'info' from the array */
if (st->ss->external)
- rv = sysfs_set_str(sra, info, "slot", "none");
+ rv = sysfs_set_str(sra, info, "slot", STR_COMMON_NONE);
else
rv = ioctl(mdfd, HOT_REMOVE_DISK, makedev(info->disk.major,
info->disk.minor));
int rv;
if (st->ss->external)
- return sysfs_set_array(info, 9003);
-
+ return sysfs_set_array(info);
+
memset(&inf, 0, sizeof(inf));
inf.major_version = info->array.major_version;
inf.minor_version = info->array.minor_version;
int len;
pid_t pid;
int status;
+ char *prefix = in_initrd() ? "initrd-" : "";
char pathbuf[1024];
char *paths[4] = {
pathbuf,
if (check_env("MDADM_NO_MDMON"))
return 0;
- if (continue_via_systemd(devnm, MDMON_SERVICE))
+ if (continue_via_systemd(devnm, MDMON_SERVICE, prefix))
return 0;
/* That failed, try running mdmon directly */
unsigned int __invalid_size_argument_for_IOC = 0;
#endif
+/**
+ * disk_fd_matches_criteria() - check if device matches spare criteria.
+ * @st: supertype, not NULL.
+ * @disk_fd: file descriptor of the disk.
+ * @sc: criteria to test.
+ *
+ * Return: true if disk matches criteria, false otherwise.
+ */
+bool disk_fd_matches_criteria(struct supertype *st, int disk_fd, struct spare_criteria *sc)
+{
+ unsigned int dev_sector_size = 0;
+ unsigned long long dev_size = 0;
+
+ if (!sc->criteria_set)
+ return true;
+
+ if (!get_dev_size(disk_fd, NULL, &dev_size) || dev_size < sc->min_size)
+ return false;
+
+ if (!get_dev_sector_size(disk_fd, NULL, &dev_sector_size) ||
+ sc->sector_size != dev_sector_size)
+ return false;
+
+ if (drive_test_and_add_policies(st, &sc->pols, disk_fd, 0))
+ return false;
+
+ return true;
+}
+
+/**
+ * devid_matches_criteria() - check if device referenced by devid matches spare criteria.
+ * @st: supertype, not NULL.
+ * @devid: devid of the device to check.
+ * @sc: criteria to test.
+ *
+ * Return: true if disk matches criteria, false otherwise.
+ */
+bool devid_matches_criteria(struct supertype *st, dev_t devid, struct spare_criteria *sc)
+{
+ char buf[NAME_MAX];
+ bool ret;
+ int fd;
+
+ if (!sc->criteria_set)
+ return true;
+
+ snprintf(buf, NAME_MAX, "%d:%d", major(devid), minor(devid));
+
+ fd = dev_open(buf, O_RDONLY);
+ if (!is_fd_valid(fd))
+ return false;
+
+ /* Error code inherited */
+ ret = disk_fd_matches_criteria(st, fd, sc);
+
+ close(fd);
+ return ret;
+}
+
/* Pick all spares matching given criteria from a container
* if min_size == 0 do not check size
* if domlist == NULL do not check domains
dp = &disks->devs;
disks->array.spare_disks = 0;
while (*dp) {
- int found = 0;
+ bool found = false;
+
d = *dp;
if (d->disk.state == 0) {
- /* check if size is acceptable */
- unsigned long long dev_size;
- unsigned int dev_sector_size;
- int size_valid = 0;
- int sector_size_valid = 0;
-
dev_t dev = makedev(d->disk.major,d->disk.minor);
- if (!criteria->min_size ||
- (dev_size_from_id(dev, &dev_size) &&
- dev_size >= criteria->min_size))
- size_valid = 1;
-
- if (!criteria->sector_size ||
- (dev_sector_size_from_id(dev, &dev_sector_size) &&
- criteria->sector_size == dev_sector_size))
- sector_size_valid = 1;
-
- found = size_valid && sector_size_valid;
+ found = devid_matches_criteria(st, dev, criteria);
/* check if domain matches */
if (found && domlist) {
pol_add(&pol, pol_domain,
spare_group, NULL);
if (domain_test(domlist, pol, metadata) != 1)
- found = 0;
+ found = false;
+
dev_policy_free(pol);
}
}
* 1- if systemd service has been started
* 0- otherwise
*/
-int continue_via_systemd(char *devnm, char *service_name)
+int continue_via_systemd(char *devnm, char *service_name, char *prefix)
{
int pid, status;
char pathbuf[1024];
case 0:
manage_fork_fds(1);
snprintf(pathbuf, sizeof(pathbuf),
- "%s@%s.service", service_name, devnm);
+ "%s@%s%s.service", service_name, prefix ?: "", devnm);
status = execl("/usr/bin/systemctl", "systemctl", "restart",
pathbuf, NULL);
status = execl("/bin/systemctl", "systemctl", "restart",
int in_initrd(void)
{
- /* This is based on similar function in systemd. */
- struct statfs s;
- /* statfs.f_type is signed long on s390x and MIPS, causing all
- sorts of sign extension problems with RAMFS_MAGIC being
- defined as 0x858458f6 */
- return statfs("/", &s) >= 0 &&
- ((unsigned long)s.f_type == TMPFS_MAGIC ||
- ((unsigned long)s.f_type & 0xFFFFFFFFUL) ==
- ((unsigned long)RAMFS_MAGIC & 0xFFFFFFFFUL));
+ return access("/etc/initrd-release", F_OK) >= 0;
}
void reopen_mddev(int mdfd)
}
} while (!wake_after_interrupt && errno == EINTR);
}
+
+/* is_directory() - Checks if directory provided by path is indeed a regular directory.
+ * @path: directory path to be checked
+ *
+ * Doesn't accept symlinks.
+ *
+ * Return: true if is a directory, false if not
+ */
+bool is_directory(const char *path)
+{
+ struct stat st;
+
+ if (lstat(path, &st) != 0) {
+ pr_err("%s: %s\n", strerror(errno), path);
+ return false;
+ }
+
+ if (!S_ISDIR(st.st_mode))
+ return false;
+
+ return true;
+}
+
+/*
+ * is_file() - Checks if file provided by path is indeed a regular file.
+ * @path: file path to be checked
+ *
+ * Doesn't accept symlinks.
+ *
+ * Return: true if is a file, false if not
+ */
+bool is_file(const char *path)
+{
+ struct stat st;
+
+ if (lstat(path, &st) != 0) {
+ pr_err("%s: %s\n", strerror(errno), path);
+ return false;
+ }
+
+ if (!S_ISREG(st.st_mode))
+ return false;
+
+ return true;
+}