summaryrefslogtreecommitdiffstats
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--util.c253
1 files changed, 152 insertions, 101 deletions
diff --git a/util.c b/util.c
index 9e83704..a120c98 100644
--- a/util.c
+++ b/util.c
@@ -24,6 +24,8 @@
#include "mdadm.h"
#include "md_p.h"
+#include "xmalloc.h"
+
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/wait.h>
@@ -513,6 +515,9 @@ int enough(int level, int raid_disks, int layout, int clean, char *avail)
int i;
int avail_disks = 0;
+ if (raid_disks <= 0)
+ return 0;
+
for (i = 0; i < raid_disks; i++)
avail_disks += !!avail[i];
@@ -521,7 +526,7 @@ int enough(int level, int raid_disks, int layout, int clean, char *avail)
/* This is the tricky one - we need to check
* which actual disks are present.
*/
- copies = (layout&255)* ((layout>>8) & 255);
+ copies = (layout & 255) * ((layout >> 8) & 255);
first = 0;
do {
/* there must be one of the 'copies' form 'first' */
@@ -531,16 +536,16 @@ int enough(int level, int raid_disks, int layout, int clean, char *avail)
while (n--) {
if (avail[this])
cnt++;
- this = (this+1) % raid_disks;
+ this = (this + 1) % raid_disks;
}
if (cnt == 0)
return 0;
- first = (first+(layout&255)) % raid_disks;
+ first = (first + (layout & 255)) % raid_disks;
} while (first != 0);
return 1;
case LEVEL_MULTIPATH:
- return avail_disks>= 1;
+ return avail_disks >= 1;
case LEVEL_LINEAR:
case 0:
return avail_disks == raid_disks;
@@ -556,12 +561,12 @@ int enough(int level, int raid_disks, int layout, int clean, char *avail)
/* FALL THROUGH */
case 5:
if (clean)
- return avail_disks >= raid_disks-1;
+ return avail_disks >= raid_disks - 1;
else
return avail_disks >= raid_disks;
case 6:
if (clean)
- return avail_disks >= raid_disks-2;
+ return avail_disks >= raid_disks - 2;
else
return avail_disks >= raid_disks;
default:
@@ -633,9 +638,9 @@ int check_ext2(int fd, char *name)
bsize = sb[24]|(sb[25]|(sb[26]|sb[27]<<8)<<8)<<8;
size = sb[4]|(sb[5]|(sb[6]|sb[7]<<8)<<8)<<8;
size <<= bsize;
- pr_err("%s appears to contain an ext2fs file system\n",
+ pr_info("%s appears to contain an ext2fs file system\n",
name);
- cont_err("size=%lluK mtime=%s", size, ctime(&mtime));
+ pr_info("size=%lluK mtime=%s", size, ctime(&mtime));
return 1;
}
@@ -725,60 +730,34 @@ int stat_is_blkdev(char *devname, dev_t *rdev)
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) ";
- }
- pr_err("assuming 'no'\n");
- return 0;
-}
+ char buf[3] = {0};
-int is_standard(char *dev, int *nump)
-{
- /* tests if dev is a "standard" md dev name.
- * i.e if the last component is "/dNN" or "/mdNN",
- * where NN is a string of digits
- * Returns 1 if a partitionable standard,
- * -1 if non-partitonable,
- * 0 if not a standard name.
- */
- char *d = strrchr(dev, '/');
- int type = 0;
- int num;
- if (!d)
+ fprintf(stderr, "%s [y/N]? ", mesg);
+ fflush(stderr);
+ if (fgets(buf, 3, stdin) == NULL)
return 0;
- if (strncmp(d, "/d",2) == 0)
- d += 2, type = 1; /* /dev/md/dN{pM} */
- else if (strncmp(d, "/md_d", 5) == 0)
- d += 5, type = 1; /* /dev/md_dN{pM} */
- else if (strncmp(d, "/md", 3) == 0)
- d += 3, type = -1; /* /dev/mdN */
- else if (d-dev > 3 && strncmp(d-2, "md/", 3) == 0)
- d += 1, type = -1; /* /dev/md/N */
- else
- return 0;
- if (!*d)
+ if (strlen(buf) == 1) {
+ pr_err("assuming no.\n");
return 0;
- num = atoi(d);
- while (isdigit(*d))
- d++;
- if (*d)
+ }
+ if (buf[1] != '\n')
+ goto bad_option;
+ if (toupper(buf[0]) == 'Y')
+ return 1;
+ if (toupper(buf[0]) == 'N')
return 0;
- if (nump) *nump = num;
-
- return type;
+bad_option:
+ pr_err("bad option.\n");
+ return 0;
}
unsigned long calc_csum(void *super, int bytes)
@@ -993,7 +972,7 @@ static bool is_devname_numbered(const char *devname, const char *pref, const int
if (parse_num(&val, devname + pref_len) != 0)
return false;
- if (val > 127)
+ if (val > 1024)
return false;
return true;
@@ -1096,17 +1075,6 @@ int dev_open(char *dev, int flags)
fd = open(devname, flags);
unlink(devname);
}
- if (fd < 0) {
- /* Try /tmp as /dev appear to be read-only */
- snprintf(devname, sizeof(devname),
- "/tmp/.tmp.md.%d:%d:%d",
- (int)getpid(), major, minor);
- if (mknod(devname, S_IFBLK|0600,
- makedev(major, minor)) == 0) {
- fd = open(devname, flags);
- unlink(devname);
- }
- }
} else
fd = open(dev, flags);
return fd;
@@ -1243,7 +1211,7 @@ struct supertype *super_by_fd(int fd, char **subarrayp)
*subarray++ = '\0';
subarray = xstrdup(subarray);
}
- strcpy(container, dev);
+ snprintf(container, sizeof(container), "%s", dev);
sysfs_free(sra);
sra = sysfs_read(-1, container, GET_VERSION);
if (sra && sra->text_version[0])
@@ -1420,7 +1388,8 @@ static int get_gpt_last_partition_end(int fd, unsigned long long *endofpart)
/* skip protective MBR */
if (!get_dev_sector_size(fd, NULL, &sector_size))
return 0;
- lseek(fd, sector_size, SEEK_SET);
+ if (lseek(fd, sector_size, SEEK_SET) == -1L)
+ return 0;
/* read GPT header */
if (read(fd, &gpt, 512) != 512)
return 0;
@@ -1441,7 +1410,8 @@ static int get_gpt_last_partition_end(int fd, unsigned long long *endofpart)
part = (struct GPT_part_entry *)buf;
/* set offset to third block (GPT entries) */
- lseek(fd, sector_size*2, SEEK_SET);
+ if (lseek(fd, sector_size*2, SEEK_SET) == -1L)
+ return 0;
for (part_nr = 0; part_nr < all_partitions; part_nr++) {
/* read partition entry */
if (read(fd, buf, entry_size) != (ssize_t)entry_size)
@@ -1476,7 +1446,8 @@ static int get_last_partition_end(int fd, unsigned long long *endofpart)
BUILD_BUG_ON(sizeof(boot_sect) != 512);
/* read MBR */
- lseek(fd, 0, 0);
+ if (lseek(fd, 0, 0) == -1L)
+ goto abort;
if (read(fd, &boot_sect, 512) != 512)
goto abort;
@@ -1661,16 +1632,6 @@ int metadata_subdev_matches(char *metadata, char *devnm)
return 0;
}
-int is_container_member(struct mdstat_ent *mdstat, char *container)
-{
- if (mdstat->metadata_version == NULL ||
- strncmp(mdstat->metadata_version, "external:", 9) != 0 ||
- !metadata_container_matches(mdstat->metadata_version+9, container))
- return 0;
-
- return 1;
-}
-
int is_subarray_active(char *subarray, char *container)
{
struct mdstat_ent *mdstat = mdstat_read(0, 0);
@@ -1715,7 +1676,7 @@ int open_subarray(char *dev, char *subarray, struct supertype *st, int quiet)
dev);
goto close_fd;
}
- strcpy(st->devnm, _devnm);
+ snprintf(st->devnm, sizeof(st->devnm), "%s", _devnm);
mdi = sysfs_read(fd, st->devnm, GET_VERSION|GET_LEVEL);
if (!mdi) {
@@ -1847,14 +1808,23 @@ int hot_remove_disk(int mdfd, unsigned long dev, int force)
int sys_hot_remove_disk(int statefd, int force)
{
+ static const char val[] = "remove";
int cnt = force ? 500 : 5;
- int ret;
- while ((ret = write(statefd, "remove", 6)) == -1 &&
- errno == EBUSY &&
- cnt-- > 0)
+ while (cnt--) {
+ int err = 0;
+ int ret = sysfs_write_descriptor(statefd, val, strlen(val), &err);
+
+ if (ret == MDADM_STATUS_SUCCESS)
+ return 0;
+
+ if (err != EBUSY)
+ break;
+
sleep_for(0, MSEC_TO_NSEC(10), true);
- return ret == 6 ? 0 : -1;
+ }
+
+ return -1;
}
int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
@@ -1868,6 +1838,7 @@ int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
if (st->ss->external)
return sysfs_set_array(info);
+
memset(&inf, 0, sizeof(inf));
inf.major_version = info->array.major_version;
inf.minor_version = info->array.minor_version;
@@ -1891,7 +1862,7 @@ unsigned long long min_recovery_start(struct mdinfo *array)
return recovery_start;
}
-int mdmon_pid(char *devnm)
+int mdmon_pid(const char *devnm)
{
char path[100];
char pid[10];
@@ -1911,7 +1882,7 @@ int mdmon_pid(char *devnm)
return atoi(pid);
}
-int mdmon_running(char *devnm)
+int mdmon_running(const char *devnm)
{
int pid = mdmon_pid(devnm);
if (pid <= 0)
@@ -1921,6 +1892,80 @@ int mdmon_running(char *devnm)
return 0;
}
+/*
+ * wait_for_mdmon_control_socket() - Waits for mdmon control socket
+ * to be created within specified time.
+ * @container_devnm: Device for which mdmon control socket should start.
+ *
+ * In foreground mode, when mdadm is trying to connect to control
+ * socket it is possible that the mdmon has not created it yet.
+ * Give some time to mdmon to create socket. Timeout set to 2 sec.
+ *
+ * Return: MDADM_STATUS_SUCCESS if connect succeed, otherwise return
+ * error code.
+ */
+mdadm_status_t wait_for_mdmon_control_socket(const char *container_devnm)
+{
+ enum mdadm_status status = MDADM_STATUS_SUCCESS;
+ int sfd, rv, retry_count = 0;
+ struct sockaddr_un addr;
+ char path[PATH_MAX];
+
+ snprintf(path, PATH_MAX, "%s/%s.sock", MDMON_DIR, container_devnm);
+ sfd = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (!is_fd_valid(sfd))
+ return MDADM_STATUS_ERROR;
+
+ addr.sun_family = PF_LOCAL;
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
+ addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
+
+ for (retry_count = 0; retry_count < 10; retry_count++) {
+ rv = connect(sfd, (struct sockaddr*)&addr, sizeof(addr));
+ if (rv < 0) {
+ sleep_for(0, MSEC_TO_NSEC(200), true);
+ continue;
+ }
+ break;
+ }
+
+ if (rv < 0) {
+ pr_err("Failed to connect to control socket.\n");
+ status = MDADM_STATUS_ERROR;
+ }
+ close(sfd);
+ return status;
+}
+
+/*
+ * wait_for_mdmon() - Waits for mdmon within specified time.
+ * @devnm: Device for which mdmon should start.
+ *
+ * Function waits for mdmon to start. It may need few seconds
+ * to start, we set timeout to 5, it should be sufficient.
+ * Do not wait if mdmon has been started.
+ *
+ * Return: MDADM_STATUS_SUCCESS if mdmon is running, error code otherwise.
+ */
+mdadm_status_t wait_for_mdmon(const char *devnm)
+{
+ const time_t mdmon_timeout = 5;
+ time_t start_time = time(0);
+
+ if (mdmon_running(devnm))
+ return MDADM_STATUS_SUCCESS;
+
+ pr_info("Waiting for mdmon to start\n");
+ while (time(0) - start_time < mdmon_timeout) {
+ sleep_for(0, MSEC_TO_NSEC(200), true);
+ if (mdmon_running(devnm))
+ return MDADM_STATUS_SUCCESS;
+ };
+
+ pr_err("Timeout waiting for mdmon\n");
+ return MDADM_STATUS_ERROR;
+}
+
int start_mdmon(char *devnm)
{
int i;
@@ -2218,14 +2263,16 @@ void manage_fork_fds(int close_all)
{
DIR *dir;
struct dirent *dirent;
+ int fd = open("/dev/null", O_RDWR);
- close(0);
- open("/dev/null", O_RDWR);
-
+ if (is_fd_valid(fd)) {
+ dup2(fd, 0);
#ifndef DEBUG
dup2(0, 1);
dup2(0, 2);
+ close_fd(&fd);
#endif
+ }
if (close_all == 0)
return;
@@ -2244,8 +2291,10 @@ void manage_fork_fds(int close_all)
fd = strtol(dirent->d_name, NULL, 10);
if (fd > 2)
- close(fd);
+ close_fd(&fd);
}
+ closedir(dir);
+ return;
}
/* In a systemd/udev world, it is best to get systemd to
@@ -2292,13 +2341,15 @@ void reopen_mddev(int mdfd)
/* Re-open without any O_EXCL, but keep
* the same fd
*/
- char *devnm;
- int fd;
- devnm = fd2devnm(mdfd);
- close(mdfd);
- fd = open_dev(devnm);
- if (fd >= 0 && fd != mdfd)
- dup2(fd, mdfd);
+ char *devnm = fd2devnm(mdfd);
+ int fd = open_dev(devnm);
+
+ if (!is_fd_valid(fd))
+ return;
+
+ dup2(fd, mdfd);
+
+ close_fd(&fd);
}
static struct cmap_hooks *cmap_hooks = NULL;