Add FoundationDB stuff
[slow/toolbox.git] / xattr.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <stdbool.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <dirent.h>
10 #include <sys/types.h>
11 #include <sys/xattr.h>
12 #include <sys/socket.h>
13 #include <signal.h>
14
15 #define ERR_USAGE       1
16 #define ERR_SYSCALL     2
17 #define ERR_CALL        3
18 #define ERR_FATAL       4
19
20 #define ERROR(err, ...)                                                 \
21         do {                                                            \
22                 do_log(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__);  \
23                 exit(err);                                              \
24         } while (0)
25
26 #define LOG(...)                                                        \
27         do {                                                            \
28                 do_log(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__);  \
29         } while (0)
30
31 #define FREE(p)                         \
32         do {                            \
33                 free(p);                \
34                 p = 0;                  \
35         } while (0)
36
37 static void do_log(const char *file, int line, const char *func, const char *fmt, ...)
38 {
39         char *message;
40         va_list args;
41         int len;
42
43         va_start(args, fmt);
44         len = vasprintf(&message, fmt, args);
45         va_end(args);
46         if (len == -1) {
47                 exit(ERR_FATAL);
48         }
49
50         printf("%s:%d(%s): %s\n", file, line, func, message);
51         free(message);
52 }
53
54 static int run_child(const char *path, int fd)
55 {
56         ssize_t nwritten;
57         char c;
58         int ret;
59
60         c = (getpid() % 10) + 48;
61
62         ret = setxattr(path, "user.test", &c, 1, 0);
63         if (ret != 0) {
64                 ERROR(ERR_SYSCALL,
65                       "setxattr failed: %s\n",
66                       strerror(errno));
67         }
68
69         /* Tell parent what we wrote */
70         nwritten = write(fd, &c, 1);
71         if (nwritten != 1) {
72                 ERROR(ERR_SYSCALL,
73                       "write failed: %s\n",
74                       strerror(errno));
75         }
76
77         return 0;
78 }
79
80 static int run_parent(const char *path)
81 {
82         pid_t child;
83         int fds[2];
84         int child_fd;
85         ssize_t nwritten;
86         ssize_t nread;
87         int ret;
88
89         while (true) {
90                 char expected;
91                 char got;
92
93                 ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
94                 if (ret != 0) {
95                         ERROR(ERR_SYSCALL, "socketpair failed: %s\n", strerror(errno));
96                 }
97
98                 child = fork();
99                 if (child == -1) {
100                         ERROR(ERR_SYSCALL, "fork failed: %s\n", strerror(errno));
101                 }
102                 if (child == 0) {
103                         close(fds[0]);
104                         return run_child(path, fds[1]);
105                 }
106
107                 close(fds[1]);
108                 child_fd = fds[0];
109
110                 /* Read expected value from child */
111                 nread = read(child_fd, &expected, 1);
112                 if (nread != 1) {
113                         return 0;
114                 }
115
116                 /* Wait for the child to go away*/
117                 nread = read(child_fd, &expected, 1);
118                 if (nread != 0) {
119                         ERROR(ERR_CALL, "Non-0 read\n");
120                         return 0;
121                 }
122
123                 usleep(10000);
124
125                 nread = getxattr(path, "user.test", &got, 1);
126                 if (nread == -1) {
127                         ERROR(ERR_SYSCALL,
128                               "getxattr failed: %s\n",
129                               strerror(errno));
130                 }
131
132                 printf("expected: %c, got: %c\n", expected, got);
133                 if (expected != got) {
134                         ERROR(ERR_FATAL,
135                               "Expected: %c, got: %c\n",
136                               expected, got);
137                 }
138
139                 close(child_fd);
140         }
141
142         return 0;
143 }
144
145 int main(int argc, char **argv)
146 {
147         char *path = NULL;
148         struct sigaction sa;
149         int ret;
150
151         if (argc != 2) {
152                 ERROR(ERR_USAGE, "Usage: %s <PATH>\n", argv[0]);
153         }
154         path = argv[1];
155
156         sa = (struct sigaction) {
157                 .sa_handler = SIG_IGN,
158                 .sa_flags = SA_NOCLDWAIT,
159         };
160
161         ret = sigaction(SIGCHLD, &sa, NULL);
162         if (ret != 0) {
163                 ERROR(ERR_SYSCALL, "sigaction failed: %s\n", strerror(errno));
164         }
165
166
167         return run_parent(path);
168 }