util.c (mdadm-4.1) | : | util.c (mdadm-4.2) | ||
---|---|---|---|---|
skipping to change at line 308 | skipping to change at line 308 | |||
} | } | |||
/* | /* | |||
* Get disk info from the kernel. | * Get disk info from the kernel. | |||
*/ | */ | |||
int md_get_disk_info(int fd, struct mdu_disk_info_s *disk) | int md_get_disk_info(int fd, struct mdu_disk_info_s *disk) | |||
{ | { | |||
return ioctl(fd, GET_DISK_INFO, disk); | return ioctl(fd, GET_DISK_INFO, disk); | |||
} | } | |||
/* | ||||
* Parse a 128 bit uuid in 4 integers | ||||
* format is 32 hexx nibbles with options :.<space> separator | ||||
* If not exactly 32 hex digits are found, return 0 | ||||
* else return 1 | ||||
*/ | ||||
int parse_uuid(char *str, int uuid[4]) | ||||
{ | ||||
int hit = 0; /* number of Hex digIT */ | ||||
int i; | ||||
char c; | ||||
for (i = 0; i < 4; i++) | ||||
uuid[i] = 0; | ||||
while ((c = *str++) != 0) { | ||||
int n; | ||||
if (c >= '0' && c <= '9') | ||||
n = c-'0'; | ||||
else if (c >= 'a' && c <= 'f') | ||||
n = 10 + c - 'a'; | ||||
else if (c >= 'A' && c <= 'F') | ||||
n = 10 + c - 'A'; | ||||
else if (strchr(":. -", c)) | ||||
continue; | ||||
else return 0; | ||||
if (hit<32) { | ||||
uuid[hit/8] <<= 4; | ||||
uuid[hit/8] += n; | ||||
} | ||||
hit++; | ||||
} | ||||
if (hit == 32) | ||||
return 1; | ||||
return 0; | ||||
} | ||||
int get_linux_version() | int get_linux_version() | |||
{ | { | |||
struct utsname name; | struct utsname name; | |||
char *cp; | char *cp; | |||
int a = 0, b = 0,c = 0; | int a = 0, b = 0,c = 0; | |||
if (uname(&name) <0) | if (uname(&name) <0) | |||
return -1; | return -1; | |||
cp = name.release; | cp = name.release; | |||
a = strtoul(cp, &cp, 10); | a = strtoul(cp, &cp, 10); | |||
skipping to change at line 391 | skipping to change at line 354 | |||
else | else | |||
c = 0; | c = 0; | |||
if (*cp != ' ' && *cp != '-') | if (*cp != ' ' && *cp != '-') | |||
return -1; | return -1; | |||
return (a*1000000)+(b*1000)+c; | return (a*1000000)+(b*1000)+c; | |||
} | } | |||
unsigned long long parse_size(char *size) | unsigned long long parse_size(char *size) | |||
{ | { | |||
/* parse 'size' which should be a number optionally | /* parse 'size' which should be a number optionally | |||
* followed by 'K', 'M', or 'G'. | * followed by 'K', 'M'. 'G' or 'T'. | |||
* Without a suffix, K is assumed. | * Without a suffix, K is assumed. | |||
* Number returned is in sectors (half-K) | * Number returned is in sectors (half-K) | |||
* INVALID_SECTORS returned on error. | * INVALID_SECTORS returned on error. | |||
*/ | */ | |||
char *c; | char *c; | |||
long long s = strtoll(size, &c, 10); | long long s = strtoll(size, &c, 10); | |||
if (s > 0) { | if (s > 0) { | |||
switch (*c) { | switch (*c) { | |||
case 'K': | case 'K': | |||
c++; | c++; | |||
skipping to change at line 413 | skipping to change at line 376 | |||
s *= 2; | s *= 2; | |||
break; | break; | |||
case 'M': | case 'M': | |||
c++; | c++; | |||
s *= 1024 * 2; | s *= 1024 * 2; | |||
break; | break; | |||
case 'G': | case 'G': | |||
c++; | c++; | |||
s *= 1024 * 1024 * 2; | s *= 1024 * 1024 * 2; | |||
break; | break; | |||
case 'T': | ||||
c++; | ||||
s *= 1024 * 1024 * 1024 * 2LL; | ||||
break; | ||||
case 's': /* sectors */ | case 's': /* sectors */ | |||
c++; | c++; | |||
break; | break; | |||
} | } | |||
} else | } else | |||
s = INVALID_SECTORS; | s = INVALID_SECTORS; | |||
if (*c) | if (*c) | |||
s = INVALID_SECTORS; | s = INVALID_SECTORS; | |||
return s; | return s; | |||
} | } | |||
skipping to change at line 457 | skipping to change at line 424 | |||
rv = 256 + copies; | rv = 256 + copies; | |||
else if (layout[0] == 'o') | else if (layout[0] == 'o') | |||
rv = 0x10000 + (copies<<8) + 1; | rv = 0x10000 + (copies<<8) + 1; | |||
else | else | |||
rv = 1 + (copies<<8); | rv = 1 + (copies<<8); | |||
return rv; | return rv; | |||
} | } | |||
int parse_layout_faulty(char *layout) | int parse_layout_faulty(char *layout) | |||
{ | { | |||
if (!layout) | ||||
return -1; | ||||
/* Parse the layout string for 'faulty' */ | /* Parse the layout string for 'faulty' */ | |||
int ln = strcspn(layout, "0123456789"); | int ln = strcspn(layout, "0123456789"); | |||
char *m = xstrdup(layout); | char *m = xstrdup(layout); | |||
int mode; | int mode; | |||
m[ln] = 0; | m[ln] = 0; | |||
mode = map_name(faultylayout, m); | mode = map_name(faultylayout, m); | |||
if (mode == UnSet) | if (mode == UnSet) | |||
return -1; | return -1; | |||
return mode | (atoi(layout+ln)<< ModeShift); | return mode | (atoi(layout+ln)<< ModeShift); | |||
} | } | |||
long parse_num(char *num) | ||||
{ | ||||
/* Either return a valid number, or -1 */ | ||||
char *c; | ||||
long rv = strtol(num, &c, 10); | ||||
if (rv < 0 || *c || !num[0]) | ||||
return -1; | ||||
else | ||||
return rv; | ||||
} | ||||
int parse_cluster_confirm_arg(char *input, char **devname, int *slot) | int parse_cluster_confirm_arg(char *input, char **devname, int *slot) | |||
{ | { | |||
char *dev; | char *dev; | |||
*slot = strtoul(input, &dev, 10); | *slot = strtoul(input, &dev, 10); | |||
if (dev == input || dev[0] != ':') | if (dev == input || dev[0] != ':') | |||
return -1; | return -1; | |||
*devname = dev+1; | *devname = dev+1; | |||
return 0; | return 0; | |||
} | } | |||
skipping to change at line 609 | skipping to change at line 567 | |||
case 6: | case 6: | |||
if (clean) | if (clean) | |||
return avail_disks >= raid_disks-2; | return avail_disks >= raid_disks-2; | |||
else | else | |||
return avail_disks >= raid_disks; | return avail_disks >= raid_disks; | |||
default: | default: | |||
return 0; | return 0; | |||
} | } | |||
} | } | |||
const int uuid_zero[4] = { 0, 0, 0, 0 }; | ||||
int same_uuid(int a[4], int b[4], int swapuuid) | ||||
{ | ||||
if (swapuuid) { | ||||
/* parse uuids are hostendian. | ||||
* uuid's from some superblocks are big-ending | ||||
* if there is a difference, we need to swap.. | ||||
*/ | ||||
unsigned char *ac = (unsigned char *)a; | ||||
unsigned char *bc = (unsigned char *)b; | ||||
int i; | ||||
for (i = 0; i < 16; i += 4) { | ||||
if (ac[i+0] != bc[i+3] || | ||||
ac[i+1] != bc[i+2] || | ||||
ac[i+2] != bc[i+1] || | ||||
ac[i+3] != bc[i+0]) | ||||
return 0; | ||||
} | ||||
return 1; | ||||
} else { | ||||
if (a[0]==b[0] && | ||||
a[1]==b[1] && | ||||
a[2]==b[2] && | ||||
a[3]==b[3]) | ||||
return 1; | ||||
return 0; | ||||
} | ||||
} | ||||
void copy_uuid(void *a, int b[4], int swapuuid) | ||||
{ | ||||
if (swapuuid) { | ||||
/* parse uuids are hostendian. | ||||
* uuid's from some superblocks are big-ending | ||||
* if there is a difference, we need to swap.. | ||||
*/ | ||||
unsigned char *ac = (unsigned char *)a; | ||||
unsigned char *bc = (unsigned char *)b; | ||||
int i; | ||||
for (i = 0; i < 16; i += 4) { | ||||
ac[i+0] = bc[i+3]; | ||||
ac[i+1] = bc[i+2]; | ||||
ac[i+2] = bc[i+1]; | ||||
ac[i+3] = bc[i+0]; | ||||
} | ||||
} else | ||||
memcpy(a, b, 16); | ||||
} | ||||
char *__fname_from_uuid(int id[4], int swap, char *buf, char sep) | char *__fname_from_uuid(int id[4], int swap, char *buf, char sep) | |||
{ | { | |||
int i, j; | int i, j; | |||
char uuid[16]; | char uuid[16]; | |||
char *c = buf; | char *c = buf; | |||
strcpy(c, "UUID-"); | strcpy(c, "UUID-"); | |||
c += strlen(c); | c += strlen(c); | |||
copy_uuid(uuid, id, swap); | copy_uuid(uuid, id, swap); | |||
for (i = 0; i < 4; i++) { | for (i = 0; i < 4; i++) { | |||
if (i) | if (i) | |||
skipping to change at line 687 | skipping to change at line 595 | |||
} | } | |||
char *fname_from_uuid(struct supertype *st, struct mdinfo *info, | char *fname_from_uuid(struct supertype *st, struct mdinfo *info, | |||
char *buf, char sep) | char *buf, char sep) | |||
{ | { | |||
// dirty hack to work around an issue with super1 superblocks... | // dirty hack to work around an issue with super1 superblocks... | |||
// super1 superblocks need swapuuid set in order for assembly to | // super1 superblocks need swapuuid set in order for assembly to | |||
// work, but can't have it set if we want this printout to match | // 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 | // all the other uuid printouts in super1.c, so we force swapuuid | |||
// to 1 to make our printout match the rest of super1 | // 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); | ||||
#else | ||||
return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 : | return __fname_from_uuid(info->uuid, (st->ss == &super1) ? 1 : | |||
st->ss->swapuuid, buf, sep); | st->ss->swapuuid, buf, sep); | |||
#endif | ||||
} | } | |||
int check_ext2(int fd, char *name) | int check_ext2(int fd, char *name) | |||
{ | { | |||
/* | /* | |||
* Check for an ext2fs file system. | * Check for an ext2fs file system. | |||
* Superblock is always 1K at 1K offset | * Superblock is always 1K at 1K offset | |||
* | * | |||
* s_magic is le16 at 56 == 0xEF53 | * s_magic is le16 at 56 == 0xEF53 | |||
* report mtime - le32 at 44 | * report mtime - le32 at 44 | |||
skipping to change at line 891 | skipping to change at line 803 | |||
csum = (csum & 0xffff) + (csum >> 16); | csum = (csum & 0xffff) + (csum >> 16); | |||
csum = (csum & 0xffff) + (csum >> 16); | csum = (csum & 0xffff) + (csum >> 16); | |||
#endif | #endif | |||
return csum; | return csum; | |||
} | } | |||
char *human_size(long long bytes) | char *human_size(long long bytes) | |||
{ | { | |||
static char buf[47]; | static char buf[47]; | |||
/* We convert bytes to either centi-M{ega,ibi}bytes or | /* We convert bytes to either centi-M{ega,ibi}bytes, | |||
* centi-G{igi,ibi}bytes, with appropriate rounding, | * centi-G{igi,ibi}bytes or centi-T{era,ebi}bytes | |||
* and then print 1/100th of those as a decimal. | * with appropriate rounding, and then print | |||
* 1/100th of those as a decimal. | ||||
* We allow upto 2048Megabytes before converting to | * We allow upto 2048Megabytes before converting to | |||
* gigabytes, as that shows more precision and isn't | * gigabytes and 2048Gigabytes before converting to | |||
* terabytes, as that shows more precision and isn't | ||||
* too large a number. | * too large a number. | |||
* Terabytes are not yet handled. | ||||
*/ | */ | |||
if (bytes < 5000*1024) | if (bytes < 5000*1024) | |||
buf[0] = 0; | buf[0] = 0; | |||
else if (bytes < 2*1024LL*1024LL*1024LL) { | else if (bytes < 2*1024LL*1024LL*1024LL) { | |||
long cMiB = (bytes * 200LL / (1LL<<20) + 1) / 2; | long cMiB = (bytes * 200LL / (1LL<<20) + 1) / 2; | |||
long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2; | long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2; | |||
snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)", | snprintf(buf, sizeof(buf), " (%ld.%02ld MiB %ld.%02ld MB)", | |||
cMiB/100, cMiB % 100, cMB/100, cMB % 100); | cMiB/100, cMiB % 100, cMB/100, cMB % 100); | |||
} else { | } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) { | |||
long cGiB = (bytes * 200LL / (1LL<<30) +1) / 2; | long cGiB = (bytes * 200LL / (1LL<<30) +1) / 2; | |||
long cGB = (bytes / (1000000000LL/200LL ) +1) /2; | long cGB = (bytes / (1000000000LL/200LL ) +1) /2; | |||
snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)", | snprintf(buf, sizeof(buf), " (%ld.%02ld GiB %ld.%02ld GB)", | |||
cGiB/100, cGiB % 100, cGB/100, cGB % 100); | cGiB/100, cGiB % 100, cGB/100, cGB % 100); | |||
} else { | ||||
long cTiB = (bytes * 200LL / (1LL<<40) + 1) / 2; | ||||
long cTB = (bytes / (1000000000000LL / 200LL) + 1) / 2; | ||||
snprintf(buf, sizeof(buf), " (%ld.%02ld TiB %ld.%02ld TB)", | ||||
cTiB/100, cTiB % 100, cTB/100, cTB % 100); | ||||
} | } | |||
return buf; | return buf; | |||
} | } | |||
char *human_size_brief(long long bytes, int prefix) | char *human_size_brief(long long bytes, int prefix) | |||
{ | { | |||
static char buf[30]; | static char buf[30]; | |||
/* We convert bytes to either centi-M{ega,ibi}bytes or | /* We convert bytes to either centi-M{ega,ibi}bytes, | |||
* centi-G{igi,ibi}bytes, with appropriate rounding, | * centi-G{igi,ibi}bytes or centi-T{era,ebi}bytes | |||
* and then print 1/100th of those as a decimal. | * with appropriate rounding, and then print | |||
* 1/100th of those as a decimal. | ||||
* We allow upto 2048Megabytes before converting to | * We allow upto 2048Megabytes before converting to | |||
* gigabytes, as that shows more precision and isn't | * gigabytes and 2048Gigabytes before converting to | |||
* terabytes, as that shows more precision and isn't | ||||
* too large a number. | * too large a number. | |||
* Terabytes are not yet handled. | ||||
* | * | |||
* If prefix == IEC, we mean prefixes like kibi,mebi,gibi etc. | * If prefix == IEC, we mean prefixes like kibi,mebi,gibi etc. | |||
* If prefix == JEDEC, we mean prefixes like kilo,mega,giga etc. | * If prefix == JEDEC, we mean prefixes like kilo,mega,giga etc. | |||
*/ | */ | |||
if (bytes < 5000*1024) | if (bytes < 5000*1024) | |||
buf[0] = 0; | buf[0] = 0; | |||
else if (prefix == IEC) { | else if (prefix == IEC) { | |||
if (bytes < 2*1024LL*1024LL*1024LL) { | if (bytes < 2*1024LL*1024LL*1024LL) { | |||
long cMiB = (bytes * 200LL / (1LL<<20) +1) /2; | long cMiB = (bytes * 200LL / (1LL<<20) +1) /2; | |||
snprintf(buf, sizeof(buf), "%ld.%02ldMiB", | snprintf(buf, sizeof(buf), "%ld.%02ldMiB", | |||
cMiB/100, cMiB % 100); | cMiB/100, cMiB % 100); | |||
} else { | } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) { | |||
long cGiB = (bytes * 200LL / (1LL<<30) +1) /2; | long cGiB = (bytes * 200LL / (1LL<<30) +1) /2; | |||
snprintf(buf, sizeof(buf), "%ld.%02ldGiB", | snprintf(buf, sizeof(buf), "%ld.%02ldGiB", | |||
cGiB/100, cGiB % 100); | cGiB/100, cGiB % 100); | |||
} else { | ||||
long cTiB = (bytes * 200LL / (1LL<<40) + 1) / 2; | ||||
snprintf(buf, sizeof(buf), "%ld.%02ldTiB", | ||||
cTiB/100, cTiB % 100); | ||||
} | } | |||
} | } | |||
else if (prefix == JEDEC) { | else if (prefix == JEDEC) { | |||
if (bytes < 2*1024LL*1024LL*1024LL) { | if (bytes < 2*1024LL*1024LL*1024LL) { | |||
long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2; | long cMB = (bytes / ( 1000000LL / 200LL ) +1) /2; | |||
snprintf(buf, sizeof(buf), "%ld.%02ldMB", | snprintf(buf, sizeof(buf), "%ld.%02ldMB", | |||
cMB/100, cMB % 100); | cMB/100, cMB % 100); | |||
} else { | } else if (bytes < 2*1024LL*1024LL*1024LL*1024LL) { | |||
long cGB = (bytes / (1000000000LL/200LL ) +1) /2; | long cGB = (bytes / (1000000000LL/200LL ) +1) /2; | |||
snprintf(buf, sizeof(buf), "%ld.%02ldGB", | snprintf(buf, sizeof(buf), "%ld.%02ldGB", | |||
cGB/100, cGB % 100); | cGB/100, cGB % 100); | |||
} else { | ||||
long cTB = (bytes / (1000000000000LL / 200LL) + 1) / 2; | ||||
snprintf(buf, sizeof(buf), "%ld.%02ldTB", | ||||
cTB/100, cTB % 100); | ||||
} | } | |||
} | } | |||
else | else | |||
buf[0] = 0; | buf[0] = 0; | |||
return buf; | return buf; | |||
} | } | |||
void print_r10_layout(int layout) | void print_r10_layout(int layout) | |||
{ | { | |||
skipping to change at line 1013 | skipping to change at line 940 | |||
} | } | |||
return data_disks; | return data_disks; | |||
} | } | |||
dev_t devnm2devid(char *devnm) | dev_t devnm2devid(char *devnm) | |||
{ | { | |||
/* First look in /sys/block/$DEVNM/dev for %d:%d | /* First look in /sys/block/$DEVNM/dev for %d:%d | |||
* If that fails, try parsing out a number | * If that fails, try parsing out a number | |||
*/ | */ | |||
char path[100]; | char path[PATH_MAX]; | |||
char *ep; | char *ep; | |||
int fd; | int fd; | |||
int mjr,mnr; | int mjr,mnr; | |||
sprintf(path, "/sys/block/%s/dev", devnm); | snprintf(path, sizeof(path), "/sys/block/%s/dev", devnm); | |||
fd = open(path, O_RDONLY); | fd = open(path, O_RDONLY); | |||
if (fd >= 0) { | if (fd >= 0) { | |||
char buf[20]; | char buf[20]; | |||
int n = read(fd, buf, sizeof(buf)); | int n = read(fd, buf, sizeof(buf)); | |||
close(fd); | close(fd); | |||
if (n > 0) | if (n > 0) | |||
buf[n] = 0; | buf[n] = 0; | |||
if (n > 0 && sscanf(buf, "%d:%d\n", &mjr, &mnr) == 2) | if (n > 0 && sscanf(buf, "%d:%d\n", &mjr, &mnr) == 2) | |||
return makedev(mjr, mnr); | return makedev(mjr, mnr); | |||
} | } | |||
skipping to change at line 1609 | skipping to change at line 1536 | |||
} | } | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
int open_container(int fd) | int open_container(int fd) | |||
{ | { | |||
/* 'fd' is a block device. Find out if it is in use | /* 'fd' is a block device. Find out if it is in use | |||
* by a container, and return an open fd on that container. | * by a container, and return an open fd on that container. | |||
*/ | */ | |||
char path[256]; | char path[288]; | |||
char *e; | char *e; | |||
DIR *dir; | DIR *dir; | |||
struct dirent *de; | struct dirent *de; | |||
int dfd, n; | int dfd, n; | |||
char buf[200]; | char buf[200]; | |||
int major, minor; | int major, minor; | |||
struct stat st; | struct stat st; | |||
if (fstat(fd, &st) != 0) | if (fstat(fd, &st) != 0) | |||
return -1; | return -1; | |||
skipping to change at line 1981 | skipping to change at line 1908 | |||
int pid = mdmon_pid(devnm); | int pid = mdmon_pid(devnm); | |||
if (pid <= 0) | if (pid <= 0) | |||
return 0; | return 0; | |||
if (kill(pid, 0) == 0) | if (kill(pid, 0) == 0) | |||
return 1; | return 1; | |||
return 0; | return 0; | |||
} | } | |||
int start_mdmon(char *devnm) | int start_mdmon(char *devnm) | |||
{ | { | |||
int i, skipped; | int i; | |||
int len; | int len; | |||
pid_t pid; | pid_t pid; | |||
int status; | int status; | |||
char pathbuf[1024]; | char pathbuf[1024]; | |||
char *paths[4] = { | char *paths[4] = { | |||
pathbuf, | pathbuf, | |||
BINDIR "/mdmon", | BINDIR "/mdmon", | |||
"./mdmon", | "./mdmon", | |||
NULL | NULL | |||
}; | }; | |||
if (check_env("MDADM_NO_MDMON")) | if (check_env("MDADM_NO_MDMON")) | |||
return 0; | return 0; | |||
if (continue_via_systemd(devnm, MDMON_SERVICE)) | ||||
return 0; | ||||
/* That failed, try running mdmon directly */ | ||||
len = readlink("/proc/self/exe", pathbuf, sizeof(pathbuf)-1); | len = readlink("/proc/self/exe", pathbuf, sizeof(pathbuf)-1); | |||
if (len > 0) { | if (len > 0) { | |||
char *sl; | char *sl; | |||
pathbuf[len] = 0; | pathbuf[len] = 0; | |||
sl = strrchr(pathbuf, '/'); | sl = strrchr(pathbuf, '/'); | |||
if (sl) | if (sl) | |||
sl++; | sl++; | |||
else | else | |||
sl = pathbuf; | sl = pathbuf; | |||
strcpy(sl, "mdmon"); | strcpy(sl, "mdmon"); | |||
} else | } else | |||
pathbuf[0] = '\0'; | pathbuf[0] = '\0'; | |||
/* First try to run systemctl */ | ||||
if (!check_env("MDADM_NO_SYSTEMCTL")) | ||||
switch(fork()) { | ||||
case 0: | ||||
/* FIXME yuk. CLOSE_EXEC?? */ | ||||
skipped = 0; | ||||
for (i = 3; skipped < 20; i++) | ||||
if (close(i) < 0) | ||||
skipped++; | ||||
else | ||||
skipped = 0; | ||||
/* Don't want to see error messages from | ||||
* systemctl. If the service doesn't exist, | ||||
* we start mdmon ourselves. | ||||
*/ | ||||
close(2); | ||||
open("/dev/null", O_WRONLY); | ||||
snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service", | ||||
devnm); | ||||
status = execl("/usr/bin/systemctl", "systemctl", | ||||
"start", | ||||
pathbuf, NULL); | ||||
status = execl("/bin/systemctl", "systemctl", "start", | ||||
pathbuf, NULL); | ||||
exit(1); | ||||
case -1: pr_err("cannot run mdmon. Array remains readonly\n"); | ||||
return -1; | ||||
default: /* parent - good */ | ||||
pid = wait(&status); | ||||
if (pid >= 0 && status == 0) | ||||
return 0; | ||||
} | ||||
/* That failed, try running mdmon directly */ | ||||
switch(fork()) { | switch(fork()) { | |||
case 0: | case 0: | |||
/* FIXME yuk. CLOSE_EXEC?? */ | manage_fork_fds(1); | |||
skipped = 0; | ||||
for (i = 3; skipped < 20; i++) | ||||
if (close(i) < 0) | ||||
skipped++; | ||||
else | ||||
skipped = 0; | ||||
for (i = 0; paths[i]; i++) | for (i = 0; paths[i]; i++) | |||
if (paths[i][0]) { | if (paths[i][0]) { | |||
execl(paths[i], paths[i], | execl(paths[i], paths[i], | |||
devnm, NULL); | devnm, NULL); | |||
} | } | |||
exit(1); | exit(1); | |||
case -1: pr_err("cannot run mdmon. Array remains readonly\n"); | case -1: pr_err("cannot run mdmon. Array remains readonly\n"); | |||
return -1; | return -1; | |||
default: /* parent - good */ | default: /* parent - good */ | |||
pid = wait(&status); | pid = wait(&status); | |||
skipping to change at line 2258 | skipping to change at line 2146 | |||
unsigned int fds = 20 + devices; | unsigned int fds = 20 + devices; | |||
struct rlimit lim; | struct rlimit lim; | |||
if (getrlimit(RLIMIT_NOFILE, &lim) != 0 || lim.rlim_cur >= fds) | if (getrlimit(RLIMIT_NOFILE, &lim) != 0 || lim.rlim_cur >= fds) | |||
return; | return; | |||
if (lim.rlim_max < fds) | if (lim.rlim_max < fds) | |||
lim.rlim_max = fds; | lim.rlim_max = fds; | |||
lim.rlim_cur = fds; | lim.rlim_cur = fds; | |||
setrlimit(RLIMIT_NOFILE, &lim); | setrlimit(RLIMIT_NOFILE, &lim); | |||
} | } | |||
/* Close all opened descriptors if needed and redirect | ||||
* streams to /dev/null. | ||||
* For debug purposed, leave STDOUT and STDERR untouched | ||||
* Returns: | ||||
* 1- if any error occurred | ||||
* 0- otherwise | ||||
*/ | ||||
void manage_fork_fds(int close_all) | ||||
{ | ||||
DIR *dir; | ||||
struct dirent *dirent; | ||||
close(0); | ||||
open("/dev/null", O_RDWR); | ||||
#ifndef DEBUG | ||||
dup2(0, 1); | ||||
dup2(0, 2); | ||||
#endif | ||||
if (close_all == 0) | ||||
return; | ||||
dir = opendir("/proc/self/fd"); | ||||
if (!dir) { | ||||
pr_err("Cannot open /proc/self/fd directory.\n"); | ||||
return; | ||||
} | ||||
for (dirent = readdir(dir); dirent; dirent = readdir(dir)) { | ||||
int fd = -1; | ||||
if ((strcmp(dirent->d_name, ".") == 0) || | ||||
(strcmp(dirent->d_name, "..")) == 0) | ||||
continue; | ||||
fd = strtol(dirent->d_name, NULL, 10); | ||||
if (fd > 2) | ||||
close(fd); | ||||
} | ||||
} | ||||
/* In a systemd/udev world, it is best to get systemd to | ||||
* run daemon rather than running in the background. | ||||
* Returns: | ||||
* 1- if systemd service has been started | ||||
* 0- otherwise | ||||
*/ | ||||
int continue_via_systemd(char *devnm, char *service_name) | ||||
{ | ||||
int pid, status; | ||||
char pathbuf[1024]; | ||||
/* Simply return that service cannot be started */ | ||||
if (check_env("MDADM_NO_SYSTEMCTL")) | ||||
return 0; | ||||
switch (fork()) { | ||||
case 0: | ||||
manage_fork_fds(1); | ||||
snprintf(pathbuf, sizeof(pathbuf), | ||||
"%s@%s.service", service_name, devnm); | ||||
status = execl("/usr/bin/systemctl", "systemctl", "restart", | ||||
pathbuf, NULL); | ||||
status = execl("/bin/systemctl", "systemctl", "restart", | ||||
pathbuf, NULL); | ||||
exit(1); | ||||
case -1: /* Just do it ourselves. */ | ||||
break; | ||||
default: /* parent - good */ | ||||
pid = wait(&status); | ||||
if (pid >= 0 && status == 0) | ||||
return 1; | ||||
} | ||||
return 0; | ||||
} | ||||
int in_initrd(void) | int in_initrd(void) | |||
{ | { | |||
/* This is based on similar function in systemd. */ | /* This is based on similar function in systemd. */ | |||
struct statfs s; | struct statfs s; | |||
/* statfs.f_type is signed long on s390x and MIPS, causing all | /* statfs.f_type is signed long on s390x and MIPS, causing all | |||
sorts of sign extension problems with RAMFS_MAGIC being | sorts of sign extension problems with RAMFS_MAGIC being | |||
defined as 0x858458f6 */ | defined as 0x858458f6 */ | |||
return statfs("/", &s) >= 0 && | return statfs("/", &s) >= 0 && | |||
((unsigned long)s.f_type == TMPFS_MAGIC || | ((unsigned long)s.f_type == TMPFS_MAGIC || | |||
((unsigned long)s.f_type & 0xFFFFFFFFUL) == | ((unsigned long)s.f_type & 0xFFFFFFFFUL) == | |||
End of changes. 29 change blocks. | ||||
159 lines changed or deleted | 122 lines changed or added |