aboutsummaryrefslogblamecommitdiffstats
path: root/io.c
blob: 063265bed8949db356bc4bf54e917d05710b1184 (plain) (tree)
1
2
3
4



                                                         






































                                                      






















































                                                                             




















                                                                         







































































                                                                     
/* 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