aboutsummaryrefslogtreecommitdiffstats
path: root/ask.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-09-21 19:31:16 +0200
committerMattias Andrée <maandree@kth.se>2024-09-21 19:31:16 +0200
commit2e55bedc45e836899a18ea7f4a488f50597afad5 (patch)
tree5a9e3cc1465cfc711fb1f74580cb17f20a46212e /ask.c
parentUpdate documentation and adjust blocksize if larger than the device size (diff)
downloaddeadshred-2e55bedc45e836899a18ea7f4a488f50597afad5.tar.gz
deadshred-2e55bedc45e836899a18ea7f4a488f50597afad5.tar.bz2
deadshred-2e55bedc45e836899a18ea7f4a488f50597afad5.tar.xz
misc
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'ask.c')
-rw-r--r--ask.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/ask.c b/ask.c
new file mode 100644
index 0000000..bb8fa50
--- /dev/null
+++ b/ask.c
@@ -0,0 +1,115 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#if defined(__linux__)
+# include <sys/sysmacros.h>
+#endif
+
+
+int
+confirm(const char *device, off_t off, off_t len, off_t end)
+{
+ char buf[1024];
+ int ttyfd = -1;
+ int need_close;
+ int ret = 1;
+ int custom_section = (off >= 0 || len >= 0 || end >= 0);
+ const char *type;
+ ssize_t i, r;
+ int confirm_state = 0;
+ struct stat st;
+
+ if (isatty(STDIN_FILENO)) {
+ ttyfd = STDIN_FILENO;
+ need_close = 0;
+ } else {
+ ttyfd = open("/dev/tty", O_RDWR);
+ if (ttyfd < 0)
+ return 1;
+ need_close = 1;
+ }
+
+ if (getpgrp() != tcgetpgrp(ttyfd))
+ goto out;
+
+ if (custom_section) {
+ if (off < 0)
+ off = 0;
+ if (end >= 0)
+ len = end - off;
+ else if (len >= 0)
+ end = off + len;
+ else if (off == 0)
+ custom_section = 0;
+ if (end >= 0 && end < off)
+ eprintf("the value of -e option is lower than value of -o option");
+ }
+
+ if (stat(device, &st))
+ eprintf("stat %s:", device);
+ switch (st.st_mode & S_IFMT) {
+ case S_IFREG:
+ type = "file";
+ break;
+ case S_IFBLK:
+ type = "device";
+ break;
+ default:
+ eprintf("%s: not a regular file or block device", device);
+ }
+
+ if (dprintf(ttyfd, "Are you sure you want to erase the contents of %s?\n", device) < 0)
+ goto printerror;
+
+ if (S_ISREG(st.st_mode)) {
+ if (dprintf(ttyfd, "\nThe file is %s large.\n", exact_and_human_size(st.st_size, buf, 1)) < 0)
+ goto printerror;
+#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/<devname>/) */
+ }
+#endif
+ }
+
+ if (custom_section) {
+ if (dprintf(ttyfd, "\nYou have requested to only erase part of the %s:\n", type) < 0 ||
+ (off >= 0 && dprintf(ttyfd, "\tFirst byte: %s\n", exact_and_human_size(off, buf, 0)) < 0) ||
+ (len >= 0 && dprintf(ttyfd, "\tNumber of bytes: %s\n", exact_and_human_size(len, buf, 0)) < 0) ||
+ (end >= 0 && dprintf(ttyfd, "\tEnd of overwrite: %s\n", exact_and_human_size(end, buf, 1)) < 0))
+ goto printerror;
+ }
+
+ if (dprintf(ttyfd, "\nAffirm by entering 'yes' in majuscule without quotes.\n") < 0)
+ goto printerror;
+
+ ret = 0;
+ for (;;) {
+ r = read(ttyfd, buf, sizeof(buf));
+ if (!r) {
+ goto out;
+ } else if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ eprintf("read %s:", need_close ? "/dev/tty" : "<stdin>");
+ }
+ for (i = 0; i < r; i++) {
+ if (buf[i] != "YES\n"[confirm_state++])
+ goto out;
+ if (buf[i] == '\n') {
+ ret = 1;
+ goto out;
+ }
+ }
+ }
+
+out:
+ if (need_close)
+ close(ttyfd);
+ if (dprintf(ttyfd, "%s\n", ret ? "" : "User did not affirm action. Aborting...") < 0)
+ goto printerror;
+ return ret;
+
+printerror:
+ eprintf("dprintf %s:", need_close ? "/dev/tty" : "<stdin>");
+}