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