From b968f8ed826b9cc662c1a484040c55b0e0ad18c4 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 22 Sep 2024 00:17:14 +0200 Subject: Expose device information in confirmation prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- ask.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- common.h | 1 + deadshred.c | 6 ++- io.c | 39 +++++++++++++++ 4 files changed, 200 insertions(+), 4 deletions(-) diff --git a/ask.c b/ask.c index bb8fa50..5917a12 100644 --- a/ask.c +++ b/ask.c @@ -5,6 +5,146 @@ #endif +struct devinfo { + char *part; + char *dev; + char *part_start; + char *part_size; + char *dev_size; + char *dev_wwid; + char *dev_model; + char *dev_serial; + char *dev_transport; +}; + + +static void +destroy_devinfo(struct devinfo *info) +{ + free(info->part); + free(info->dev); + free(info->part_start); + free(info->part_size); + free(info->dev_size); + free(info->dev_wwid); + free(info->dev_model); + free(info->dev_serial); + free(info->dev_transport); +} + + +static char * +strip(char *s) +{ + char *ret = s; + if (s) { + char *p = s; + while (*s) { + while (*s && !isspace(*s)) + s++; + p = s; + while (*s && isspace(*s)) + s++; + } + *p = '\0'; + } + return ret; +} + + +static char * +fmtsize(char *s) +{ + uintmax_t val; + char *end, *ret; + char buf[256]; + + if (!s) + return NULL; + + errno = 0; + val = strtoumax(s, &end, 10); + if (!isdigit(*s) || *end || errno || val > (uintmax_t)(OFF_MAX / 512)) { + free(s); + return NULL; + } + + ret = estrdup(exact_and_human_size((off_t)val * 512, buf, 1)); + free(s); + return ret; +} + + +static int +get_devinfo(struct devinfo *info, const char *name) +{ + struct stat st; + char *path, *p; + int dfd; + + info->part = NULL; + info->dev = NULL; + info->part_start = NULL; + info->part_size = NULL; + info->dev_size = NULL; + info->dev_wwid = NULL; + info->dev_model = NULL; + info->dev_serial = NULL; + info->dev_transport = NULL; + + path = emalloc(sizeof("/sys/class/block/") + strlen(name)); + p = stpcpy(stpcpy(path, "/sys/class/block/"), name); + + dfd = open(path, O_PATH); + if (dfd < 0) + return 0; + + info->part = strip(readtextfileat(dfd, "partition")); + if (info->part) { + info->part_start = fmtsize(strip(readtextfileat(dfd, "start"))); + info->part_size = fmtsize(strip(readtextfileat(dfd, "size"))); + + close(dfd); + + if (!isdigit(p[-1])) + return 1; + while (isdigit(p[-1])) + *--p = '\0'; + + dfd = open(path, O_PATH); + if (dfd < 0) { + if (isalpha(p[-1])) { + *--p = '\0'; + dfd = open(path, O_PATH); + } + if (dfd < 0) + return 1; + } + + if (fstatat(dfd, name, &st, 0) || !S_ISDIR(st.st_mode)) { + close(dfd); + return 1; + } + + while (p[-1] != '/') + p--; + info->dev = estrdup(p); + } + + info->dev_size = fmtsize(strip(readtextfileat(dfd, "size"))); + info->dev_wwid = strip(readtextfileat(dfd, "wwid")); + if (!info->dev_wwid) + info->dev_wwid = strip(readtextfileat(dfd, "device/wwid")); + info->dev_model = strip(readtextfileat(dfd, "device/model")); + info->dev_serial = strip(readtextfileat(dfd, "device/serial")); + info->dev_transport = strip(readtextfileat(dfd, "device/transport")); + + close(dfd); + + return info->part || info->dev_size || info->dev_wwid || info->dev_model || info->dev_serial || info->dev_transport; +} + + int confirm(const char *device, off_t off, off_t len, off_t end) { @@ -66,8 +206,22 @@ confirm(const char *device, off_t off, off_t len, off_t end) #if defined(__linux__) } else if (S_ISBLK(st.st_mode)) { char *devname = get_device_name(major(st.st_rdev), minor(st.st_rdev)); - if (devname) { - /* TODO display device identity and size (look in /sys/class/block//) */ + struct devinfo info; + if (devname && get_devinfo(&info, devname)) { + if ((dprintf(ttyfd, "\nFile is identified as block device %s. Details below:\n", devname) < 0) || + (info.part && info.dev && dprintf(ttyfd, "\tPartition %s of %s\n", info.part, info.dev) < 0) || + (info.part_size && dprintf(ttyfd, "\tSize of the partition: %s\n", info.part_size) < 0) || + (info.part_start && dprintf(ttyfd, "\tOffset of the partition: %s\n", info.part_start) < 0) || + (info.dev_size && dprintf(ttyfd, "\tSize of the device: %s\n", info.dev_size) < 0) || + (info.dev_model && dprintf(ttyfd, "\tModel of the device: %s\n", info.dev_model) < 0) || + (info.dev_serial && dprintf(ttyfd, "\tSerial number of the device: %s\n", info.dev_serial) < 0) || + (info.dev_transport && dprintf(ttyfd, "\tTransport type of the device: %s\n", info.dev_transport) < 0) || + (info.dev_wwid && dprintf(ttyfd, "\tWWID of the device: %s\n", info.dev_wwid) < 0)) + goto printerror; + destroy_devinfo(&info); + } else if (devname) { + if (dprintf(ttyfd, "\nFile is identified as block device %s. No details available.\n", devname) < 0) + goto printerror; } #endif } diff --git a/common.h b/common.h index ad4b8a8..891f1c6 100644 --- a/common.h +++ b/common.h @@ -51,6 +51,7 @@ struct status { /* io.c */ +char *readtextfileat(int dfd, const char *path); void writeall(int fd, const void *data, size_t n, const char *fname); void filecpy(int fd, off_t src, off_t len, const char *fname); off_t filesize(int fd, const char *fname); diff --git a/deadshred.c b/deadshred.c index 8b8a74c..baa7bf6 100644 --- a/deadshred.c +++ b/deadshred.c @@ -57,8 +57,8 @@ print_status(int done, struct status *s) libsimple_difftimespec(&time_spent, &s->now, &start_time); sprintf(bufi == 0 ? buf1 : buf2, - "%ji bytes (%s, %s, %.2lf %%) of %s (%s) shredded\033[K\n" - "failed writes: %ju; bad sections: %ju (%ji bytes, %s, %s)\033[K\n" + "%ji byte%s (%s, %s, %.2lf %%) of %s (%s) shredded\033[K\n" + "failed writes: %ju; bad sections: %ju (%ji byte%s, %s, %s)\033[K\n" "time spent shredding: %s; performance: %s\033[K\n" "time since last successful write: %s\033[K\n" "maximum time until a successful write: %s\033[K\n" @@ -66,6 +66,7 @@ print_status(int done, struct status *s) "%s", /* line 1 { */ (intmax_t)s->shredded, + s->shredded == 1 ? "" : "s", humansize1000(s->shredded, subbuf1), humansize1024(s->shredded, subbuf2), 100 * (double)s->shredded / (double)total_size, @@ -75,6 +76,7 @@ print_status(int done, struct status *s) s->bad_writes, s->bad_sections, (intmax_t)s->bad_bytes, + s->bad_bytes == 1 ? "" : "s", humansize1000(s->bad_bytes, subbuf3), humansize1024(s->bad_bytes, subbuf4), /* } line 3 { */ diff --git a/io.c b/io.c index 98afe53..063265b 100644 --- a/io.c +++ b/io.c @@ -2,6 +2,45 @@ #include "common.h" +char * +readtextfileat(int dfd, const char *path) +{ + int fd; + char *text = NULL; + size_t size = 0; + size_t len = 0; + ssize_t r; + + fd = openat(dfd, path, O_RDONLY); + if (fd < 0) + return NULL; + + for (;;) { + if (len == size) { + size = size ? size * 2U : 64U; + text = erealloc(text, size); + } + r = read(fd, &text[len], size - len); + if (r <= 0) { + if (!r) + break; + if (errno == EINTR) + continue; + close(fd); + return NULL; + } + len += (size_t)r; + } + + close(fd); + + if (len == size) + text = erealloc(text, len + 1U); + text[len] = '\0'; + return text; +} + + void writeall(int fd, const void *data, size_t n, const char *fname) { -- cgit v1.2.3-70-g09d2