/* * loadfont.c - Eugene Crosser & Andries Brouwer * * Version 0.96bb * * Loads the console font, and possibly the corresponding screen map(s). * (Adapted for busybox by Matej Vela.) */ #include "internal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define PSF_MAGIC1 0x36 #define PSF_MAGIC2 0x04 #define PSF_MODE512 0x01 #define PSF_MODEHASTAB 0x02 #define PSF_MAXMODE 0x03 #define PSF_SEPARATOR 0xFFFF static const char loadfont_usage[] = "loadfont\n" "\n" "\tLoad a console font from standard input.\n" "\n"; struct psf_header { unsigned char magic1, magic2; /* Magic number */ unsigned char mode; /* PSF font mode */ unsigned char charsize; /* Character size */ }; #define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2) static void loadnewfont(int fd); extern int loadfont_main(int argc, char **argv) { int fd; fd = open("/dev/tty0", O_RDWR); if (fd < 0) { fprintf(stderr, "Error opening /dev/tty0: %s\n", strerror(errno)); return 1; } loadnewfont(fd); return 0; } static void do_loadfont(int fd, char *inbuf, int unit, int fontsize) { char buf[16384]; int i; memset(buf,0,sizeof(buf)); if (unit < 1 || unit > 32) { fprintf(stderr, "Bad character size %d\n", unit); exit(1); } for (i = 0; i < fontsize; i++) memcpy(buf+(32*i), inbuf+(unit*i), unit); #if defined( PIO_FONTX ) && !defined( __sparc__ ) { struct consolefontdesc cfd; cfd.charcount = fontsize; cfd.charheight = unit; cfd.chardata = buf; if (ioctl(fd, PIO_FONTX, &cfd) == 0) return; /* success */ perror("PIO_FONTX ioctl error (trying PIO_FONT)"); } #endif if (ioctl(fd, PIO_FONT, buf)) { perror("PIO_FONT ioctl error"); exit(1); } } static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) { struct unimapinit advice; struct unimapdesc ud; struct unipair *up; int ct = 0, maxct; int glyph; u_short unicode; maxct = tailsz; /* more than enough */ up = (struct unipair *) malloc(maxct * sizeof(struct unipair)); if (!up) { fprintf(stderr, "Out of memory?\n"); exit(1); } for (glyph = 0; glyph < fontsize; glyph++) { while (tailsz >= 2) { unicode = (((u_short) inbuf[1]) << 8) + inbuf[0]; tailsz -= 2; inbuf += 2; if (unicode == PSF_SEPARATOR) break; up[ct].unicode = unicode; up[ct].fontpos = glyph; ct++; } } /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP this printf did not work on many kernels */ advice.advised_hashsize = 0; advice.advised_hashstep = 0; advice.advised_hashlevel = 0; if(ioctl(fd, PIO_UNIMAPCLR, &advice)) { #ifdef ENOIOCTLCMD if (errno == ENOIOCTLCMD) { fprintf(stderr, "It seems this kernel is older than 1.1.92\n"); fprintf(stderr, "No Unicode mapping table loaded.\n"); } else #endif perror("PIO_UNIMAPCLR"); exit(1); } ud.entry_ct = ct; ud.entries = up; if(ioctl(fd, PIO_UNIMAP, &ud)) { #if 0 if (errno == ENOMEM) { /* change advice parameters */ } #endif perror("PIO_UNIMAP"); exit(1); } } static void loadnewfont(int fd) { int unit; char inbuf[32768]; /* primitive */ int inputlth, offset; /* * We used to look at the length of the input file * with stat(); now that we accept compressed files, * just read the entire file. */ inputlth = fread(inbuf, 1, sizeof(inbuf), stdin); if (ferror(stdin)) { perror("Error reading input font"); exit(1); } /* use malloc/realloc in case of giant files; maybe these do not occur: 16kB for the font, and 16kB for the map leaves 32 unicode values for each font position */ if (!feof(stdin)) { perror("Font too large"); exit(1); } /* test for psf first */ { struct psf_header psfhdr; int fontsize; int hastable; int head0, head; if (inputlth < sizeof(struct psf_header)) goto no_psf; psfhdr = * (struct psf_header *) &inbuf[0]; if (!PSF_MAGIC_OK(psfhdr)) goto no_psf; if (psfhdr.mode > PSF_MAXMODE) { fprintf(stderr, "Unsupported psf file mode\n"); exit(1); } fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256); #if !defined( PIO_FONTX ) || defined( __sparc__ ) if (fontsize != 256) { fprintf(stderr, "Only fontsize 256 supported\n"); exit(1); } #endif hastable = (psfhdr.mode & PSF_MODEHASTAB); unit = psfhdr.charsize; head0 = sizeof(struct psf_header); head = head0 + fontsize*unit; if (head > inputlth || (!hastable && head != inputlth)) { fprintf(stderr, "Input file: bad length\n"); exit(1); } do_loadfont(fd, inbuf + head0, unit, fontsize); if (hastable) do_loadtable(fd, inbuf + head, inputlth-head, fontsize); return; } no_psf: /* file with three code pages? */ if (inputlth == 9780) { offset = 40; unit = 16; } else { /* bare font */ if (inputlth & 0377) { fprintf(stderr, "Bad input file size\n"); exit(1); } offset = 0; unit = inputlth/256; } do_loadfont(fd, inbuf+offset, unit, 256); }