1ac69908d1f62f87fb770f0cc547c606f8537cfc
[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 <errno.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <linux/fs.h>
26 #include <sys/ioctl.h>
27
28 #include "efivar.h"
29 #include "log/log.h"
30 #include "talloc/talloc.h"
31
32 static const char *efivarfs_path;
33
34 inline void set_efivarfs_path(const char *path)
35 {
36         efivarfs_path = path;
37 }
38
39 inline const char *get_efivarfs_path(void)
40 {
41
42         return efivarfs_path;
43 }
44
45 int efi_del_variable(void *ctx, const char *guidstr,
46                 const char *name)
47 {
48         int fd, flag, errno_value;
49         int rc = -1;
50         const char *dir;
51         char *path;
52
53         dir = get_efivarfs_path();
54         if (!dir)
55                 return -1;
56
57         path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr);
58         if (!path)
59                 return -1;
60
61         fd = open(path, O_RDONLY|O_NONBLOCK);
62         if (fd == -1)
63                 goto err;
64
65         rc = ioctl(fd, FS_IOC_GETFLAGS, &flag);
66         if (rc == -1)
67                 goto err;
68
69         flag &= ~FS_IMMUTABLE_FL;
70         rc = ioctl(fd, FS_IOC_SETFLAGS, &flag);
71         if (rc == -1)
72                 goto err;
73
74         close(fd);
75         rc = unlink(path);
76
77 err:
78         errno_value = errno;
79         if (fd > 0)
80                 close(fd);
81
82         errno = errno_value;
83         return rc;
84 }
85
86 int efi_get_variable(void *ctx, const char *guidstr, const char *name,
87                 uint8_t **data, size_t *data_size, uint32_t *attributes)
88 {
89         int fd, errno_value;
90         int rc = -1;
91         void *p, *buf;
92         size_t bufsize = 4096;
93         size_t filesize = 0;
94         ssize_t sz;
95         const char *dir;
96         char *path;
97
98         dir = get_efivarfs_path();
99         if (!dir)
100                 return EFAULT;
101
102         path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr);
103         if (!path)
104                 return ENOMEM;
105
106         fd = open(path, O_RDONLY|O_NONBLOCK);
107         if (fd < 0)
108                 goto err;
109
110         buf = talloc_size(ctx, bufsize);
111         if (!buf)
112                 goto err;
113
114         do {
115                 p = buf + filesize;
116                 sz = read(fd, p, bufsize);
117                 if (sz < 0 && errno == EAGAIN) {
118                         continue;
119                 } else if (sz == 0) {
120                         break;
121                 }
122                 filesize += sz;
123         } while (1);
124
125         *attributes = *(uint32_t *)buf;
126         *data = (uint8_t *)(buf + sizeof(uint32_t));
127         *data_size = strlen(buf + sizeof(uint32_t));
128         rc = 0;
129
130 err:
131         errno_value = errno;
132         if (fd > 0)
133                 close(fd);
134
135         errno = errno_value;
136         return rc;
137 }
138
139 int efi_set_variable(void *ctx, const char *guidstr, const char *name,
140                 uint8_t *data, size_t data_size, uint32_t attributes)
141 {
142         int rc = -1, errno_value;
143         int fd = -1;
144         ssize_t len;
145         const char *dir;
146         char *path;
147         void *buf;
148         size_t bufsize;
149         mode_t mask = 0644;
150
151         dir = get_efivarfs_path();
152         if (!dir)
153                 return EFAULT;
154
155         path = talloc_asprintf(ctx, "%s%s-%s", dir, name, guidstr);
156         if (!path)
157                 return ENOMEM;
158
159         if (!access(path, F_OK)) {
160                 rc = efi_del_variable(ctx, guidstr, name);
161                 if (rc < 0) {
162                         goto err;
163                 }
164         }
165
166         fd = open(path, O_CREAT|O_WRONLY, mask);
167         if (fd < 0)
168                 goto err;
169
170         bufsize = sizeof(uint32_t) + data_size;
171         buf = talloc_size(ctx, bufsize);
172         if (!buf)
173                 goto err;
174
175         *(uint32_t *)buf = attributes;
176         memcpy(buf + sizeof(uint32_t), data, data_size);
177
178         len = write(fd, buf, bufsize);
179         if ((size_t)len != bufsize)
180                 goto err;
181         else
182                 rc = 0;
183
184 err:
185         errno_value = errno;
186         if (fd > 0)
187                 close(fd);
188
189         errno = errno_value;
190         return rc;
191 }