162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <errno.h>
362306a36Sopenharmony_ci#include <stdio.h>
462306a36Sopenharmony_ci#include <stdint.h>
562306a36Sopenharmony_ci#include <stdlib.h>
662306a36Sopenharmony_ci#include <unistd.h>
762306a36Sopenharmony_ci#include <sys/ioctl.h>
862306a36Sopenharmony_ci#include <sys/types.h>
962306a36Sopenharmony_ci#include <sys/stat.h>
1062306a36Sopenharmony_ci#include <fcntl.h>
1162306a36Sopenharmony_ci#include <linux/fs.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic int set_immutable(const char *path, int immutable)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	unsigned int flags;
1662306a36Sopenharmony_ci	int fd;
1762306a36Sopenharmony_ci	int rc;
1862306a36Sopenharmony_ci	int error;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	fd = open(path, O_RDONLY);
2162306a36Sopenharmony_ci	if (fd < 0)
2262306a36Sopenharmony_ci		return fd;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
2562306a36Sopenharmony_ci	if (rc < 0) {
2662306a36Sopenharmony_ci		error = errno;
2762306a36Sopenharmony_ci		close(fd);
2862306a36Sopenharmony_ci		errno = error;
2962306a36Sopenharmony_ci		return rc;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if (immutable)
3362306a36Sopenharmony_ci		flags |= FS_IMMUTABLE_FL;
3462306a36Sopenharmony_ci	else
3562306a36Sopenharmony_ci		flags &= ~FS_IMMUTABLE_FL;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
3862306a36Sopenharmony_ci	error = errno;
3962306a36Sopenharmony_ci	close(fd);
4062306a36Sopenharmony_ci	errno = error;
4162306a36Sopenharmony_ci	return rc;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int get_immutable(const char *path)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	unsigned int flags;
4762306a36Sopenharmony_ci	int fd;
4862306a36Sopenharmony_ci	int rc;
4962306a36Sopenharmony_ci	int error;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	fd = open(path, O_RDONLY);
5262306a36Sopenharmony_ci	if (fd < 0)
5362306a36Sopenharmony_ci		return fd;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
5662306a36Sopenharmony_ci	if (rc < 0) {
5762306a36Sopenharmony_ci		error = errno;
5862306a36Sopenharmony_ci		close(fd);
5962306a36Sopenharmony_ci		errno = error;
6062306a36Sopenharmony_ci		return rc;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	close(fd);
6362306a36Sopenharmony_ci	if (flags & FS_IMMUTABLE_FL)
6462306a36Sopenharmony_ci		return 1;
6562306a36Sopenharmony_ci	return 0;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciint main(int argc, char **argv)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	const char *path;
7162306a36Sopenharmony_ci	char buf[5];
7262306a36Sopenharmony_ci	int fd, rc;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (argc < 2) {
7562306a36Sopenharmony_ci		fprintf(stderr, "usage: %s <path>\n", argv[0]);
7662306a36Sopenharmony_ci		return EXIT_FAILURE;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	path = argv[1];
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* attributes: EFI_VARIABLE_NON_VOLATILE |
8262306a36Sopenharmony_ci	 *		EFI_VARIABLE_BOOTSERVICE_ACCESS |
8362306a36Sopenharmony_ci	 *		EFI_VARIABLE_RUNTIME_ACCESS
8462306a36Sopenharmony_ci	 */
8562306a36Sopenharmony_ci	*(uint32_t *)buf = 0x7;
8662306a36Sopenharmony_ci	buf[4] = 0;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* create a test variable */
8962306a36Sopenharmony_ci	fd = open(path, O_WRONLY | O_CREAT, 0600);
9062306a36Sopenharmony_ci	if (fd < 0) {
9162306a36Sopenharmony_ci		perror("open(O_WRONLY)");
9262306a36Sopenharmony_ci		return EXIT_FAILURE;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	rc = write(fd, buf, sizeof(buf));
9662306a36Sopenharmony_ci	if (rc != sizeof(buf)) {
9762306a36Sopenharmony_ci		perror("write");
9862306a36Sopenharmony_ci		return EXIT_FAILURE;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	close(fd);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	rc = get_immutable(path);
10462306a36Sopenharmony_ci	if (rc < 0) {
10562306a36Sopenharmony_ci		perror("ioctl(FS_IOC_GETFLAGS)");
10662306a36Sopenharmony_ci		return EXIT_FAILURE;
10762306a36Sopenharmony_ci	} else if (rc) {
10862306a36Sopenharmony_ci		rc = set_immutable(path, 0);
10962306a36Sopenharmony_ci		if (rc < 0) {
11062306a36Sopenharmony_ci			perror("ioctl(FS_IOC_SETFLAGS)");
11162306a36Sopenharmony_ci			return EXIT_FAILURE;
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	fd = open(path, O_RDONLY);
11662306a36Sopenharmony_ci	if (fd < 0) {
11762306a36Sopenharmony_ci		perror("open");
11862306a36Sopenharmony_ci		return EXIT_FAILURE;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (unlink(path) < 0) {
12262306a36Sopenharmony_ci		perror("unlink");
12362306a36Sopenharmony_ci		return EXIT_FAILURE;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	rc = read(fd, buf, sizeof(buf));
12762306a36Sopenharmony_ci	if (rc > 0) {
12862306a36Sopenharmony_ci		fprintf(stderr, "reading from an unlinked variable "
12962306a36Sopenharmony_ci				"shouldn't be possible\n");
13062306a36Sopenharmony_ci		return EXIT_FAILURE;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return EXIT_SUCCESS;
13462306a36Sopenharmony_ci}
135