/* See LICENSE file for copyright and license details. */ #include "common.h" char * readtextfileat(int dfd, const char *path) { int fd; char *text = NULL; size_t size = 0; size_t len = 0; ssize_t r; fd = openat(dfd, path, O_RDONLY); if (fd < 0) return NULL; for (;;) { if (len == size) { size = size ? size * 2U : 64U; text = erealloc(text, size); } r = read(fd, &text[len], size - len); if (r <= 0) { if (!r) break; if (errno == EINTR) continue; close(fd); return NULL; } len += (size_t)r; } close(fd); if (len == size) text = erealloc(text, len + 1U); text[len] = '\0'; return text; } void writeall(int fd, const void *data, size_t n, const char *fname) { const char *text = data; ssize_t r; while (n) { r = write(fd, text, n); if (r < 0) { if (errno == EINTR) continue; eprintf("write %s:", fname); } text = &text[r]; n -= (size_t)r; } } void filecpy(int fd, off_t src, off_t len, const char *fname) { char buf[8UL << 10]; ssize_t r; size_t n; size_t off; while (len) { read_again: r = pread(fd, buf, sizeof(buf), src); if (r <= 0) { if (!r) eprintf("%s: unexpected end of file", fname); if (errno == EINTR) goto read_again; eprintf("pread %s:", fname); } src += (off_t)r; len -= (off_t)r; n = (size_t)r; for (off = 0; off < n;) { write_again: r = write(fd, &buf[off], n - off); if (r < 0) { if (errno == EINTR) goto write_again; eprintf("write %s:", fname); } off += (size_t)r; } } } off_t filesize(int fd, const char *fname) { struct stat st; if (fstat(fd, &st)) eprintf("fstat %s:", fname); switch (st.st_mode & S_IFMT) { case S_IFREG: break; case S_IFBLK: if (ioctl(fd, BLKGETSIZE64, &st.st_size) < 0) eprintf("ioctl %s BLKGETSIZE64:", fname); break; default: eprintf("%s: not a regular file or block device", fname); } return st.st_size; } #if defined(__linux__) char * get_device_name(unsigned int devmajor, unsigned int devminor) { char dev[2 * 3 * sizeof(int) + 3]; size_t devlen; char buf[PATH_MAX]; struct dirent *f; DIR *dir; int dfd, fd; ssize_t r; size_t off; devlen = (size_t)sprintf(dev, "%u:%u\n", devmajor, devminor); dir = opendir("/sys/class/block"); if (!dir) { weprintf("opendir /sys/class/block:"); return NULL; } dfd = dirfd(dir); if (dfd < 0) { weprintf("dirfd /sys/class/block:"); goto fail; } while ((errno = 0, f = readdir(dir))) { if (f->d_name[0] == '.') continue; if (strlen(f->d_name) > sizeof(buf) - sizeof("/dev")) continue; stpcpy(stpcpy(buf, f->d_name), "/dev"); fd = openat(dfd, buf, O_RDONLY); if (fd < 0) continue; off = 0; while (off < sizeof(buf)) { r = read(fd, &buf[off], sizeof(buf) - off); if (!r) goto complete; if (r < 0) { if (errno == EINTR) continue; goto next; } off += (size_t)r; } goto next; complete: if (off == devlen && !memcmp(dev, buf, devlen)) { close(fd); closedir(dir); return strdup(f->d_name); } next: close(fd); } if (errno) weprintf("readdir /sys/class/block:"); fail: closedir(dir); return NULL; } #endif