1/*-
2 * Copyright (c) 2010 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/ioctl.h>
31#include <sys/types.h>
32#include <fcntl.h>
33#include <stddef.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37
38#include "libefi_int.h"
39
40static int __iofd = -1;
41
42static void
43iodev_fd_close(void)
44{
45
46	close(__iofd);
47}
48
49static int
50iodev_fd(int *fd)
51{
52
53	*fd = __iofd;
54	if (__iofd != -1)
55		return (0);
56
57	__iofd = open("/dev/io", O_RDWR);
58	if (__iofd == -1)
59		return (errno);
60
61	atexit(iodev_fd_close);
62	*fd = __iofd;
63	return (0);
64}
65
66int
67libefi_ucs2_to_utf8(u_short *nm, size_t *szp, char *name)
68{
69	size_t len, sz;
70	u_short c;
71
72	len = 0;
73	sz = *szp;
74	while (*nm) {
75		c = *nm++;
76		if (c > 0x7ff) {
77			if (len++ < sz)
78				*name++ = 0xE0 | (c >> 12);
79			if (len++ < sz)
80				*name++ = 0x80 | ((c >> 6) & 0x3f);
81			if (len++ < sz)
82				*name++ = 0x80 | (c & 0x3f);
83		} else if (c > 0x7f) {
84			if (len++ < sz)
85				*name++ = 0xC0 | ((c >> 6) & 0x1f);
86			if (len++ < sz)
87				*name++ = 0x80 | (c & 0x3f);
88		} else {
89			if (len++ < sz)
90				*name++ = (c & 0x7f);
91		}
92	}
93	if (len++ < sz)
94		*name++ = 0;
95
96	*szp = len;
97	return ((len <= sz) ? 0 : EOVERFLOW);
98}
99
100int
101libefi_utf8_to_ucs2(char *name, size_t *szp, u_short **nmp)
102{
103	u_short *nm;
104	size_t sz;
105	uint32_t ucs4;
106	int c, bytes;
107
108	*szp = sz = (*szp == 0) ? strlen(name) * 2 + 2 : *szp;
109	*nmp = nm = malloc(sz);
110
111	ucs4 = 0;
112	bytes = 0;
113	while (sz > 1 && *name != '\0') {
114		c = *name++;
115		/*
116		 * Conditionalize on the two major character types:
117		 * initial and followup characters.
118		 */
119		if ((c & 0xc0) != 0x80) {
120			/* Initial characters. */
121			if (bytes != 0) {
122				free(nm);
123				return (EILSEQ);
124			}
125			if ((c & 0xf8) == 0xf0) {
126				ucs4 = c & 0x07;
127				bytes = 3;
128			} else if ((c & 0xf0) == 0xe0) {
129				ucs4 = c & 0x0f;
130				bytes = 2;
131			} else if ((c & 0xe0) == 0xc0) {
132				ucs4 = c & 0x1f;
133				bytes = 1;
134			} else {
135				ucs4 = c & 0x7f;
136				bytes = 0;
137			}
138		} else {
139			/* Followup characters. */
140			if (bytes > 0) {
141				ucs4 = (ucs4 << 6) + (c & 0x3f);
142				bytes--;
143			} else if (bytes == 0) {
144				free(nm);
145				return (EILSEQ);
146			}
147		}
148		if (bytes == 0) {
149			if (ucs4 > 0xffff) {
150				free(nm);
151				return (EILSEQ);
152			}
153			*nm++ = (u_short)ucs4;
154			sz -= 2;
155		}
156	}
157	if (sz < 2) {
158		free(nm);
159		return (EDOOFUS);
160	}
161	*nm = 0;
162	return (0);
163}
164
165int
166libefi_efivar(struct iodev_efivar_req *req)
167{
168	int error, fd;
169
170	error = iodev_fd(&fd);
171	if (!error)
172		error = (ioctl(fd, IODEV_EFIVAR, req) == -1) ? errno : 0;
173	if (!error)
174		error = req->result;
175	return (error);
176}
177