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 
12 static 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 
43 static 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 
67 int 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