1716fd348SMartin Matuska /*
2716fd348SMartin Matuska * CDDL HEADER START
3716fd348SMartin Matuska *
4716fd348SMartin Matuska * The contents of this file are subject to the terms of the
5716fd348SMartin Matuska * Common Development and Distribution License (the "License").
6716fd348SMartin Matuska * You may not use this file except in compliance with the License.
7716fd348SMartin Matuska *
8716fd348SMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
10716fd348SMartin Matuska * See the License for the specific language governing permissions
11716fd348SMartin Matuska * and limitations under the License.
12716fd348SMartin Matuska *
13716fd348SMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each
14716fd348SMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15716fd348SMartin Matuska * If applicable, add the following below this CDDL HEADER, with the
16716fd348SMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying
17716fd348SMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner]
18716fd348SMartin Matuska *
19716fd348SMartin Matuska * CDDL HEADER END
20716fd348SMartin Matuska */
21716fd348SMartin Matuska
22716fd348SMartin Matuska /*
23716fd348SMartin Matuska * Copyright 2016 Lawrence Livermore National Security, LLC.
24716fd348SMartin Matuska */
25716fd348SMartin Matuska
26716fd348SMartin Matuska /*
27716fd348SMartin Matuska * An extended attribute (xattr) correctness test. This program creates
28716fd348SMartin Matuska * N files and sets M attrs on them of size S. Optionally is will verify
29716fd348SMartin Matuska * a pattern stored in the xattr.
30716fd348SMartin Matuska */
31716fd348SMartin Matuska #include <stdlib.h>
32716fd348SMartin Matuska #include <stddef.h>
33716fd348SMartin Matuska #include <stdio.h>
34716fd348SMartin Matuska #include <string.h>
35716fd348SMartin Matuska #include <errno.h>
36716fd348SMartin Matuska #include <getopt.h>
37716fd348SMartin Matuska #include <fcntl.h>
38716fd348SMartin Matuska #include <time.h>
39716fd348SMartin Matuska #include <unistd.h>
40716fd348SMartin Matuska #include <sys/xattr.h>
41716fd348SMartin Matuska #include <sys/types.h>
42716fd348SMartin Matuska #include <sys/wait.h>
43716fd348SMartin Matuska #include <sys/stat.h>
44716fd348SMartin Matuska #include <sys/time.h>
45716fd348SMartin Matuska #include <linux/limits.h>
46716fd348SMartin Matuska
47716fd348SMartin Matuska #define ERROR(fmt, ...) \
48716fd348SMartin Matuska fprintf(stderr, "xattrtest: %s:%d: %s: " fmt "\n", \
49716fd348SMartin Matuska __FILE__, __LINE__, \
50716fd348SMartin Matuska __func__, ## __VA_ARGS__);
51716fd348SMartin Matuska
52716fd348SMartin Matuska static const char shortopts[] = "hvycdn:f:x:s:p:t:e:rRko:";
53716fd348SMartin Matuska static const struct option longopts[] = {
54716fd348SMartin Matuska { "help", no_argument, 0, 'h' },
55716fd348SMartin Matuska { "verbose", no_argument, 0, 'v' },
56716fd348SMartin Matuska { "verify", no_argument, 0, 'y' },
57716fd348SMartin Matuska { "nth", required_argument, 0, 'n' },
58716fd348SMartin Matuska { "files", required_argument, 0, 'f' },
59716fd348SMartin Matuska { "xattrs", required_argument, 0, 'x' },
60716fd348SMartin Matuska { "size", required_argument, 0, 's' },
61716fd348SMartin Matuska { "path", required_argument, 0, 'p' },
62716fd348SMartin Matuska { "synccaches", no_argument, 0, 'c' },
63716fd348SMartin Matuska { "dropcaches", no_argument, 0, 'd' },
64716fd348SMartin Matuska { "script", required_argument, 0, 't' },
65716fd348SMartin Matuska { "seed", required_argument, 0, 'e' },
66716fd348SMartin Matuska { "random", no_argument, 0, 'r' },
67716fd348SMartin Matuska { "randomvalue", no_argument, 0, 'R' },
68716fd348SMartin Matuska { "keep", no_argument, 0, 'k' },
69716fd348SMartin Matuska { "only", required_argument, 0, 'o' },
70716fd348SMartin Matuska { 0, 0, 0, 0 }
71716fd348SMartin Matuska };
72716fd348SMartin Matuska
73716fd348SMartin Matuska enum phases {
74716fd348SMartin Matuska PHASE_ALL = 0,
75716fd348SMartin Matuska PHASE_CREATE,
76716fd348SMartin Matuska PHASE_SETXATTR,
77716fd348SMartin Matuska PHASE_GETXATTR,
78716fd348SMartin Matuska PHASE_UNLINK,
79716fd348SMartin Matuska PHASE_INVAL
80716fd348SMartin Matuska };
81716fd348SMartin Matuska
82716fd348SMartin Matuska static int verbose = 0;
83716fd348SMartin Matuska static int verify = 0;
84716fd348SMartin Matuska static int synccaches = 0;
85716fd348SMartin Matuska static int dropcaches = 0;
86716fd348SMartin Matuska static int nth = 0;
87716fd348SMartin Matuska static int files = 1000;
88716fd348SMartin Matuska static int xattrs = 1;
89716fd348SMartin Matuska static int size = 6;
90716fd348SMartin Matuska static int size_is_random = 0;
91716fd348SMartin Matuska static int value_is_random = 0;
92716fd348SMartin Matuska static int keep_files = 0;
93716fd348SMartin Matuska static int phase = PHASE_ALL;
94a0b956f5SMartin Matuska static const char *path = "/tmp/xattrtest";
95a0b956f5SMartin Matuska static const char *script = "/bin/true";
96716fd348SMartin Matuska static char xattrbytes[XATTR_SIZE_MAX];
97716fd348SMartin Matuska
98716fd348SMartin Matuska static int
usage(char * argv0)99716fd348SMartin Matuska usage(char *argv0)
100716fd348SMartin Matuska {
101716fd348SMartin Matuska fprintf(stderr,
102716fd348SMartin Matuska "usage: %s [-hvycdrRk] [-n <nth>] [-f <files>] [-x <xattrs>]\n"
103716fd348SMartin Matuska " [-s <bytes>] [-p <path>] [-t <script> ] [-o <phase>]\n",
104716fd348SMartin Matuska argv0);
105716fd348SMartin Matuska
106716fd348SMartin Matuska fprintf(stderr,
107716fd348SMartin Matuska " --help -h This help\n"
108716fd348SMartin Matuska " --verbose -v Increase verbosity\n"
109716fd348SMartin Matuska " --verify -y Verify xattr contents\n"
110716fd348SMartin Matuska " --nth -n <nth> Print every nth file\n"
111716fd348SMartin Matuska " --files -f <files> Set xattrs on N files\n"
112716fd348SMartin Matuska " --xattrs -x <xattrs> Set N xattrs on each file\n"
113716fd348SMartin Matuska " --size -s <bytes> Set N bytes per xattr\n"
114716fd348SMartin Matuska " --path -p <path> Path to files\n"
115716fd348SMartin Matuska " --synccaches -c Sync caches between phases\n"
116716fd348SMartin Matuska " --dropcaches -d Drop caches between phases\n"
117716fd348SMartin Matuska " --script -t <script> Exec script between phases\n"
118716fd348SMartin Matuska " --seed -e <seed> Random seed value\n"
119716fd348SMartin Matuska " --random -r Randomly sized xattrs [16-size]\n"
120716fd348SMartin Matuska " --randomvalue -R Random xattr values\n"
121716fd348SMartin Matuska " --keep -k Don't unlink files\n"
122716fd348SMartin Matuska " --only -o <num> Only run phase N\n"
123716fd348SMartin Matuska " 0=all, 1=create, 2=setxattr,\n"
124716fd348SMartin Matuska " 3=getxattr, 4=unlink\n\n");
125716fd348SMartin Matuska
126716fd348SMartin Matuska return (1);
127716fd348SMartin Matuska }
128716fd348SMartin Matuska
129716fd348SMartin Matuska static int
parse_args(int argc,char ** argv)130716fd348SMartin Matuska parse_args(int argc, char **argv)
131716fd348SMartin Matuska {
132716fd348SMartin Matuska long seed = time(NULL);
133716fd348SMartin Matuska int c;
134716fd348SMartin Matuska int rc = 0;
135716fd348SMartin Matuska
136716fd348SMartin Matuska while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
137716fd348SMartin Matuska switch (c) {
138716fd348SMartin Matuska case 'h':
139716fd348SMartin Matuska return (usage(argv[0]));
140716fd348SMartin Matuska case 'v':
141716fd348SMartin Matuska verbose++;
142716fd348SMartin Matuska break;
143716fd348SMartin Matuska case 'y':
144716fd348SMartin Matuska verify = 1;
145716fd348SMartin Matuska break;
146716fd348SMartin Matuska case 'n':
147716fd348SMartin Matuska nth = strtol(optarg, NULL, 0);
148716fd348SMartin Matuska break;
149716fd348SMartin Matuska case 'f':
150716fd348SMartin Matuska files = strtol(optarg, NULL, 0);
151716fd348SMartin Matuska break;
152716fd348SMartin Matuska case 'x':
153716fd348SMartin Matuska xattrs = strtol(optarg, NULL, 0);
154716fd348SMartin Matuska break;
155716fd348SMartin Matuska case 's':
156716fd348SMartin Matuska size = strtol(optarg, NULL, 0);
157716fd348SMartin Matuska if (size > XATTR_SIZE_MAX) {
158716fd348SMartin Matuska fprintf(stderr, "Error: the -s value may not "
159716fd348SMartin Matuska "be greater than %d\n", XATTR_SIZE_MAX);
160716fd348SMartin Matuska rc = 1;
161716fd348SMartin Matuska }
162716fd348SMartin Matuska break;
163716fd348SMartin Matuska case 'p':
164a0b956f5SMartin Matuska path = optarg;
165716fd348SMartin Matuska break;
166716fd348SMartin Matuska case 'c':
167716fd348SMartin Matuska synccaches = 1;
168716fd348SMartin Matuska break;
169716fd348SMartin Matuska case 'd':
170716fd348SMartin Matuska dropcaches = 1;
171716fd348SMartin Matuska break;
172716fd348SMartin Matuska case 't':
173a0b956f5SMartin Matuska script = optarg;
174716fd348SMartin Matuska break;
175716fd348SMartin Matuska case 'e':
176716fd348SMartin Matuska seed = strtol(optarg, NULL, 0);
177716fd348SMartin Matuska break;
178716fd348SMartin Matuska case 'r':
179716fd348SMartin Matuska size_is_random = 1;
180716fd348SMartin Matuska break;
181716fd348SMartin Matuska case 'R':
182716fd348SMartin Matuska value_is_random = 1;
183716fd348SMartin Matuska break;
184716fd348SMartin Matuska case 'k':
185716fd348SMartin Matuska keep_files = 1;
186716fd348SMartin Matuska break;
187716fd348SMartin Matuska case 'o':
188716fd348SMartin Matuska phase = strtol(optarg, NULL, 0);
189716fd348SMartin Matuska if (phase <= PHASE_ALL || phase >= PHASE_INVAL) {
190716fd348SMartin Matuska fprintf(stderr, "Error: the -o value must be "
191716fd348SMartin Matuska "greater than %d and less than %d\n",
192716fd348SMartin Matuska PHASE_ALL, PHASE_INVAL);
193716fd348SMartin Matuska rc = 1;
194716fd348SMartin Matuska }
195716fd348SMartin Matuska break;
196716fd348SMartin Matuska default:
197716fd348SMartin Matuska rc = 1;
198716fd348SMartin Matuska break;
199716fd348SMartin Matuska }
200716fd348SMartin Matuska }
201716fd348SMartin Matuska
202716fd348SMartin Matuska if (rc != 0)
203716fd348SMartin Matuska return (rc);
204716fd348SMartin Matuska
205716fd348SMartin Matuska srandom(seed);
206716fd348SMartin Matuska
207716fd348SMartin Matuska if (verbose) {
208716fd348SMartin Matuska fprintf(stdout, "verbose: %d\n", verbose);
209716fd348SMartin Matuska fprintf(stdout, "verify: %d\n", verify);
210716fd348SMartin Matuska fprintf(stdout, "nth: %d\n", nth);
211716fd348SMartin Matuska fprintf(stdout, "files: %d\n", files);
212716fd348SMartin Matuska fprintf(stdout, "xattrs: %d\n", xattrs);
213716fd348SMartin Matuska fprintf(stdout, "size: %d\n", size);
214716fd348SMartin Matuska fprintf(stdout, "path: %s\n", path);
215716fd348SMartin Matuska fprintf(stdout, "synccaches: %d\n", synccaches);
216716fd348SMartin Matuska fprintf(stdout, "dropcaches: %d\n", dropcaches);
217716fd348SMartin Matuska fprintf(stdout, "script: %s\n", script);
218716fd348SMartin Matuska fprintf(stdout, "seed: %ld\n", seed);
219716fd348SMartin Matuska fprintf(stdout, "random size: %d\n", size_is_random);
220716fd348SMartin Matuska fprintf(stdout, "random value: %d\n", value_is_random);
221716fd348SMartin Matuska fprintf(stdout, "keep: %d\n", keep_files);
222716fd348SMartin Matuska fprintf(stdout, "only: %d\n", phase);
223716fd348SMartin Matuska fprintf(stdout, "%s", "\n");
224716fd348SMartin Matuska }
225716fd348SMartin Matuska
226716fd348SMartin Matuska return (rc);
227716fd348SMartin Matuska }
228716fd348SMartin Matuska
229716fd348SMartin Matuska static int
drop_caches(void)230716fd348SMartin Matuska drop_caches(void)
231716fd348SMartin Matuska {
232716fd348SMartin Matuska char file[] = "/proc/sys/vm/drop_caches";
233716fd348SMartin Matuska int fd, rc;
234716fd348SMartin Matuska
235716fd348SMartin Matuska fd = open(file, O_WRONLY);
236716fd348SMartin Matuska if (fd == -1) {
237716fd348SMartin Matuska ERROR("Error %d: open(\"%s\", O_WRONLY)\n", errno, file);
238716fd348SMartin Matuska return (errno);
239716fd348SMartin Matuska }
240716fd348SMartin Matuska
241716fd348SMartin Matuska rc = write(fd, "3", 1);
242716fd348SMartin Matuska if ((rc == -1) || (rc != 1)) {
243716fd348SMartin Matuska ERROR("Error %d: write(%d, \"3\", 1)\n", errno, fd);
244716fd348SMartin Matuska (void) close(fd);
245716fd348SMartin Matuska return (errno);
246716fd348SMartin Matuska }
247716fd348SMartin Matuska
248716fd348SMartin Matuska rc = close(fd);
249716fd348SMartin Matuska if (rc == -1) {
250716fd348SMartin Matuska ERROR("Error %d: close(%d)\n", errno, fd);
251716fd348SMartin Matuska return (errno);
252716fd348SMartin Matuska }
253716fd348SMartin Matuska
254716fd348SMartin Matuska return (0);
255716fd348SMartin Matuska }
256716fd348SMartin Matuska
257716fd348SMartin Matuska static int
run_process(const char * path,char * argv[])258716fd348SMartin Matuska run_process(const char *path, char *argv[])
259716fd348SMartin Matuska {
260716fd348SMartin Matuska pid_t pid;
261716fd348SMartin Matuska int rc, devnull_fd;
262716fd348SMartin Matuska
263716fd348SMartin Matuska pid = fork();
264716fd348SMartin Matuska if (pid == 0) {
265716fd348SMartin Matuska devnull_fd = open("/dev/null", O_WRONLY);
266716fd348SMartin Matuska
267716fd348SMartin Matuska if (devnull_fd < 0)
268716fd348SMartin Matuska _exit(-1);
269716fd348SMartin Matuska
270716fd348SMartin Matuska (void) dup2(devnull_fd, STDOUT_FILENO);
271716fd348SMartin Matuska (void) dup2(devnull_fd, STDERR_FILENO);
272716fd348SMartin Matuska close(devnull_fd);
273716fd348SMartin Matuska
274716fd348SMartin Matuska (void) execvp(path, argv);
275716fd348SMartin Matuska _exit(-1);
276716fd348SMartin Matuska } else if (pid > 0) {
277716fd348SMartin Matuska int status;
278716fd348SMartin Matuska
279716fd348SMartin Matuska while ((rc = waitpid(pid, &status, 0)) == -1 &&
280716fd348SMartin Matuska errno == EINTR) { }
281716fd348SMartin Matuska
282716fd348SMartin Matuska if (rc < 0 || !WIFEXITED(status))
283716fd348SMartin Matuska return (-1);
284716fd348SMartin Matuska
285716fd348SMartin Matuska return (WEXITSTATUS(status));
286716fd348SMartin Matuska }
287716fd348SMartin Matuska
288716fd348SMartin Matuska return (-1);
289716fd348SMartin Matuska }
290716fd348SMartin Matuska
291716fd348SMartin Matuska static int
post_hook(const char * phase)292a0b956f5SMartin Matuska post_hook(const char *phase)
293716fd348SMartin Matuska {
294a0b956f5SMartin Matuska char *argv[3] = { (char *)script, (char *)phase, NULL };
295716fd348SMartin Matuska int rc;
296716fd348SMartin Matuska
297716fd348SMartin Matuska if (synccaches)
298716fd348SMartin Matuska sync();
299716fd348SMartin Matuska
300716fd348SMartin Matuska if (dropcaches) {
301716fd348SMartin Matuska rc = drop_caches();
302716fd348SMartin Matuska if (rc)
303716fd348SMartin Matuska return (rc);
304716fd348SMartin Matuska }
305716fd348SMartin Matuska
306716fd348SMartin Matuska rc = run_process(script, argv);
307716fd348SMartin Matuska if (rc)
308716fd348SMartin Matuska return (rc);
309716fd348SMartin Matuska
310716fd348SMartin Matuska return (0);
311716fd348SMartin Matuska }
312716fd348SMartin Matuska
313716fd348SMartin Matuska #define USEC_PER_SEC 1000000
314716fd348SMartin Matuska
315716fd348SMartin Matuska static void
timeval_normalize(struct timeval * tv,time_t sec,suseconds_t usec)316716fd348SMartin Matuska timeval_normalize(struct timeval *tv, time_t sec, suseconds_t usec)
317716fd348SMartin Matuska {
318716fd348SMartin Matuska while (usec >= USEC_PER_SEC) {
319716fd348SMartin Matuska usec -= USEC_PER_SEC;
320716fd348SMartin Matuska sec++;
321716fd348SMartin Matuska }
322716fd348SMartin Matuska
323716fd348SMartin Matuska while (usec < 0) {
324716fd348SMartin Matuska usec += USEC_PER_SEC;
325716fd348SMartin Matuska sec--;
326716fd348SMartin Matuska }
327716fd348SMartin Matuska
328716fd348SMartin Matuska tv->tv_sec = sec;
329716fd348SMartin Matuska tv->tv_usec = usec;
330716fd348SMartin Matuska }
331716fd348SMartin Matuska
332716fd348SMartin Matuska static void
timeval_sub(struct timeval * delta,struct timeval * tv1,struct timeval * tv2)333716fd348SMartin Matuska timeval_sub(struct timeval *delta, struct timeval *tv1, struct timeval *tv2)
334716fd348SMartin Matuska {
335716fd348SMartin Matuska timeval_normalize(delta,
336716fd348SMartin Matuska tv1->tv_sec - tv2->tv_sec,
337716fd348SMartin Matuska tv1->tv_usec - tv2->tv_usec);
338716fd348SMartin Matuska }
339716fd348SMartin Matuska
340716fd348SMartin Matuska static double
timeval_sub_seconds(struct timeval * tv1,struct timeval * tv2)341716fd348SMartin Matuska timeval_sub_seconds(struct timeval *tv1, struct timeval *tv2)
342716fd348SMartin Matuska {
343716fd348SMartin Matuska struct timeval delta;
344716fd348SMartin Matuska
345716fd348SMartin Matuska timeval_sub(&delta, tv1, tv2);
346716fd348SMartin Matuska return ((double)delta.tv_usec / USEC_PER_SEC + delta.tv_sec);
347716fd348SMartin Matuska }
348716fd348SMartin Matuska
349716fd348SMartin Matuska static int
create_files(void)350716fd348SMartin Matuska create_files(void)
351716fd348SMartin Matuska {
352716fd348SMartin Matuska int i, rc;
353716fd348SMartin Matuska char *file = NULL;
354716fd348SMartin Matuska struct timeval start, stop;
355716fd348SMartin Matuska double seconds;
356716fd348SMartin Matuska size_t fsize;
357716fd348SMartin Matuska
358716fd348SMartin Matuska fsize = PATH_MAX;
359716fd348SMartin Matuska file = malloc(fsize);
360716fd348SMartin Matuska if (file == NULL) {
361716fd348SMartin Matuska rc = ENOMEM;
362716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
363716fd348SMartin Matuska PATH_MAX);
364716fd348SMartin Matuska goto out;
365716fd348SMartin Matuska }
366716fd348SMartin Matuska
367716fd348SMartin Matuska (void) gettimeofday(&start, NULL);
368716fd348SMartin Matuska
369716fd348SMartin Matuska for (i = 1; i <= files; i++) {
370716fd348SMartin Matuska if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
371716fd348SMartin Matuska rc = EINVAL;
372716fd348SMartin Matuska ERROR("Error %d: path too long\n", rc);
373716fd348SMartin Matuska goto out;
374716fd348SMartin Matuska }
375716fd348SMartin Matuska
376716fd348SMartin Matuska if (nth && ((i % nth) == 0))
377716fd348SMartin Matuska fprintf(stdout, "create: %s\n", file);
378716fd348SMartin Matuska
379716fd348SMartin Matuska rc = unlink(file);
380716fd348SMartin Matuska if ((rc == -1) && (errno != ENOENT)) {
381716fd348SMartin Matuska ERROR("Error %d: unlink(%s)\n", errno, file);
382716fd348SMartin Matuska rc = errno;
383716fd348SMartin Matuska goto out;
384716fd348SMartin Matuska }
385716fd348SMartin Matuska
386716fd348SMartin Matuska rc = open(file, O_CREAT, 0644);
387716fd348SMartin Matuska if (rc == -1) {
388716fd348SMartin Matuska ERROR("Error %d: open(%s, O_CREATE, 0644)\n",
389716fd348SMartin Matuska errno, file);
390716fd348SMartin Matuska rc = errno;
391716fd348SMartin Matuska goto out;
392716fd348SMartin Matuska }
393716fd348SMartin Matuska
394716fd348SMartin Matuska rc = close(rc);
395716fd348SMartin Matuska if (rc == -1) {
396716fd348SMartin Matuska ERROR("Error %d: close(%d)\n", errno, rc);
397716fd348SMartin Matuska rc = errno;
398716fd348SMartin Matuska goto out;
399716fd348SMartin Matuska }
400716fd348SMartin Matuska }
401716fd348SMartin Matuska
402716fd348SMartin Matuska (void) gettimeofday(&stop, NULL);
403716fd348SMartin Matuska seconds = timeval_sub_seconds(&stop, &start);
404716fd348SMartin Matuska fprintf(stdout, "create: %f seconds %f creates/second\n",
405716fd348SMartin Matuska seconds, files / seconds);
406716fd348SMartin Matuska
407716fd348SMartin Matuska rc = post_hook("post");
408716fd348SMartin Matuska out:
409716fd348SMartin Matuska if (file)
410716fd348SMartin Matuska free(file);
411716fd348SMartin Matuska
412716fd348SMartin Matuska return (rc);
413716fd348SMartin Matuska }
414716fd348SMartin Matuska
415716fd348SMartin Matuska static int
get_random_bytes(char * buf,size_t bytes)416716fd348SMartin Matuska get_random_bytes(char *buf, size_t bytes)
417716fd348SMartin Matuska {
418716fd348SMartin Matuska int rand;
419716fd348SMartin Matuska ssize_t bytes_read = 0;
420716fd348SMartin Matuska
421716fd348SMartin Matuska rand = open("/dev/urandom", O_RDONLY);
422716fd348SMartin Matuska
423716fd348SMartin Matuska if (rand < 0)
424716fd348SMartin Matuska return (rand);
425716fd348SMartin Matuska
426716fd348SMartin Matuska while (bytes_read < bytes) {
427716fd348SMartin Matuska ssize_t rc = read(rand, buf + bytes_read, bytes - bytes_read);
428716fd348SMartin Matuska if (rc < 0)
429716fd348SMartin Matuska break;
430716fd348SMartin Matuska bytes_read += rc;
431716fd348SMartin Matuska }
432716fd348SMartin Matuska
433716fd348SMartin Matuska (void) close(rand);
434716fd348SMartin Matuska
435716fd348SMartin Matuska return (bytes_read);
436716fd348SMartin Matuska }
437716fd348SMartin Matuska
438716fd348SMartin Matuska static int
setxattrs(void)439716fd348SMartin Matuska setxattrs(void)
440716fd348SMartin Matuska {
441716fd348SMartin Matuska int i, j, rnd_size = size, shift, rc = 0;
442716fd348SMartin Matuska char name[XATTR_NAME_MAX];
443716fd348SMartin Matuska char *value = NULL;
444716fd348SMartin Matuska char *file = NULL;
445716fd348SMartin Matuska struct timeval start, stop;
446716fd348SMartin Matuska double seconds;
447716fd348SMartin Matuska size_t fsize;
448716fd348SMartin Matuska
449716fd348SMartin Matuska value = malloc(XATTR_SIZE_MAX);
450716fd348SMartin Matuska if (value == NULL) {
451716fd348SMartin Matuska rc = ENOMEM;
452716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for xattr value\n", rc,
453716fd348SMartin Matuska XATTR_SIZE_MAX);
454716fd348SMartin Matuska goto out;
455716fd348SMartin Matuska }
456716fd348SMartin Matuska
457716fd348SMartin Matuska fsize = PATH_MAX;
458716fd348SMartin Matuska file = malloc(fsize);
459716fd348SMartin Matuska if (file == NULL) {
460716fd348SMartin Matuska rc = ENOMEM;
461716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
462716fd348SMartin Matuska PATH_MAX);
463716fd348SMartin Matuska goto out;
464716fd348SMartin Matuska }
465716fd348SMartin Matuska
466716fd348SMartin Matuska (void) gettimeofday(&start, NULL);
467716fd348SMartin Matuska
468716fd348SMartin Matuska for (i = 1; i <= files; i++) {
469716fd348SMartin Matuska if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
470716fd348SMartin Matuska rc = EINVAL;
471716fd348SMartin Matuska ERROR("Error %d: path too long\n", rc);
472716fd348SMartin Matuska goto out;
473716fd348SMartin Matuska }
474716fd348SMartin Matuska
475716fd348SMartin Matuska if (nth && ((i % nth) == 0))
476716fd348SMartin Matuska fprintf(stdout, "setxattr: %s\n", file);
477716fd348SMartin Matuska
478716fd348SMartin Matuska for (j = 1; j <= xattrs; j++) {
479716fd348SMartin Matuska if (size_is_random)
480716fd348SMartin Matuska rnd_size = (random() % (size - 16)) + 16;
481716fd348SMartin Matuska
482716fd348SMartin Matuska (void) sprintf(name, "user.%d", j);
483716fd348SMartin Matuska shift = sprintf(value, "size=%d ", rnd_size);
484716fd348SMartin Matuska memcpy(value + shift, xattrbytes,
485716fd348SMartin Matuska sizeof (xattrbytes) - shift);
486716fd348SMartin Matuska
487716fd348SMartin Matuska rc = lsetxattr(file, name, value, rnd_size, 0);
488716fd348SMartin Matuska if (rc == -1) {
489716fd348SMartin Matuska ERROR("Error %d: lsetxattr(%s, %s, ..., %d)\n",
490716fd348SMartin Matuska errno, file, name, rnd_size);
491716fd348SMartin Matuska goto out;
492716fd348SMartin Matuska }
493716fd348SMartin Matuska }
494716fd348SMartin Matuska }
495716fd348SMartin Matuska
496716fd348SMartin Matuska (void) gettimeofday(&stop, NULL);
497716fd348SMartin Matuska seconds = timeval_sub_seconds(&stop, &start);
498716fd348SMartin Matuska fprintf(stdout, "setxattr: %f seconds %f setxattrs/second\n",
499716fd348SMartin Matuska seconds, (files * xattrs) / seconds);
500716fd348SMartin Matuska
501716fd348SMartin Matuska rc = post_hook("post");
502716fd348SMartin Matuska out:
503716fd348SMartin Matuska if (file)
504716fd348SMartin Matuska free(file);
505716fd348SMartin Matuska
506716fd348SMartin Matuska if (value)
507716fd348SMartin Matuska free(value);
508716fd348SMartin Matuska
509716fd348SMartin Matuska return (rc);
510716fd348SMartin Matuska }
511716fd348SMartin Matuska
512716fd348SMartin Matuska static int
getxattrs(void)513716fd348SMartin Matuska getxattrs(void)
514716fd348SMartin Matuska {
515716fd348SMartin Matuska int i, j, rnd_size, shift, rc = 0;
516716fd348SMartin Matuska char name[XATTR_NAME_MAX];
517716fd348SMartin Matuska char *verify_value = NULL;
518a0b956f5SMartin Matuska const char *verify_string;
519716fd348SMartin Matuska char *value = NULL;
520a0b956f5SMartin Matuska const char *value_string;
521716fd348SMartin Matuska char *file = NULL;
522716fd348SMartin Matuska struct timeval start, stop;
523716fd348SMartin Matuska double seconds;
524716fd348SMartin Matuska size_t fsize;
525716fd348SMartin Matuska
526716fd348SMartin Matuska verify_value = malloc(XATTR_SIZE_MAX);
527716fd348SMartin Matuska if (verify_value == NULL) {
528716fd348SMartin Matuska rc = ENOMEM;
529716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for xattr verify\n", rc,
530716fd348SMartin Matuska XATTR_SIZE_MAX);
531716fd348SMartin Matuska goto out;
532716fd348SMartin Matuska }
533716fd348SMartin Matuska
534716fd348SMartin Matuska value = malloc(XATTR_SIZE_MAX);
535716fd348SMartin Matuska if (value == NULL) {
536716fd348SMartin Matuska rc = ENOMEM;
537716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for xattr value\n", rc,
538716fd348SMartin Matuska XATTR_SIZE_MAX);
539716fd348SMartin Matuska goto out;
540716fd348SMartin Matuska }
541716fd348SMartin Matuska
542716fd348SMartin Matuska verify_string = value_is_random ? "<random>" : verify_value;
543716fd348SMartin Matuska value_string = value_is_random ? "<random>" : value;
544716fd348SMartin Matuska
545716fd348SMartin Matuska fsize = PATH_MAX;
546716fd348SMartin Matuska file = malloc(fsize);
547716fd348SMartin Matuska
548716fd348SMartin Matuska if (file == NULL) {
549716fd348SMartin Matuska rc = ENOMEM;
550716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for file name\n", rc,
551716fd348SMartin Matuska PATH_MAX);
552716fd348SMartin Matuska goto out;
553716fd348SMartin Matuska }
554716fd348SMartin Matuska
555716fd348SMartin Matuska (void) gettimeofday(&start, NULL);
556716fd348SMartin Matuska
557716fd348SMartin Matuska for (i = 1; i <= files; i++) {
558716fd348SMartin Matuska if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
559716fd348SMartin Matuska rc = EINVAL;
560716fd348SMartin Matuska ERROR("Error %d: path too long\n", rc);
561716fd348SMartin Matuska goto out;
562716fd348SMartin Matuska }
563716fd348SMartin Matuska
564716fd348SMartin Matuska if (nth && ((i % nth) == 0))
565716fd348SMartin Matuska fprintf(stdout, "getxattr: %s\n", file);
566716fd348SMartin Matuska
567716fd348SMartin Matuska for (j = 1; j <= xattrs; j++) {
568716fd348SMartin Matuska (void) sprintf(name, "user.%d", j);
569716fd348SMartin Matuska
570716fd348SMartin Matuska rc = lgetxattr(file, name, value, XATTR_SIZE_MAX);
571716fd348SMartin Matuska if (rc == -1) {
572716fd348SMartin Matuska ERROR("Error %d: lgetxattr(%s, %s, ..., %d)\n",
573716fd348SMartin Matuska errno, file, name, XATTR_SIZE_MAX);
574716fd348SMartin Matuska goto out;
575716fd348SMartin Matuska }
576716fd348SMartin Matuska
577716fd348SMartin Matuska if (!verify)
578716fd348SMartin Matuska continue;
579716fd348SMartin Matuska
580716fd348SMartin Matuska sscanf(value, "size=%d [a-z]", &rnd_size);
581716fd348SMartin Matuska shift = sprintf(verify_value, "size=%d ",
582716fd348SMartin Matuska rnd_size);
583716fd348SMartin Matuska memcpy(verify_value + shift, xattrbytes,
584716fd348SMartin Matuska sizeof (xattrbytes) - shift);
585716fd348SMartin Matuska
586716fd348SMartin Matuska if (rnd_size != rc ||
587716fd348SMartin Matuska memcmp(verify_value, value, rnd_size)) {
588716fd348SMartin Matuska ERROR("Error %d: verify failed\n "
589716fd348SMartin Matuska "verify: %s\n value: %s\n", EINVAL,
590716fd348SMartin Matuska verify_string, value_string);
591716fd348SMartin Matuska rc = 1;
592716fd348SMartin Matuska goto out;
593716fd348SMartin Matuska }
594716fd348SMartin Matuska }
595716fd348SMartin Matuska }
596716fd348SMartin Matuska
597716fd348SMartin Matuska (void) gettimeofday(&stop, NULL);
598716fd348SMartin Matuska seconds = timeval_sub_seconds(&stop, &start);
599716fd348SMartin Matuska fprintf(stdout, "getxattr: %f seconds %f getxattrs/second\n",
600716fd348SMartin Matuska seconds, (files * xattrs) / seconds);
601716fd348SMartin Matuska
602716fd348SMartin Matuska rc = post_hook("post");
603716fd348SMartin Matuska out:
604716fd348SMartin Matuska if (file)
605716fd348SMartin Matuska free(file);
606716fd348SMartin Matuska
607716fd348SMartin Matuska if (value)
608716fd348SMartin Matuska free(value);
609716fd348SMartin Matuska
610716fd348SMartin Matuska if (verify_value)
611716fd348SMartin Matuska free(verify_value);
612716fd348SMartin Matuska
613716fd348SMartin Matuska return (rc);
614716fd348SMartin Matuska }
615716fd348SMartin Matuska
616716fd348SMartin Matuska static int
unlink_files(void)617716fd348SMartin Matuska unlink_files(void)
618716fd348SMartin Matuska {
619716fd348SMartin Matuska int i, rc;
620716fd348SMartin Matuska char *file = NULL;
621716fd348SMartin Matuska struct timeval start, stop;
622716fd348SMartin Matuska double seconds;
623716fd348SMartin Matuska size_t fsize;
624716fd348SMartin Matuska
625716fd348SMartin Matuska fsize = PATH_MAX;
626716fd348SMartin Matuska file = malloc(fsize);
627716fd348SMartin Matuska if (file == NULL) {
628716fd348SMartin Matuska rc = ENOMEM;
629716fd348SMartin Matuska ERROR("Error %d: malloc(%d) bytes for file name\n",
630716fd348SMartin Matuska rc, PATH_MAX);
631716fd348SMartin Matuska goto out;
632716fd348SMartin Matuska }
633716fd348SMartin Matuska
634716fd348SMartin Matuska (void) gettimeofday(&start, NULL);
635716fd348SMartin Matuska
636716fd348SMartin Matuska for (i = 1; i <= files; i++) {
637716fd348SMartin Matuska if (snprintf(file, fsize, "%s/file-%d", path, i) >= fsize) {
638716fd348SMartin Matuska rc = EINVAL;
639716fd348SMartin Matuska ERROR("Error %d: path too long\n", rc);
640716fd348SMartin Matuska goto out;
641716fd348SMartin Matuska }
642716fd348SMartin Matuska
643716fd348SMartin Matuska if (nth && ((i % nth) == 0))
644716fd348SMartin Matuska fprintf(stdout, "unlink: %s\n", file);
645716fd348SMartin Matuska
646716fd348SMartin Matuska rc = unlink(file);
647716fd348SMartin Matuska if ((rc == -1) && (errno != ENOENT)) {
648716fd348SMartin Matuska ERROR("Error %d: unlink(%s)\n", errno, file);
649716fd348SMartin Matuska free(file);
650716fd348SMartin Matuska return (errno);
651716fd348SMartin Matuska }
652716fd348SMartin Matuska }
653716fd348SMartin Matuska
654716fd348SMartin Matuska (void) gettimeofday(&stop, NULL);
655716fd348SMartin Matuska seconds = timeval_sub_seconds(&stop, &start);
656716fd348SMartin Matuska fprintf(stdout, "unlink: %f seconds %f unlinks/second\n",
657716fd348SMartin Matuska seconds, files / seconds);
658716fd348SMartin Matuska
659716fd348SMartin Matuska rc = post_hook("post");
660716fd348SMartin Matuska out:
661716fd348SMartin Matuska if (file)
662716fd348SMartin Matuska free(file);
663716fd348SMartin Matuska
664716fd348SMartin Matuska return (rc);
665716fd348SMartin Matuska }
666716fd348SMartin Matuska
667716fd348SMartin Matuska int
main(int argc,char ** argv)668716fd348SMartin Matuska main(int argc, char **argv)
669716fd348SMartin Matuska {
670716fd348SMartin Matuska int rc;
671716fd348SMartin Matuska
672716fd348SMartin Matuska rc = parse_args(argc, argv);
673716fd348SMartin Matuska if (rc)
674716fd348SMartin Matuska return (rc);
675716fd348SMartin Matuska
676716fd348SMartin Matuska if (value_is_random) {
677716fd348SMartin Matuska size_t rndsz = sizeof (xattrbytes);
678716fd348SMartin Matuska
679716fd348SMartin Matuska rc = get_random_bytes(xattrbytes, rndsz);
680716fd348SMartin Matuska if (rc < rndsz) {
681716fd348SMartin Matuska ERROR("Error %d: get_random_bytes() wanted %zd "
682716fd348SMartin Matuska "got %d\n", errno, rndsz, rc);
683716fd348SMartin Matuska return (rc);
684716fd348SMartin Matuska }
685716fd348SMartin Matuska } else {
686716fd348SMartin Matuska memset(xattrbytes, 'x', sizeof (xattrbytes));
687716fd348SMartin Matuska }
688716fd348SMartin Matuska
689716fd348SMartin Matuska if (phase == PHASE_ALL || phase == PHASE_CREATE) {
690716fd348SMartin Matuska rc = create_files();
691716fd348SMartin Matuska if (rc)
692716fd348SMartin Matuska return (rc);
693716fd348SMartin Matuska }
694716fd348SMartin Matuska
695716fd348SMartin Matuska if (phase == PHASE_ALL || phase == PHASE_SETXATTR) {
696716fd348SMartin Matuska rc = setxattrs();
697716fd348SMartin Matuska if (rc)
698716fd348SMartin Matuska return (rc);
699716fd348SMartin Matuska }
700716fd348SMartin Matuska
701716fd348SMartin Matuska if (phase == PHASE_ALL || phase == PHASE_GETXATTR) {
702716fd348SMartin Matuska rc = getxattrs();
703716fd348SMartin Matuska if (rc)
704716fd348SMartin Matuska return (rc);
705716fd348SMartin Matuska }
706716fd348SMartin Matuska
707716fd348SMartin Matuska if (!keep_files && (phase == PHASE_ALL || phase == PHASE_UNLINK)) {
708716fd348SMartin Matuska rc = unlink_files();
709716fd348SMartin Matuska if (rc)
710716fd348SMartin Matuska return (rc);
711716fd348SMartin Matuska }
712716fd348SMartin Matuska
713716fd348SMartin Matuska return (0);
714716fd348SMartin Matuska }
715