/* 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>");
}