]> git.ozlabs.org Git - petitboot/blob - lib/efi/efivar.c
lib/efi: Move magic to implementation
[petitboot] / lib / efi / efivar.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; version 2 of the License.
5  *
6  *  This program is distributed in the hope that it will be useful,
7  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
8  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  *  GNU General Public License for more details.
10  *
11  *  You should have received a copy of the GNU General Public License
12  *  along with this program; if not, write to the Free Software
13  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  *
15  *  Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights
16  *  reserved.
17  *  Author: Ge Song <ge.song@hxt-semitech.com>
18  */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <linux/fs.h>
27 #include <linux/magic.h>
28 #include <sys/ioctl.h>
29 #include <sys/stat.h>
30 #include <sys/statfs.h>
31
32 #include "efivar.h"
33 #include "log/log.h"
34 #include "talloc/talloc.h"
35
36 #ifndef EFIVARFS_MAGIC
37 #define EFIVARFS_MAGIC 0xde5e81e4
38 #endif
39
40 void efi_init_mount(struct efi_mount *efi_mount, const char *path,
41         const char *guid)
42 {
43         assert(efi_mount);
44
45         efi_mount->path = path;
46         efi_mount->guid = guid;
47
48         pb_debug_fn("%s--%s", efi_mount->path, efi_mount->guid);
49 }
50
51 bool efi_check_mount_magic(const struct efi_mount *efi_mount, bool check_magic)
52 {
53         struct statfs s;
54
55         assert(efi_mount);
56
57         if (!efi_mount->guid) {
58                 pb_debug_fn("guid not set\n");
59                 return false;
60         }
61
62         if (access(efi_mount->path, R_OK | W_OK)) {
63                 pb_debug_fn("Can't access %s\n", efi_mount->path);
64                 return false;
65         }
66
67         memset(&s, '\0', sizeof(s));
68         if (statfs(efi_mount->path, &s)) {
69                 pb_debug_fn("statfs failed: %s: (%d) %s\n", efi_mount->path,
70                         errno, strerror(errno));
71                 return false;
72         }
73
74         if (check_magic && s.f_type != EFIVARFS_MAGIC) {
75                 pb_debug_fn("Bad magic = 0x%lx\n", (unsigned long)s.f_type);
76                 return false;
77         }
78
79         return true;
80 }
81
82 static int efi_open(const struct efi_mount *efi_mount, const char *name,
83         int flags, mode_t mode, char **path)
84 {
85         int fd;
86
87         assert(efi_mount);
88
89         *path = NULL;
90
91         if (!efi_mount->path || !efi_mount->guid)
92                 return -1;
93
94         *path = talloc_asprintf(NULL, "%s/%s-%s", efi_mount->path, name,
95                 efi_mount->guid);
96         if (!*path)
97                 return -1;
98
99         flags = flags ? flags : O_RDONLY | O_NONBLOCK;
100
101         fd = open(*path, flags, mode);
102
103         if (fd < 0) {
104                 pb_log("%s: open failed '%s': (%d) %s\n", __func__, *path,
105                         errno, strerror(errno));
106                 talloc_free(*path);
107                 *path = NULL;
108                 return -1;
109         }
110
111         return fd;
112 }
113
114 int efi_del_variable(const struct efi_mount *efi_mount, const char *name)
115 {
116         int fd, flag;
117         int rc = -1;
118         char *path;
119
120         assert(efi_mount);
121
122         fd = efi_open(efi_mount, name, 0, 0, &path);
123         if (fd < 0)
124                 return -1;
125
126         rc = ioctl(fd, FS_IOC_GETFLAGS, &flag);
127         if (rc == -1 && errno == ENOTTY) {
128                 pb_debug_fn("'%s' does not support ioctl_iflags.\n",
129                         efi_mount->path);
130                 goto delete;
131         } else if (rc == -1) {
132                 pb_log_fn("FS_IOC_GETFLAGS failed: (%d) %s\n", errno,
133                         strerror(errno));
134                 goto exit;
135         }
136
137         flag &= ~FS_IMMUTABLE_FL;
138         rc = ioctl(fd, FS_IOC_SETFLAGS, &flag);
139         if (rc == -1) {
140                 pb_log_fn("FS_IOC_SETFLAGS failed: (%d) %s\n", errno,
141                         strerror(errno));
142                 goto exit;
143         }
144
145 delete:
146         close(fd);
147         fd = 0;
148         rc = unlink(path);
149         if (rc == -1) {
150                 pb_log_fn("unlink failed: (%d) %s\n", errno, strerror(errno));
151                 goto exit;
152         }
153         pb_debug_fn("Deleted: '%s'\n", name);
154 exit:
155         talloc_free(path);
156         close(fd);
157         return rc;
158 }
159
160 int efi_get_variable(void *ctx, const struct efi_mount *efi_mount,
161         const char *name, struct efi_data **efi_data)
162 {
163         int fd;
164         int rc = -1;
165         char *p;
166         char buf[4096];
167         ssize_t total;
168         ssize_t count;
169         char *path;
170
171         assert(efi_mount);
172
173         *efi_data = NULL;
174
175         fd = efi_open(efi_mount, name, 0, 0, &path);
176         if (fd < 0)
177                 return -1;
178
179         for (p = buf, total = 0; ; p = buf + count) {
180                 count = read(fd, p, sizeof(buf) - total);
181                 if (count < 0) {
182                         if (errno == EAGAIN || errno == EWOULDBLOCK)
183                                 continue;
184
185                         pb_log("%s: read failed %s: (%ld) (%d) %s\n", __func__, path,
186                                 count, errno, strerror(errno));
187                         goto exit;
188                 }
189                 if (p >= (buf + sizeof(buf))) {
190                         pb_log("%s: buffer full %s: (%ld)\n", __func__, path,
191                                 sizeof(buf));
192                         goto exit;
193                 }
194                 if (count == 0)
195                         break;
196                 total += count;
197         };
198
199         *efi_data = (void*)talloc_zero_array(ctx, char,
200                 sizeof (struct efi_data) + total);
201
202         (*efi_data)->attributes = *(uint32_t *)buf;
203         (*efi_data)->data_size = total;
204         (*efi_data)->data = (*efi_data)->fill;
205         memcpy((*efi_data)->data, buf + sizeof (uint32_t), total);
206         pb_debug_fn("Found: '%s'='%s'\n", name, (const char *)(*efi_data)->data);
207
208         rc = 0;
209 exit:
210         talloc_free(path);
211         close(fd);
212         return rc;
213 }
214
215 int efi_set_variable(const struct efi_mount *efi_mount, const char *name,
216                 const struct efi_data *efi_data)
217 {
218         int rc = -1;
219         int fd;
220         ssize_t count;
221         void *buf;
222         size_t bufsize;
223         char *path;
224
225         assert(efi_mount);
226
227         efi_del_variable(efi_mount, name);
228
229         fd = efi_open(efi_mount, name, O_CREAT | O_WRONLY,
230                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &path);
231         if (fd < 0)
232                 return -1;
233
234         bufsize = sizeof(uint32_t) + efi_data->data_size;
235         buf = talloc_size(path, bufsize);
236         if (!buf)
237                 goto exit;
238
239         *(uint32_t *)buf = efi_data->attributes;
240         memcpy(buf + sizeof(uint32_t), efi_data->data, efi_data->data_size);
241
242         count = write(fd, buf, bufsize);
243         if ((size_t)count != bufsize) {
244                 pb_log("%s: write failed %s: (%ld) (%d) %s\n", __func__, name,
245                         count, errno, strerror(errno));
246                 goto exit;
247         }
248         rc = 0;
249         pb_debug_fn("Set: '%s'='%s'\n", name,  (const char *)efi_data->data);
250
251 exit:
252         talloc_free(path);
253         close(fd);
254         return rc;
255 }