1// SPDX-License-Identifier: GPL-2.0
2#include <errno.h>
3#include <stdio.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <sys/ioctl.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <linux/fs.h>
12
13static int set_immutable(const char *path, int immutable)
14{
15 unsigned int flags;
16 int fd;
17 int rc;
18 int error;
19
20 fd = open(path, O_RDONLY);
21 if (fd < 0)
22 return fd;
23
24 rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
25 if (rc < 0) {
26 error = errno;
27 close(fd);
28 errno = error;
29 return rc;
30 }
31
32 if (immutable)
33 flags |= FS_IMMUTABLE_FL;
34 else
35 flags &= ~FS_IMMUTABLE_FL;
36
37 rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
38 error = errno;
39 close(fd);
40 errno = error;
41 return rc;
42}
43
44static int get_immutable(const char *path)
45{
46 unsigned int flags;
47 int fd;
48 int rc;
49 int error;
50
51 fd = open(path, O_RDONLY);
52 if (fd < 0)
53 return fd;
54
55 rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
56 if (rc < 0) {
57 error = errno;
58 close(fd);
59 errno = error;
60 return rc;
61 }
62 close(fd);
63 if (flags & FS_IMMUTABLE_FL)
64 return 1;
65 return 0;
66}
67
68int main(int argc, char **argv)
69{
70 const char *path;
71 char buf[5];
72 int fd, rc;
73
74 if (argc < 2) {
75 fprintf(stderr, "usage: %s <path>\n", argv[0]);
76 return EXIT_FAILURE;
77 }
78
79 path = argv[1];
80
81 /* attributes: EFI_VARIABLE_NON_VOLATILE |
82 * EFI_VARIABLE_BOOTSERVICE_ACCESS |
83 * EFI_VARIABLE_RUNTIME_ACCESS
84 */
85 *(uint32_t *)buf = 0x7;
86 buf[4] = 0;
87
88 /* create a test variable */
89 fd = open(path, O_WRONLY | O_CREAT, 0600);
90 if (fd < 0) {
91 perror("open(O_WRONLY)");
92 return EXIT_FAILURE;
93 }
94
95 rc = write(fd, buf, sizeof(buf));
96 if (rc != sizeof(buf)) {
97 perror("write");
98 return EXIT_FAILURE;
99 }
100
101 close(fd);
102
103 rc = get_immutable(path);
104 if (rc < 0) {
105 perror("ioctl(FS_IOC_GETFLAGS)");
106 return EXIT_FAILURE;
107 } else if (rc) {
108 rc = set_immutable(path, immutable: 0);
109 if (rc < 0) {
110 perror("ioctl(FS_IOC_SETFLAGS)");
111 return EXIT_FAILURE;
112 }
113 }
114
115 fd = open(path, O_RDONLY);
116 if (fd < 0) {
117 perror("open");
118 return EXIT_FAILURE;
119 }
120
121 if (unlink(path) < 0) {
122 perror("unlink");
123 return EXIT_FAILURE;
124 }
125
126 rc = read(fd, buf, sizeof(buf));
127 if (rc > 0) {
128 fprintf(stderr, "reading from an unlinked variable "
129 "shouldn't be possible\n");
130 return EXIT_FAILURE;
131 }
132
133 return EXIT_SUCCESS;
134}
135

source code of linux/tools/testing/selftests/efivarfs/open-unlink.c