Blame src/kdfontop.c

Packit Service 50ad14
/*
Packit Service 50ad14
 * kdfontop.c - export getfont(), getfontsize() and putfont()
Packit Service 50ad14
 *
Packit Service 50ad14
 * Font handling differs between various kernel versions.
Packit Service 50ad14
 * Hide the differences in this file.
Packit Service 50ad14
 */
Packit Service 50ad14
#include "config.h"
Packit Service 50ad14
Packit Service 50ad14
#include <stdio.h>
Packit Service 50ad14
#include <errno.h>
Packit Service 50ad14
#include <stdlib.h> /* free() */
Packit Service 50ad14
#include <sys/ioctl.h>
Packit Service 50ad14
#include <linux/kd.h>
Packit Service 50ad14
#include "kdfontop.h"
Packit Service 50ad14
#include "nls.h"
Packit Service 50ad14
#include "version.h"
Packit Service 50ad14
Packit Service 50ad14
#ifdef COMPAT_HEADERS
Packit Service 50ad14
#include "compat/linux-kd.h"
Packit Service 50ad14
#endif
Packit Service 50ad14
Packit Service 50ad14
int restorefont(int fd)
Packit Service 50ad14
{
Packit Service 50ad14
	if (ioctl(fd, PIO_FONTRESET, 0)) {
Packit Service 50ad14
		perror("PIO_FONTRESET");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
	return 0;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
int font_charheight(unsigned char *buf, int count, int width)
Packit Service 50ad14
{
Packit Service 50ad14
	int h, i, x;
Packit Service 50ad14
	int bytewidth = (width + 7) / 8;
Packit Service 50ad14
Packit Service 50ad14
	for (h = 32; h > 0; h--)
Packit Service 50ad14
		for (i = 0; i < count; i++)
Packit Service 50ad14
			for (x = 0; x < bytewidth; x++)
Packit Service 50ad14
				if (buf[(32 * i + h - 1) * bytewidth + x])
Packit Service 50ad14
					goto nonzero;
Packit Service 50ad14
nonzero:
Packit Service 50ad14
	return h;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
/*
Packit Service 50ad14
 * May be called with buf==NULL if we only want info.
Packit Service 50ad14
 * May be called with width==NULL and height==NULL.
Packit Service 50ad14
 * Must not exit - we may have cleanup to do.
Packit Service 50ad14
 */
Packit Service 50ad14
int getfont(int fd, unsigned char *buf, int *count, int *width, int *height)
Packit Service 50ad14
{
Packit Service 50ad14
	struct consolefontdesc cfd;
Packit Service 50ad14
	struct console_font_op cfo;
Packit Service 50ad14
	int i;
Packit Service 50ad14
Packit Service 50ad14
	/* First attempt: KDFONTOP */
Packit Service 50ad14
	cfo.op    = KD_FONT_OP_GET;
Packit Service 50ad14
	cfo.flags = 0;
Packit Service 50ad14
	cfo.width = cfo.height = 32;
Packit Service 50ad14
	cfo.charcount          = *count;
Packit Service 50ad14
	cfo.data               = buf;
Packit Service 50ad14
	i                      = ioctl(fd, KDFONTOP, &cfo;;
Packit Service 50ad14
	if (i == 0) {
Packit Service 50ad14
		*count = cfo.charcount;
Packit Service 50ad14
		if (height)
Packit Service 50ad14
			*height = cfo.height;
Packit Service 50ad14
		if (width)
Packit Service 50ad14
			*width = cfo.width;
Packit Service 50ad14
		return 0;
Packit Service 50ad14
	}
Packit Service 50ad14
	if (errno != ENOSYS && errno != EINVAL) {
Packit Service 50ad14
		perror("getfont: KDFONTOP");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	/* The other methods do not support width != 8 */
Packit Service 50ad14
	if (width)
Packit Service 50ad14
		*width = 8;
Packit Service 50ad14
	/* Second attempt: GIO_FONTX */
Packit Service 50ad14
	cfd.charcount  = *count;
Packit Service 50ad14
	cfd.charheight = 0;
Packit Service 50ad14
	cfd.chardata   = (char *)buf;
Packit Service 50ad14
	i              = ioctl(fd, GIO_FONTX, &cfd;;
Packit Service 50ad14
	if (i == 0) {
Packit Service 50ad14
		*count = cfd.charcount;
Packit Service 50ad14
		if (height)
Packit Service 50ad14
			*height = cfd.charheight;
Packit Service 50ad14
		return 0;
Packit Service 50ad14
	}
Packit Service 50ad14
	if (errno != ENOSYS && errno != EINVAL) {
Packit Service 50ad14
		perror("getfont: GIO_FONTX");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	/* Third attempt: GIO_FONT */
Packit Service 50ad14
	if (*count < 256) {
Packit Service 50ad14
		fprintf(stderr, _("bug: getfont called with count<256\n"));
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
	if (!buf) {
Packit Service 50ad14
		fprintf(stderr, _("bug: getfont using GIO_FONT needs buf.\n"));
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
	i = ioctl(fd, GIO_FONT, buf);
Packit Service 50ad14
	if (i) {
Packit Service 50ad14
		perror("getfont: GIO_FONT");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
	*count = 256;
Packit Service 50ad14
	if (height)
Packit Service 50ad14
		*height = 0; /* undefined, at most 32 */
Packit Service 50ad14
	return 0;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
int getfontsize(int fd)
Packit Service 50ad14
{
Packit Service 50ad14
	int count;
Packit Service 50ad14
	int i;
Packit Service 50ad14
Packit Service 50ad14
	count = 0;
Packit Service 50ad14
	i     = getfont(fd, NULL, &count, NULL, NULL);
Packit Service 50ad14
	return (i == 0) ? count : 256;
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
int putfont(int fd, unsigned char *buf, int count, int width, int height)
Packit Service 50ad14
{
Packit Service 50ad14
	struct consolefontdesc cfd;
Packit Service 50ad14
	struct console_font_op cfo;
Packit Service 50ad14
	int i;
Packit Service 50ad14
Packit Service 50ad14
	if (!width)
Packit Service 50ad14
		width = 8;
Packit Service 50ad14
	if (!height)
Packit Service 50ad14
		height = font_charheight(buf, count, width);
Packit Service 50ad14
Packit Service 50ad14
	/* First attempt: KDFONTOP */
Packit Service 50ad14
	cfo.op        = KD_FONT_OP_SET;
Packit Service 50ad14
	cfo.flags     = 0;
Packit Service 50ad14
	cfo.width     = width;
Packit Service 50ad14
	cfo.height    = height;
Packit Service 50ad14
	cfo.charcount = count;
Packit Service 50ad14
	cfo.data      = buf;
Packit Service 50ad14
	i             = ioctl(fd, KDFONTOP, &cfo;;
Packit Service 50ad14
	if (i == 0)
Packit Service 50ad14
		return 0;
Packit Service 50ad14
	if (width != 8 || (errno != ENOSYS && errno != EINVAL)) {
Packit Service 50ad14
		perror("putfont: KDFONTOP");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	/* Variation on first attempt: in case count is not 256 or 512
Packit Service 50ad14
	   round up and try again. */
Packit Service 50ad14
	if (errno == EINVAL && width == 8 && count != 256 && count < 512) {
Packit Service 50ad14
		int ct               = ((count > 256) ? 512 : 256);
Packit Service 50ad14
		unsigned char *mybuf = malloc(32 * ct);
Packit Service 50ad14
Packit Service 50ad14
		if (!mybuf) {
Packit Service 50ad14
			fprintf(stderr, _("%s: out of memory\n"), progname);
Packit Service 50ad14
			return -1;
Packit Service 50ad14
		}
Packit Service 50ad14
		memset(mybuf, 0, 32 * ct);
Packit Service 50ad14
		memcpy(mybuf, buf, 32 * count);
Packit Service 50ad14
		cfo.data      = mybuf;
Packit Service 50ad14
		cfo.charcount = ct;
Packit Service 50ad14
		i             = ioctl(fd, KDFONTOP, &cfo;;
Packit Service 50ad14
		free(mybuf);
Packit Service 50ad14
		if (i == 0)
Packit Service 50ad14
			return 0;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	/* Second attempt: PIO_FONTX */
Packit Service 50ad14
	cfd.charcount  = count;
Packit Service 50ad14
	cfd.charheight = height;
Packit Service 50ad14
	cfd.chardata   = (char *)buf;
Packit Service 50ad14
	i              = ioctl(fd, PIO_FONTX, &cfd;;
Packit Service 50ad14
	if (i == 0)
Packit Service 50ad14
		return 0;
Packit Service 50ad14
	if (errno != ENOSYS && errno != EINVAL) {
Packit Service 50ad14
		fprintf(stderr, "%s: putfont: %d,%dx%d:failed: %d\n", progname, count, width, height, i);
Packit Service 50ad14
		perror("putfont: PIO_FONTX");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	/* Third attempt: PIO_FONT */
Packit Service 50ad14
	/* This will load precisely 256 chars, independent of count */
Packit Service 50ad14
	i = ioctl(fd, PIO_FONT, buf);
Packit Service 50ad14
	if (i) {
Packit Service 50ad14
		fprintf(stderr, "%s: putfont: %d,%dx%d:  failed: %d\n", progname, count, width, height, i);
Packit Service 50ad14
		perror("putfont: PIO_FONT");
Packit Service 50ad14
		return -1;
Packit Service 50ad14
	}
Packit Service 50ad14
	return 0;
Packit Service 50ad14
}