+
+void tools_keyslot_msg(int keyslot, crypt_object_op op)
+{
+ if (keyslot < 0)
+ return;
+
+ if (op == CREATED)
+ log_verbose(_("Key slot %i created."), keyslot);
+ else if (op == UNLOCKED)
+ log_verbose(_("Key slot %i unlocked."), keyslot);
+ else if (op == REMOVED)
+ log_verbose(_("Key slot %i removed."), keyslot);
+}
+
+void tools_token_msg(int token, crypt_object_op op)
+{
+ if (token < 0)
+ return;
+
+ if (op == CREATED)
+ log_verbose(_("Token %i created."), token);
+ else if (op == REMOVED)
+ log_verbose(_("Token %i removed."), token);
+}
+
+/*
+ * Device size string parsing, suffixes:
+ * s|S - 512 bytes sectors
+ * k |K |m |M |g |G |t |T - 1024 base
+ * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
+ * kb |KB |mM |MB |gB |GB |tB |TB - 1000 base
+ */
+int tools_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size)
+{
+ char *endp = NULL;
+ size_t len;
+ uint64_t mult_base, mult, tmp;
+
+ *size = strtoull(s, &endp, 10);
+ if (!isdigit(s[0]) ||
+ (errno == ERANGE && *size == ULLONG_MAX) ||
+ (errno != 0 && *size == 0))
+ return -EINVAL;
+
+ if (!endp || !*endp)
+ return 0;
+
+ len = strlen(endp);
+ /* Allow "B" and "iB" suffixes */
+ if (len > 3 ||
+ (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
+ (len == 2 && endp[1] != 'B'))
+ return -EINVAL;
+
+ if (len == 1 || len == 3)
+ mult_base = 1024;
+ else
+ mult_base = 1000;
+
+ mult = 1;
+ switch (endp[0]) {
+ case 's':
+ case 'S': mult = 512;
+ break;
+ case 't':
+ case 'T': mult *= mult_base;
+ /* Fall through */
+ case 'g':
+ case 'G': mult *= mult_base;
+ /* Fall through */
+ case 'm':
+ case 'M': mult *= mult_base;
+ /* Fall through */
+ case 'k':
+ case 'K': mult *= mult_base;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tmp = *size * mult;
+ if (*size && (tmp / *size) != mult) {
+ log_dbg("Device size overflow.");
+ return -EINVAL;
+ }
+
+ *size = tmp;
+ return 0;
+}
+
+/* Time progress helper */
+
+/* The difference in seconds between two times in "timeval" format. */
+static double time_diff(struct timeval *start, struct timeval *end)
+{
+ return (end->tv_sec - start->tv_sec)
+ + (end->tv_usec - start->tv_usec) / 1E6;
+}
+
+void tools_clear_line(void)
+{
+ if (opt_progress_frequency)
+ return;
+ /* vt100 code clear line */
+ log_std("\33[2K\r");
+}
+
+static void tools_time_progress(uint64_t device_size, uint64_t bytes, uint64_t *start_bytes,
+ struct timeval *start_time, struct timeval *end_time)
+{
+ struct timeval now_time;
+ unsigned long long mbytes, eta;
+ double tdiff, uib, frequency;
+ int final = (bytes == device_size);
+ const char *eol, *ustr = "";
+
+ if (opt_batch_mode)
+ return;
+
+ gettimeofday(&now_time, NULL);
+ if (start_time->tv_sec == 0 && start_time->tv_usec == 0) {
+ *start_time = now_time;
+ *end_time = now_time;
+ *start_bytes = bytes;
+ return;
+ }
+
+ if (opt_progress_frequency) {
+ frequency = (double)opt_progress_frequency;
+ eol = "\n";
+ } else {
+ frequency = 0.5;
+ eol = "";
+ }
+
+ if (!final && time_diff(end_time, &now_time) < frequency)
+ return;
+
+ *end_time = now_time;
+
+ tdiff = time_diff(start_time, end_time);
+ if (!tdiff)
+ return;
+
+ mbytes = bytes / 1024 / 1024;
+ uib = (double)(bytes - *start_bytes) / tdiff;
+
+ /* FIXME: calculate this from last minute only. */
+ eta = (unsigned long long)(device_size / uib - tdiff);
+
+ if (uib > 1073741824.0f) {
+ uib /= 1073741824.0f;
+ ustr = "Gi";
+ } else if (uib > 1048576.0f) {
+ uib /= 1048576.0f;
+ ustr = "Mi";
+ } else if (uib > 1024.0f) {
+ uib /= 1024.0f;
+ ustr = "Ki";
+ }
+
+ tools_clear_line();
+ if (final)
+ log_std("Finished, time %02llu:%02llu.%03llu, "
+ "%4llu MiB written, speed %5.1f %sB/s\n",
+ (unsigned long long)tdiff / 60,
+ (unsigned long long)tdiff % 60,
+ (unsigned long long)((tdiff - floor(tdiff)) * 1000.0),
+ mbytes, uib, ustr);
+ else
+ log_std("Progress: %5.1f%%, ETA %02llu:%02llu, "
+ "%4llu MiB written, speed %5.1f %sB/s%s",
+ (double)bytes / device_size * 100,
+ eta / 60, eta % 60, mbytes, uib, ustr, eol);
+ fflush(stdout);
+}
+
+int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr)
+{
+ static struct timeval start_time = {}, end_time = {};
+ static uint64_t start_offset = 0;
+ int r = 0;
+
+ tools_time_progress(size, offset, &start_offset, &start_time, &end_time);
+
+ check_signal(&r);
+ if (r) {
+ tools_clear_line();
+ log_err(_("\nWipe interrupted."));
+ }
+
+ return r;
+}
+
+static void report_partition(const char *value, const char *device)
+{
+ if (opt_batch_mode)
+ log_dbg("Device %s already contains a '%s' partition signature.", device, value);
+ else
+ log_std(_("WARNING: Device %s already contains a '%s' partition signature.\n"), device, value);
+}
+
+static void report_superblock(const char *value, const char *device)
+{
+ if (opt_batch_mode)
+ log_dbg("Device %s already contains a '%s' superblock signature.", device, value);
+ else
+ log_std(_("WARNING: Device %s already contains a '%s' superblock signature.\n"), device, value);
+}
+
+int tools_detect_signatures(const char *device, int ignore_luks, size_t *count)
+{
+ int r;
+ size_t tmp_count;
+ struct blkid_handle *h;
+ blk_probe_status pr;
+
+ if (!count)
+ count = &tmp_count;
+
+ *count = 0;
+
+ if (!blk_supported()) {
+ log_dbg("Blkid support disabled.");
+ return 0;
+ }
+
+ if ((r = blk_init_by_path(&h, device))) {
+ log_err(_("Failed to initialize device signature probes."));
+ return -EINVAL;
+ }
+
+ blk_set_chains_for_full_print(h);
+
+ if (ignore_luks && blk_superblocks_filter_luks(h)) {
+ r = -EINVAL;
+ goto out;
+ }
+
+ while ((pr = blk_probe(h)) < PRB_EMPTY) {
+ if (blk_is_partition(h))
+ report_partition(blk_get_partition_type(h), device);
+ else if (blk_is_superblock(h))
+ report_superblock(blk_get_superblock_type(h), device);
+ else {
+ log_dbg("Internal tools_detect_signatures() error.");
+ r = -EINVAL;
+ goto out;
+ }
+ (*count)++;
+ }
+
+ if (pr == PRB_FAIL)
+ r = -EINVAL;
+out:
+ blk_free(h);
+ return r;
+}
+
+int tools_wipe_all_signatures(const char *path)
+{
+ int fd, flags, r;
+ blk_probe_status pr;
+ struct stat st;
+ struct blkid_handle *h = NULL;
+
+ if (!blk_supported()) {
+ log_dbg("Blkid support disabled.");
+ return 0;
+ }
+
+ if (stat(path, &st)) {
+ log_err(_("Failed to stat device %s."), path);
+ return -EINVAL;
+ }
+
+ flags = O_RDWR;
+ if (S_ISBLK(st.st_mode))
+ flags |= O_EXCL;
+
+ /* better than opening regular file with O_EXCL (undefined) */
+ /* coverity[toctou] */
+ fd = open(path, flags);
+ if (fd < 0) {
+ if (errno == EBUSY)
+ log_err(_("Device %s is in use. Can not proceed with format operation."), path);
+ else
+ log_err(_("Failed to open file %s in read/write mode."), path);
+ return -EINVAL;
+ }
+
+ if ((r = blk_init_by_fd(&h, fd))) {
+ log_err(_("Failed to initialize device signature probes."));
+ r = -EINVAL;
+ goto out;
+ }
+
+ blk_set_chains_for_wipes(h);
+
+ while ((pr = blk_probe(h)) < PRB_EMPTY) {
+ if (blk_is_partition(h))
+ log_verbose(_("Existing '%s' partition signature (offset: %" PRIi64 " bytes) on device %s will be wiped."),
+ blk_get_partition_type(h), blk_get_offset(h), path);
+ if (blk_is_superblock(h))
+ log_verbose(_("Existing '%s' superblock signature (offset: %" PRIi64 " bytes) on device %s will be wiped."),
+ blk_get_superblock_type(h), blk_get_offset(h), path);
+ if (blk_do_wipe(h)) {
+ log_err(_("Failed to wipe device signature."));
+ r = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (pr != PRB_EMPTY) {
+ log_err(_("Failed to probe device %s for a signature."), path);
+ r = -EINVAL;
+ }
+out:
+ close(fd);
+ blk_free(h);
+ return r;
+}
+
+int tools_is_cipher_null(const char *cipher)
+{
+ if (!cipher)
+ return 0;
+
+ return !strcmp(cipher, "cipher_null") ? 1 : 0;
+}
+
+/*
+ * Keyfile - is standard input treated as a binary file (no EOL handling).
+ */
+int tools_is_stdin(const char *key_file)
+{
+ if (!key_file)
+ return 1;
+
+ return strcmp(key_file, "-") ? 0 : 1;
+}
+
+int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
+{
+ static struct timeval start_time = {}, end_time = {};
+ static uint64_t start_offset = 0;
+ int r = 0;
+
+ tools_time_progress(size, offset, &start_offset, &start_time, &end_time);
+
+ check_signal(&r);
+ if (r) {
+ tools_clear_line();
+ log_err(_("\nReencryption interrupted."));
+ }
+
+ return r;
+}