1/*
2 * Copyright 2008, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <fcntl.h>
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13
14
15extern const char *__progname;
16
17const char* kTemporaryFile = "/tmp/axels-lock-test";
18
19
20const char*
21type_name(int type)
22{
23	return type == F_RDLCK ? "shared" : type == F_WRLCK
24		? "exclusive" : "remove";
25}
26
27
28int
29do_lock(int fd, int type, off_t start, off_t length)
30{
31	printf("%s lock %lld:%lld\n", type_name(type), start, length);
32
33	struct flock flock;
34	flock.l_type = type;
35	flock.l_whence = SEEK_SET;
36	flock.l_start = start;
37	flock.l_len = length;
38	if (fcntl(fd, F_SETLK, &flock) != 0) {
39		fprintf(stderr, "ERROR: %s lock %lld:%lld failed: %s\n", type_name(type),
40			start, length, strerror(errno));
41		return -1;
42	}
43
44	return 0;
45}
46
47
48int
49shared_lock(int fd, off_t start, off_t length)
50{
51	return do_lock(fd, F_RDLCK, start, length);
52}
53
54
55int
56exclusive_lock(int fd, off_t start, off_t length)
57{
58	return do_lock(fd, F_WRLCK, start, length);
59}
60
61
62int
63remove_lock(int fd, off_t start, off_t length)
64{
65	return do_lock(fd, F_UNLCK, start, length);
66}
67
68
69void
70wait_for_enter()
71{
72	puts("wait for <enter>...");
73	char buffer[64];
74	fgets(buffer, sizeof(buffer), stdin);
75}
76
77
78void
79usage()
80{
81	fprintf(stderr, "usage: %s [shared|exclusive|unlock <start> <length>] "
82		"[wait] [...]\n", __progname);
83	exit(1);
84}
85
86
87bool
88is_command(const char* op, const char* command1, const char* command2)
89{
90	int length = strlen(op);
91	if (length == 0)
92		return false;
93
94	return command1 != NULL && !strncmp(op, command1, length)
95		|| command2 != NULL && !strncmp(op, command2, length);
96}
97
98
99int
100main(int argc, char** argv)
101{
102	int fd = open(kTemporaryFile, O_CREAT | O_RDWR, 0644);
103	if (fd < 0) {
104		fprintf(stderr, "Could not create lock file: %s\n", strerror(errno));
105		return 1;
106	}
107
108	while (argc > 1) {
109		const char* op = argv[1];
110		if (is_command(op, "wait", NULL)) {
111			wait_for_enter();
112			argv++;
113			argc--;
114			continue;
115		}
116		if (argc < 3)
117			usage();
118
119		off_t start = strtoll(argv[2], NULL, 0);
120		off_t length = strtoll(argv[3], NULL, 0);
121		int type = 0;
122		if (is_command(op, "read", "shared"))
123			type = F_RDLCK;
124		else if (is_command(op, "write", "exclusive"))
125			type = F_WRLCK;
126		else if (is_command(op, "unlock", "remove"))
127			type = F_UNLCK;
128		else
129			usage();
130
131		do_lock(fd, type, start, length);
132		argc -= 3;
133		argv += 3;
134	}
135
136	close(fd);
137	return 0;
138}
139
140