summaryrefslogtreecommitdiffstats
path: root/sysfs.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-09 11:40:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-09 11:40:59 +0000
commitad73653d36c9bd59872479e3c41f8942c70945b9 (patch)
treef184315b3ad68109e86aa4bd5bba3de919bfa3e3 /sysfs.c
parentAdding upstream version 4.3+20240723. (diff)
downloadmdadm-ad73653d36c9bd59872479e3c41f8942c70945b9.tar.xz
mdadm-ad73653d36c9bd59872479e3c41f8942c70945b9.zip
Adding upstream version 4.3+20241108.upstream/4.3+20241108upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sysfs.c')
-rw-r--r--sysfs.c96
1 files changed, 80 insertions, 16 deletions
diff --git a/sysfs.c b/sysfs.c
index 20fe1e9..a3bcb43 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -24,9 +24,11 @@
*/
#include "mdadm.h"
+#include "dlink.h"
+#include "xmalloc.h"
+
#include <dirent.h>
#include <ctype.h>
-#include "dlink.h"
#define MAX_SYSFS_PATH_LEN 120
@@ -73,6 +75,47 @@ void sysfs_free(struct mdinfo *sra)
sra = sra2;
}
}
+/**
+ * write_attr() - write value to fd, don't check errno.
+ * @attr: value to write.
+ * @fd: file descriptor write to.
+ *
+ * Size to write is calculated by strlen().
+ */
+mdadm_status_t write_attr(const char *value, const int fd)
+{
+ return sysfs_write_descriptor(fd, value, strlen(value), NULL);
+}
+
+/**
+ * sysfs_write_descriptor()- wrapper for write(), projected to be used with sysfs.
+ * @fd: file descriptor.
+ * @value: value to set.
+ * @len: length of the value.
+ * @errno_p: On write() failure, buffer to copy errno value, might be NULL.
+ *
+ * Errors are differentiated, because (at least theoretically) kernel may not process whole string
+ * and it may or may not be a problem (it depends on implementation in kernel). Decision belongs to
+ * caller then.
+ * Generally, it should be safe to check if @errno_p changed to determine if error occurred.
+ */
+mdadm_status_t sysfs_write_descriptor(const int fd, const char *value, const ssize_t len,
+ int *errno_p)
+{
+ ssize_t ret;
+
+ ret = write(fd, value, len);
+ if (ret == -1) {
+ if (errno_p)
+ *errno_p = errno;
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (ret != len)
+ return MDADM_STATUS_UNDEF;
+
+ return MDADM_STATUS_SUCCESS;
+}
/**
* sysfs_get_container_devnm() - extract container device name.
@@ -97,6 +140,24 @@ void sysfs_get_container_devnm(struct mdinfo *mdi, char *buf)
*p = 0;
}
+/**
+ * sysfs_open_memb_attr() - helper to get sysfs attr descriptor for member device.
+ * @array_devnm: array kernel device name.
+ * @memb_devnm: member device kernel device name.
+ * @attr: requested sysfs attribute.
+ * @oflag: open() flags.
+ *
+ * To refer member device directory, we need to append "dev-" before the member device name.
+ */
+int sysfs_open_memb_attr(char *array_devnm, char *memb_devnm, char *attr, int oflag)
+{
+ char path[PATH_MAX];
+
+ snprintf(path, PATH_MAX, "/sys/block/%s/md/dev-%s/%s", array_devnm, memb_devnm, attr);
+
+ return open(path, oflag);
+}
+
int sysfs_open(char *devnm, char *devname, char *attr)
{
char fname[MAX_SYSFS_PATH_LEN];
@@ -139,13 +200,14 @@ int sysfs_init(struct mdinfo *mdi, int fd, char *devnm)
goto out;
if (!S_ISDIR(stb.st_mode))
goto out;
- strcpy(mdi->sys_name, devnm);
+ strncpy(mdi->sys_name, devnm, sizeof(mdi->sys_name) - 1);
retval = 0;
out:
return retval;
}
+/* If fd >= 0, get the array it is open on, else use devnm. */
struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
{
char fname[PATH_MAX];
@@ -179,6 +241,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
sra->array.major_version = -1;
sra->array.minor_version = -2;
strcpy(sra->text_version, buf+9);
+ sra->text_version[sizeof(sra->text_version) - 1] = '\0';
} else {
sscanf(buf, "%d.%d",
&sra->array.major_version,
@@ -340,6 +403,7 @@ struct mdinfo *sysfs_read(int fd, char *devnm, unsigned long options)
}
strcpy(dev->sys_name, de->d_name);
+ dev->sys_name[sizeof(dev->sys_name) - 1] = '\0';
dev->disk.raid_disk = strtoul(buf, &ep, 10);
if (*ep) dev->disk.raid_disk = -1;
@@ -484,7 +548,6 @@ int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
char *name, char *val)
{
char fname[MAX_SYSFS_PATH_LEN];
- unsigned int n;
int fd;
snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s",
@@ -492,13 +555,14 @@ int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
fd = open(fname, O_WRONLY);
if (fd < 0)
return -1;
- n = write(fd, val, strlen(val));
- close(fd);
- if (n != strlen(val)) {
- dprintf("failed to write '%s' to '%s' (%s)\n",
- val, fname, strerror(errno));
+
+ if (write_attr(val, fd)) {
+ pr_err("failed to write '%s' to '%s' (%s)\n", val, fname, strerror(errno));
+ close(fd);
return -1;
}
+
+ close(fd);
return 0;
}
@@ -521,7 +585,6 @@ int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev,
int sysfs_uevent(struct mdinfo *sra, char *event)
{
char fname[MAX_SYSFS_PATH_LEN];
- int n;
int fd;
snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/uevent",
@@ -529,13 +592,14 @@ int sysfs_uevent(struct mdinfo *sra, char *event)
fd = open(fname, O_WRONLY);
if (fd < 0)
return -1;
- n = write(fd, event, strlen(event));
- close(fd);
- if (n != (int)strlen(event)) {
- dprintf("failed to write '%s' to '%s' (%s)\n",
- event, fname, strerror(errno));
+
+ if (write_attr(event, fd)) {
+ pr_err("failed to write '%s' to '%s' (%s)\n", event, fname, strerror(errno));
+ close(fd);
return -1;
}
+
+ close(fd);
return 0;
}
@@ -772,8 +836,8 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
memset(nm, 0, sizeof(nm));
dname = devid2kname(makedev(sd->disk.major, sd->disk.minor));
- strcpy(sd->sys_name, "dev-");
- strcpy(sd->sys_name+4, dname);
+
+ snprintf(sd->sys_name, sizeof(sd->sys_name), "dev-%s", dname);
/* test write to see if 'recovery_start' is available */
if (resume && sd->recovery_start < MaxSector &&