1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define LOG_ERR(func, err) do { \
fprintf (stderr, "%s : returned error (%s)\n", func, strerror(err)); \
exit (err); \
} while (0)
int fd;
struct flock lock;
char *buf = "ten bytes!";
char *fname = "/mnt/glusterfs/0/mand.lock";
int open_flags, child, err, status, blocked = 0;
int do_child (char *argv[]) {
/* Initialize file open flags */
if (strcmp (argv[2], "BLOCK") == 0)
open_flags = O_RDWR;
else if (strcmp (argv[2], "TRUNC") == 0)
open_flags = O_RDWR | O_TRUNC | O_NONBLOCK;
else if (strcmp (argv[2], "NONE") == 0)
open_flags = O_RDWR | O_NONBLOCK;
else
LOG_ERR ("Invalid option:", EINVAL);
/* Open the file */
fd = open (fname, open_flags);
if (fd == -1)
LOG_ERR ("Child open", errno);
/* Perform the file operation*/
if (strcmp (argv[3], "READ") == 0) {
buf = NULL;
err = read (fd, buf, 10);
if (err == -1)
LOG_ERR ("Child read", errno);
} else if (strcmp (argv[3], "WRITE") == 0) {
err = write (fd, buf, 10);
if (err == -1)
LOG_ERR ("Child write", errno);
} else if (strcmp (argv[3], "FTRUNCATE") == 0) {
err = ftruncate (fd, 5);
if (err)
LOG_ERR ("Child ftruncate", errno);
} else
LOG_ERR ("Invalid operation:", EINVAL);
/* Close child fd */
err = close (fd);
if (err)
LOG_ERR ("Child close", errno);
/* Exit success */
exit (0);
}
int main (int argc, char *argv[]) {
if (argc < 4) {
fprintf (stderr, "Wrong usage: Use as ./mandatory-lock "
"<RD_LCK/WR_LCK> <BLOCK/TRUNC/NONE> "
"<READ/WRITE/FTRUNCATE\n");
exit(EINVAL);
}
/* Create an empty lock file */
fd = open (fname, O_CREAT | O_RDWR, 0755);
if (fd == -1)
LOG_ERR ("Parent create", errno);
/* Determine the type of lock */
if (strcmp (argv[1], "RD_LCK") == 0)
lock.l_type = F_RDLCK;
else if (strcmp (argv[1], "WR_LCK") == 0)
lock.l_type = F_WRLCK;
else
LOG_ERR ("Parent lock type", EINVAL);
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 0L;
/* Let parent acquire the initial lock */
err = fcntl (fd, F_SETLK, &lock);
if (err)
LOG_ERR ("Parent lock", errno);
/* Now fork a child */
child = fork ();
if (child == 0)
/* Perform the child operations */
do_child (argv);
else {
/* If blocking mode, then sleep for 2 seconds
* and wait for the child */
if (strcmp (argv[2], "NONE") != 0) {
sleep (2);
if (waitpid (child, &status, WNOHANG) == 0)
blocked = 1;
/* Release the parent lock so that the
* child can terminate */
lock.l_type = F_UNLCK;
err = fcntl (fd, F_SETLK, &lock);
if (err)
LOG_ERR ("Parent unlock", errno);
}
/* Wait for child to finish */
waitpid (child, &status, 0);
/* Close the parent fd */
err = close (fd);
if (err)
LOG_ERR ("Parent close", errno);
/* Remove the lock file*/
err = unlink (fname);
if (err)
LOG_ERR ("Parent unlink", errno);
/* If not blocked, exit with child exit status*/
errno = WEXITSTATUS(status);
/* If blocked, exit with corresponding
* error code */
if (blocked)
errno = EWOULDBLOCK;
if (errno != 0)
printf ("%s\n", strerror(errno));
exit (errno);
}
}
|