/* See LICENSE file for copyright and license details. */ #include "common.h" #if defined(__linux__) # include #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//) */ } #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" : ""); } 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" : ""); }