diff options
Diffstat (limited to '')
-rw-r--r-- | util.c | 253 |
1 files changed, 152 insertions, 101 deletions
@@ -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, §or_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; |