1
2
3
4
5
6
7
8
9
10
11
12#include "libbb.h"
13#include <sys/kd.h>
14
15#ifndef KDFONTOP
16#define KDFONTOP 0x4B72
17struct console_font_op {
18 unsigned op;
19 unsigned flags;
20 unsigned width, height;
21 unsigned charcount;
22 unsigned char *data;
23};
24
25#define KD_FONT_OP_SET 0
26#define KD_FONT_OP_GET 1
27#define KD_FONT_OP_SET_DEFAULT 2
28
29#define KD_FONT_OP_COPY 3
30
31#define KD_FONT_FLAG_OLD 0x80000000
32#define KD_FONT_FLAG_DONT_RECALC 1
33
34#endif
35
36
37enum {
38 PSF_MAGIC1 = 0x36,
39 PSF_MAGIC2 = 0x04,
40
41 PSF_MODE512 = 0x01,
42 PSF_MODEHASTAB = 0x02,
43 PSF_MAXMODE = 0x03,
44 PSF_SEPARATOR = 0xffff
45};
46
47struct psf_header {
48 unsigned char magic1, magic2;
49 unsigned char mode;
50 unsigned char charsize;
51};
52
53#define PSF_MAGIC_OK(x) ((x)->magic1 == PSF_MAGIC1 && (x)->magic2 == PSF_MAGIC2)
54
55static void do_loadfont(int fd, unsigned char *inbuf, int unit, int fontsize)
56{
57 char *buf;
58 int i;
59
60 if (unit < 1 || unit > 32)
61 bb_error_msg_and_die("bad character size %d", unit);
62
63 buf = xzalloc(16 * 1024);
64 for (i = 0; i < fontsize; i++)
65 memcpy(buf + (32 * i), inbuf + (unit * i), unit);
66
67 {
68 struct console_font_op cfo;
69
70 cfo.op = KD_FONT_OP_SET;
71 cfo.flags = 0;
72 cfo.width = 8;
73 cfo.height = unit;
74 cfo.charcount = fontsize;
75 cfo.data = (void*)buf;
76#if 0
77 if (!ioctl_or_perror(fd, KDFONTOP, &cfo, "KDFONTOP ioctl failed (will try PIO_FONTX)"))
78 goto ret;
79#else
80 xioctl(fd, KDFONTOP, &cfo);
81#endif
82 }
83
84#if 0
85
86
87
88
89#if defined(PIO_FONTX) && !defined(__sparc__)
90 {
91 struct consolefontdesc cfd;
92
93 cfd.charcount = fontsize;
94 cfd.charheight = unit;
95 cfd.chardata = buf;
96
97 if (!ioctl_or_perror(fd, PIO_FONTX, &cfd, "PIO_FONTX ioctl failed (will try PIO_FONT)"))
98 goto ret;
99 }
100#endif
101 xioctl(fd, PIO_FONT, buf);
102 ret:
103#endif
104 free(buf);
105}
106
107static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize)
108{
109 struct unimapinit advice;
110 struct unimapdesc ud;
111 struct unipair *up;
112 int ct = 0, maxct;
113 int glyph;
114 uint16_t unicode;
115
116 maxct = tailsz;
117 up = xmalloc(maxct * sizeof(struct unipair));
118
119 for (glyph = 0; glyph < fontsize; glyph++) {
120 while (tailsz >= 2) {
121 unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0];
122 tailsz -= 2;
123 inbuf += 2;
124 if (unicode == PSF_SEPARATOR)
125 break;
126 up[ct].unicode = unicode;
127 up[ct].fontpos = glyph;
128 ct++;
129 }
130 }
131
132
133
134
135 advice.advised_hashsize = 0;
136 advice.advised_hashstep = 0;
137 advice.advised_hashlevel = 0;
138 xioctl(fd, PIO_UNIMAPCLR, &advice);
139 ud.entry_ct = ct;
140 ud.entries = up;
141 xioctl(fd, PIO_UNIMAP, &ud);
142}
143
144static void do_load(int fd, struct psf_header *psfhdr, size_t len)
145{
146 int unit;
147 int fontsize;
148 int hastable;
149 unsigned head0, head = head;
150
151
152 if (len >= sizeof(struct psf_header) && PSF_MAGIC_OK(psfhdr)) {
153 if (psfhdr->mode > PSF_MAXMODE)
154 bb_error_msg_and_die("unsupported psf file mode");
155 fontsize = ((psfhdr->mode & PSF_MODE512) ? 512 : 256);
156#if !defined(PIO_FONTX) || defined(__sparc__)
157 if (fontsize != 256)
158 bb_error_msg_and_die("only fontsize 256 supported");
159#endif
160 hastable = (psfhdr->mode & PSF_MODEHASTAB);
161 unit = psfhdr->charsize;
162 head0 = sizeof(struct psf_header);
163
164 head = head0 + fontsize * unit;
165 if (head > len || (!hastable && head != len))
166 bb_error_msg_and_die("input file: bad length");
167 } else {
168
169 if (len == 9780) {
170 head0 = 40;
171 unit = 16;
172 } else {
173
174 if (len & 0377)
175 bb_error_msg_and_die("input file: bad length");
176 head0 = 0;
177 unit = len / 256;
178 }
179 fontsize = 256;
180 hastable = 0;
181 }
182
183 do_loadfont(fd, (unsigned char *)psfhdr + head0, unit, fontsize);
184 if (hastable)
185 do_loadtable(fd, (unsigned char *)psfhdr + head, len - head, fontsize);
186}
187
188#if ENABLE_LOADFONT
189int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
190int loadfont_main(int argc UNUSED_PARAM, char **argv)
191{
192 size_t len;
193 struct psf_header *psfhdr;
194
195
196 opt_complementary = "=0";
197 getopt32(argv, "");
198
199
200
201
202
203
204 len = 32*1024;
205 psfhdr = xmalloc_read(STDIN_FILENO, &len);
206
207 if (!psfhdr)
208 bb_perror_msg_and_die("error reading input font");
209 do_load(get_console_fd_or_die(), psfhdr, len);
210
211 return EXIT_SUCCESS;
212}
213#endif
214
215#if ENABLE_SETFONT
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
251static int ctoi(char *s)
252{
253 if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0')
254 return s[1];
255
256 if (s[0] == 'U' && s[1] == '+') {
257 s[0] = '0';
258 s[1] = 'x';
259 }
260 if (!isdigit(s[0]))
261 return -1;
262 return xstrtoul(s, 0);
263}
264#endif
265
266int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
267int setfont_main(int argc UNUSED_PARAM, char **argv)
268{
269 size_t len;
270 unsigned opts;
271 int fd;
272 struct psf_header *psfhdr;
273 char *mapfilename;
274 const char *tty_name = CURRENT_TTY;
275
276 opt_complementary = "=1";
277 opts = getopt32(argv, "m:C:", &mapfilename, &tty_name);
278 argv += optind;
279
280 fd = xopen_nonblocking(tty_name);
281
282 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) {
283 if (*argv[0] != '/') {
284
285 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts");
286 }
287 }
288
289 len = 32*1024;
290 psfhdr = xmalloc_open_zipped_read_close(*argv, &len);
291 if (!psfhdr)
292 bb_simple_perror_msg_and_die(*argv);
293 do_load(fd, psfhdr, len);
294
295
296 if (opts & 1) {
297 unsigned mode = PIO_SCRNMAP;
298 void *map;
299
300 if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) {
301 if (mapfilename[0] != '/') {
302
303 chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans");
304 }
305 }
306
307 map = xmalloc_open_zipped_read_close(mapfilename, &len);
308 if (!map)
309 bb_simple_perror_msg_and_die(mapfilename);
310
311 if (len == E_TABSZ || len == 2*E_TABSZ) {
312 if (len == 2*E_TABSZ)
313 mode = PIO_UNISCRNMAP;
314 }
315#if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP
316
317
318
319
320
321 else {
322 int i;
323 char *token[2];
324 parser_t *parser;
325
326 if (ENABLE_FEATURE_CLEAN_UP)
327 free(map);
328 map = xmalloc(E_TABSZ * sizeof(unsigned short));
329
330#define unicodes ((unsigned short *)map)
331
332 for (i = 0; i < E_TABSZ; i++)
333 unicodes[i] = 0xf000 + i;
334
335 parser = config_open(mapfilename);
336 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
337
338 int a = ctoi(token[0]);
339 int b = ctoi(token[1]);
340 if (a < 0 || a >= E_TABSZ
341 || b < 0 || b > 65535
342 ) {
343 bb_error_msg_and_die("map format");
344 }
345
346 unicodes[a] = b;
347
348 if (b > 255)
349 mode = PIO_UNISCRNMAP;
350 }
351 if (ENABLE_FEATURE_CLEAN_UP)
352 config_close(parser);
353
354 if (mode != PIO_UNISCRNMAP) {
355#define asciis ((unsigned char *)map)
356 for (i = 0; i < E_TABSZ; i++)
357 asciis[i] = unicodes[i];
358#undef asciis
359 }
360#undef unicodes
361 }
362#endif
363
364
365 xioctl(fd, mode, map);
366
367 if (ENABLE_FEATURE_CLEAN_UP)
368 free(map);
369 }
370
371 return EXIT_SUCCESS;
372}
373#endif
374