static char * print_partition_table (const char *device, bool add_m_option) { char *out; CLEANUP_FREE char *err = NULL; int r; udev_settle (); if (add_m_option) r = command (&out, &err, "parted", "-m", "-s", "--", device, "unit", "b", "print", NULL); else r = command (&out, &err, "parted", "-s", "--", device, "unit", "b", "print", NULL); udev_settle (); if (r == -1) { int errcode = 0; /* Translate "unrecognised disk label" into an errno code. */ if (err && strstr (err, "unrecognised disk label") != NULL) errcode = EINVAL; reply_with_error_errno (errcode, "parted print: %s: %s", device, err); free (out); return NULL; } return out; }
/* Send back an error of different lengths. */ static char * debug_error (const char *subcmd, size_t argc, char *const *const argv) { unsigned len; CLEANUP_FREE char *buf = NULL; if (argc != 1) { error: reply_with_error ("debug error: expecting one arg: length of error message"); return NULL; } if (sscanf (argv[0], "%u", &len) != 1) goto error; if (len > 1000000) { reply_with_error ("debug error: length argument too large"); return NULL; } buf = malloc (len + 1); if (buf == NULL) { reply_with_perror ("malloc"); return NULL; } memset (buf, 'a', len); buf[len] = '\0'; /* So that the regression test can tell this is the true return path * from the function and not an actual error, we set errno to some * value that cannot be returned by any other error path. */ reply_with_error_errno (EROFS, "%s", buf); return NULL; }
/* Used to test read and write speed. */ static char * debug_device_speed (const char *subcmd, size_t argc, char *const *const argv) { const char *device; int writing, err; unsigned secs; int64_t size, position, copied; CLEANUP_FREE void *buf = NULL; struct timeval now, end; ssize_t r; int fd; char *ret; if (argc != 3) { bad_args: reply_with_error ("device_speed <device> <r|w> <secs>"); return NULL; } device = argv[0]; if (STREQ (argv[1], "r") || STREQ (argv[1], "read")) writing = 0; else if (STREQ (argv[1], "w") || STREQ (argv[1], "write")) writing = 1; else goto bad_args; if (sscanf (argv[2], "%u", &secs) != 1) goto bad_args; /* Find the size of the device. */ size = do_blockdev_getsize64 (device); if (size == -1) return NULL; if (size < BUFSIZ) { reply_with_error ("%s: device is too small", device); return NULL; } /* Because we're using O_DIRECT, the buffer must be aligned. */ err = posix_memalign (&buf, 4096, BUFSIZ); if (err != 0) { reply_with_error_errno (err, "posix_memalign"); return NULL; } /* Any non-zero data will do. */ memset (buf, 100, BUFSIZ); fd = open (device, (writing ? O_WRONLY : O_RDONLY) | O_CLOEXEC | O_DIRECT); if (fd == -1) { reply_with_perror ("open: %s", device); return NULL; } /* Now we read or write to the device, wrapping around to the * beginning when we reach the end, and only stop when <secs> * seconds has elapsed. */ gettimeofday (&end, NULL); end.tv_sec += secs; position = copied = 0; for (;;) { gettimeofday (&now, NULL); if (now.tv_sec > end.tv_sec || (now.tv_sec == end.tv_sec && now.tv_usec > end.tv_usec)) break; /* Because of O_DIRECT, only write whole, aligned buffers. */ again: if (size - position < BUFSIZ) { position = 0; goto again; } /* if (verbose) { fprintf (stderr, "p%s (fd, buf, %d, %" PRIi64 ")\n", writing ? "write" : "read", BUFSIZ, position); } */ if (writing) { r = pwrite (fd, buf, BUFSIZ, position); if (r == -1) { reply_with_perror ("write: %s", device); goto error; } } else { r = pread (fd, buf, BUFSIZ, position); if (r == -1) { reply_with_perror ("read: %s", device); goto error; } if (r == 0) { reply_with_error ("unexpected end of file while reading"); goto error; } } position += BUFSIZ; copied += r; } if (close (fd) == -1) { reply_with_perror ("close: %s", device); return NULL; } if (asprintf (&ret, "%" PRIi64, copied) == -1) { reply_with_perror ("asprintf"); return NULL; } return ret; error: close (fd); return NULL; }