Whamcloud - gitweb
LU-15152 tests: auster reports wrong testsuite status
[fs/lustre-release.git] / lustre / tests / multiop.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #ifndef _GNU_SOURCE
33 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
34 #endif
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <limits.h>
38 #include <malloc.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <sys/vfs.h>
45 #include <sys/ioctl.h>
46 #include <sys/xattr.h>
47 #include <sys/file.h>
48 #include <signal.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <semaphore.h>
52 #include <time.h>
53 #include <err.h>
54 #include <dirent.h>
55
56 #include <lustre/lustreapi.h>
57
58 #define T1 "write data before unlink\n"
59 #define T2 "write data after unlink\n"
60 char msg[] = "yabba dabba doo, I'm coming for you, I live in a shoe, I don't know what to do.\n'Bigger, bigger,and bigger yet!' cried the Creator.  'You are not yet substantial enough for my boundless intents!'  And ever greater and greater the object became, until all was lost 'neath its momentus bulk.\n";
61 char *buf, *buf_align;
62 int bufsize;
63 sem_t sem;
64 #define ALIGN_LEN 65535
65 #define XATTR "user.multiop"
66
67 char usage[] =
68 "Usage: %s filename command-sequence [path...]\n"
69 "    command-sequence items:\n"
70 "        A  fsetxattr(\"user.multiop\")\n"
71 "        a[num] fgetxattr(\"user.multiop\") [optional buffer size, default 0]\n"
72 "        c  close\n"
73 "        B[num] call setstripe ioctl to create stripes\n"
74 "        C[num] create with optional stripes\n"
75 "        d  mkdir\n"
76 "        D  open(O_DIRECTORY)\n"
77 "        e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
78 "        E[+|-] get lease. +/-: expect lease to (not) exist\n"
79 "        f  statfs\n"
80 "        F  print FID\n"
81 "        G gid get grouplock\n"
82 "        g gid put grouplock\n"
83 "        H[num] create HSM released file with num stripes\n"
84 "        K  link path to filename\n"
85 "        L  link\n"
86 "        l  symlink filename to path\n"
87 "        m  mknod\n"
88 "        M  rw mmap to EOF (must open and stat prior)\n"
89 "        n  rename path to filename\n"
90 "        N  rename filename to path\n"
91 "        o  open(O_RDONLY)\n"
92 "        O  open(O_CREAT|O_RDWR)\n"
93 "        p  print return value of last command\n"
94 "        Q  open filename (should be dir), stat first entry to init statahead"
95 "        r[num] read [optional length]\n"
96 "        R  reference entire mmap-ed region\n"
97 "        s  stat\n"
98 "        S  fstat\n"
99 "        t  fchmod\n"
100 "        T[num] ftruncate [optional position, default 0]\n"
101 "        u  unlink\n"
102 "        U  munmap\n"
103 "        v  verbose\n"
104 "        V  open a volatile file\n"
105 "        w[num] write optional length\n"
106 "        x  get file data version\n"
107 "        W  write entire mmap-ed region\n"
108 "        y  fsync\n"
109 "        Y  fdatasync\n"
110 "        z[num] lseek(SEEK_SET) [optional offset, default 0]\n"
111 "        Z[num] lseek(SEEK_CUR) [optional offset, default 0]\n"
112 "        _  wait for signal\n";
113
114 void usr1_handler(int unused)
115 {
116         int saved_errno = errno;
117
118         /*
119          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
120          * that the following functions can be safely called inside a signal
121          * handler:
122          *            sem_post()
123          */
124         sem_post(&sem);
125
126         errno = saved_errno;
127 }
128
129 static const char *
130 pop_arg(int argc, char *argv[])
131 {
132         static int cur_arg = 3;
133
134         if (cur_arg >= argc)
135                 return NULL;
136
137         return argv[cur_arg++];
138 }
139
140 struct flag_mapping {
141         const char *string;
142         const int  flag;
143 } flag_table[] = {
144         {"O_RDONLY", O_RDONLY},
145         {"O_WRONLY", O_WRONLY},
146         {"O_RDWR", O_RDWR},
147         {"O_CREAT", O_CREAT},
148         {"O_EXCL", O_EXCL},
149         {"O_NOCTTY", O_NOCTTY},
150         {"O_TRUNC", O_TRUNC},
151         {"O_APPEND", O_APPEND},
152         {"O_NONBLOCK", O_NONBLOCK},
153         {"O_NDELAY", O_NDELAY},
154         {"O_SYNC", O_SYNC},
155 #ifdef O_DIRECT
156         {"O_DIRECT", O_DIRECT},
157 #endif
158 #ifdef O_NOATIME
159         {"O_NOATIME", O_NOATIME},
160 #endif
161         {"O_LARGEFILE", O_LARGEFILE},
162         {"O_DIRECTORY", O_DIRECTORY},
163         {"O_NOFOLLOW", O_NOFOLLOW},
164         {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
165         {"", -1}
166 };
167
168 int get_flags(char *data, int *rflags)
169 {
170         char *cloned_flags;
171         char *tmp;
172         int flag_set = 0;
173         int flags = 0;
174         int size = 0;
175
176         cloned_flags = strdup(data);
177         if (!cloned_flags) {
178                 fprintf(stderr, "Insufficient memory.\n");
179                 exit(-1);
180         }
181
182         for (tmp = strtok(cloned_flags, ":"); tmp;
183              tmp = strtok(NULL, ":")) {
184                 int i;
185
186                 size = tmp - cloned_flags;
187                 for (i = 0; flag_table[i].flag != -1; i++) {
188                         if (!strcmp(tmp, flag_table[i].string)) {
189                                 flags |= flag_table[i].flag;
190                                 size += strlen(flag_table[i].string);
191                                 flag_set = 1;
192                                 break;
193                         }
194                 }
195         }
196         free(cloned_flags);
197
198         if (!flag_set) {
199                 *rflags = O_RDONLY;
200                 return 0;
201         }
202
203         *rflags = flags;
204         return size;
205 }
206
207 static int statahead(char *dname)
208 {
209         DIR *d;
210         struct dirent *dent;
211         struct stat st;
212         char *buf;
213         int rc;
214
215         rc = 0;
216         d = opendir(dname);
217         if (!d)
218                 return errno;
219         dent = readdir(d);
220         if (!dent) {
221                 rc = errno;
222                 goto out_closedir;
223         }
224         if (asprintf(&buf, "%s/%s", dname, dent->d_name) == -1) {
225                 rc = errno;
226                 goto out_closedir;
227         }
228         if (stat(buf, &st))
229                 rc = errno;
230         free(buf);
231 out_closedir:
232         closedir(d);
233         return rc;
234 }
235
236 #define POP_ARG() (pop_arg(argc, argv))
237
238 int main(int argc, char **argv)
239 {
240         char *fname, *commands;
241         const char *newfile;
242         const char *oldpath;
243         struct stat st;
244         struct statfs stfs;
245         size_t mmap_len = 0, i;
246         unsigned char *mmap_ptr = NULL, junk = 1;
247         int len, fd = -1;
248         int flags;
249         int save_errno;
250         int verbose = 0;
251         int gid = 0;
252         struct lu_fid fid;
253         struct timespec ts;
254         struct lov_user_md_v3 lum;
255         char *xattr_buf = NULL;
256         size_t xattr_buf_size = 0;
257         long long rc = 0;
258         long long last_rc;
259
260         if (argc < 3) {
261                 fprintf(stderr, usage, argv[0]);
262                 exit(1);
263         }
264
265         memset(&st, 0, sizeof(st));
266         sem_init(&sem, 0, 0);
267         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
268         sigaction(SIGUSR1,
269                   &(const struct sigaction){.sa_handler = &usr1_handler}, NULL);
270
271         fname = argv[1];
272
273         for (commands = argv[2]; *commands; commands++) {
274                 /*
275                  * XXX Most commands return 0 or we exit so we only
276                  * update rc where really needed.
277                  */
278                 last_rc = rc;
279                 rc = 0;
280
281                 switch (*commands) {
282                 case '_':
283                         if (verbose) {
284                                 printf("PAUSING\n");
285                                 fflush(stdout);
286                         }
287                         len = atoi(commands + 1);
288                         if (len <= 0)
289                                 len = 3600; /* 1 hour */
290                         ts.tv_sec = time(NULL) + len;
291                         ts.tv_nsec = 0;
292                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR)
293                                 ;
294                         break;
295                 case 'A':
296                         if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
297                                 save_errno = errno;
298                                 perror("fsetxattr");
299                                 exit(save_errno);
300                         }
301                         break;
302                 case 'a':
303                         len = atoi(commands + 1);
304                         if (xattr_buf_size < len) {
305                                 xattr_buf = realloc(xattr_buf, len);
306                                 if (!xattr_buf) {
307                                         save_errno = errno;
308                                         perror("allocating xattr buffer\n");
309                                         exit(save_errno);
310                                 }
311
312                                 xattr_buf_size = len;
313                         }
314
315                         rc = fgetxattr(fd, XATTR, xattr_buf, len);
316                         if (rc < 0) {
317                                 save_errno = errno;
318                                 perror("fgetxattr");
319                                 exit(save_errno);
320                         }
321                         break;
322                 case 'c':
323                         if (close(fd) == -1) {
324                                 save_errno = errno;
325                                 perror("close");
326                                 exit(save_errno);
327                         }
328                         fd = -1;
329                         break;
330                 case 'B':
331                         lum = (struct lov_user_md_v3) {
332                                 .lmm_magic = LOV_USER_MAGIC_V3,
333                                 .lmm_stripe_count = atoi(commands + 1),
334                         };
335
336                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
337                                 save_errno = errno;
338                                 perror("LL_IOC_LOV_SETSTRIPE");
339                                 exit(save_errno);
340                         }
341                         break;
342                 case 'C':
343                         len = atoi(commands + 1);
344                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
345                                              0, 0, len, 0);
346                         if (fd == -1) {
347                                 save_errno = errno;
348                                 perror("create stripe file");
349                                 exit(save_errno);
350                         }
351                         rc = fd;
352                         break;
353                 case 'd':
354                         if (mkdir(fname, 0755) == -1) {
355                                 save_errno = errno;
356                                 perror("mkdir(0755)");
357                                 exit(save_errno);
358                         }
359                         break;
360                 case 'D':
361                         fd = open(fname, O_DIRECTORY);
362                         if (fd == -1) {
363                                 save_errno = errno;
364                                 perror("open(O_DIRECTORY)");
365                                 exit(save_errno);
366                         }
367                         rc = fd;
368                         break;
369                 case 'e':
370                         commands++;
371                         switch (*commands) {
372                         case 'U':
373                                 rc = llapi_lease_release(fd);
374                                 break;
375                         case 'R':
376                                 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
377                                 break;
378                         case 'W':
379                                 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
380                                 break;
381                         default:
382                                 errx(-1, "unknown mode: %c", *commands);
383                         }
384                         if (rc < 0)
385                                 err(errno, "apply/unlock lease error");
386
387                         if (flags != LL_LEASE_UNLCK)
388                                 break;
389
390                         /* F_UNLCK, interpret return code */
391                         if (rc > 0) {
392                                 const char *str = "unknown";
393
394                                 if (rc == LL_LEASE_RDLCK)
395                                         str = "read";
396                                 else if (rc == LL_LEASE_WRLCK)
397                                         str = "write";
398                                 fprintf(stdout, "%s lease(%lld) released.\n",
399                                         str, rc);
400                         } else if (rc == 0) {
401                                 fprintf(stdout, "lease already broken.\n");
402                         }
403                         break;
404                 case 'E':
405                         commands++;
406                         if (*commands != '-' && *commands != '+')
407                                 errx(-1, "unknown mode: %c\n", *commands);
408
409                         rc = llapi_lease_check(fd);
410                         if (rc > 0) {
411                                 const char *str = "unknown";
412
413                                 if (rc == LL_LEASE_RDLCK)
414                                         str = "read";
415                                 else if (rc == LL_LEASE_WRLCK)
416                                         str = "write";
417                                 fprintf(stdout, "%s lease(%lld) has applied.\n",
418                                         str, rc);
419                                 if (*commands == '-')
420                                         errx(-1, "expect lease to not exist");
421                         } else if (rc == 0) {
422                                 fprintf(stdout, "no lease applied.\n");
423                                 if (*commands == '+')
424                                         errx(-1, "expect lease exists");
425                         } else {
426                                 err(errno, "free lease error");
427                         }
428                         break;
429                 case 'f':
430                         if (statfs(fname, &stfs) == -1)
431                                 errx(-1, "statfs()");
432                         break;
433                 case 'F':
434                         if (fd == -1)
435                                 rc = llapi_path2fid(fname, &fid);
436                         else
437                                 rc = llapi_fd2fid(fd, &fid);
438                         if (rc != 0)
439                                 fprintf(stderr,
440                                         "llapi_path/fd2fid() on %d, rc=%lld\n",
441                                         fd, rc);
442                         else
443                                 printf(DFID"\n", PFID(&fid));
444                         fflush(stdout);
445                         break;
446                 case 'G':
447                         gid = atoi(commands + 1);
448                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
449                                 save_errno = errno;
450                                 perror("ioctl(GROUP_LOCK)");
451                                 exit(save_errno);
452                         }
453                         break;
454                 case 'g':
455                         gid = atoi(commands + 1);
456                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
457                                 save_errno = errno;
458                                 perror("ioctl(GROUP_UNLOCK)");
459                                 exit(save_errno);
460                         }
461                         break;
462                 case 'H':
463                         len = atoi(commands + 1);
464                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
465                                              0, 0, len, LOV_PATTERN_RAID0 |
466                                              LOV_PATTERN_F_RELEASED);
467                         if (fd == -1) {
468                                 save_errno = errno;
469                                 perror("create stripe file");
470                                 exit(save_errno);
471                         }
472                         rc = fd;
473                         break;
474                 case 'j':
475                         if (flock(fd, LOCK_EX) == -1)
476                                 errx(-1, "flock()");
477                         break;
478                 case 'K':
479                         oldpath = POP_ARG();
480                         if (!oldpath)
481                                 oldpath = fname;
482
483                         if (link(oldpath, fname)) {
484                                 save_errno = errno;
485                                 perror("link()");
486                                 exit(save_errno);
487                         }
488                         break;
489                 case 'l':
490                         newfile = POP_ARG();
491                         if (!newfile)
492                                 newfile = fname;
493                         if (symlink(fname, newfile)) {
494                                 save_errno = errno;
495                                 perror("symlink()");
496                                 exit(save_errno);
497                         }
498                         break;
499                 case 'L':
500                         newfile = POP_ARG();
501                         if (!newfile)
502                                 newfile = fname;
503
504                         if (link(fname, newfile)) {
505                                 save_errno = errno;
506                                 perror("link()");
507                                 exit(save_errno);
508                         }
509                         break;
510                 case 'm':
511                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
512                                 save_errno = errno;
513                                 perror("mknod(S_IFREG|0644, 0)");
514                                 exit(save_errno);
515                         }
516                         break;
517                 case 'M':
518                         if (st.st_size == 0) {
519                                 fprintf(stderr,
520                                         "mmap without preceeding stat, or on zero length file.\n");
521                                 exit(-1);
522                         }
523                         mmap_len = st.st_size;
524                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
525                                         MAP_SHARED, fd, 0);
526                         if (mmap_ptr == MAP_FAILED) {
527                                 save_errno = errno;
528                                 perror("mmap");
529                                 exit(save_errno);
530                         }
531                         break;
532                 case 'n':
533                         oldpath = POP_ARG();
534                         if (!oldpath)
535                                 oldpath = fname;
536
537                         if (rename(oldpath, fname) < 0) {
538                                 save_errno = errno;
539                                 perror("rename()");
540                                 exit(save_errno);
541                         }
542                         break;
543                 case 'N':
544                         newfile = POP_ARG();
545                         if (!newfile)
546                                 newfile = fname;
547                         if (rename(fname, newfile)) {
548                                 save_errno = errno;
549                                 perror("rename()");
550                                 exit(save_errno);
551                         }
552                         break;
553                 case 'O':
554                         fd = open(fname, O_CREAT | O_RDWR, 0644);
555                         if (fd == -1) {
556                                 save_errno = errno;
557                                 perror("open(O_RDWR|O_CREAT)");
558                                 exit(save_errno);
559                         }
560                         rc = fd;
561                         break;
562                 case 'o':
563                         len = get_flags(commands + 1, &flags);
564                         commands += len;
565                         if (flags & O_CREAT)
566                                 fd = open(fname, flags, 0666);
567                         else
568                                 fd = open(fname, flags);
569                         if (fd == -1) {
570                                 save_errno = errno;
571                                 perror("open");
572                                 exit(save_errno);
573                         }
574                         rc = fd;
575                         break;
576                 case 'p':
577                         printf("%lld\n", last_rc);
578                         break;
579                 case 'Q':
580                         save_errno = statahead(fname);
581                         if (save_errno) {
582                                 perror("statahead");
583                                 exit(save_errno);
584                         }
585                         break;
586                 case 'r':
587                         len = atoi(commands + 1);
588                         if (len <= 0)
589                                 len = 1;
590                         if (bufsize < len) {
591                                 void *tmp;
592
593                                 tmp = realloc(buf, len + ALIGN_LEN);
594                                 if (!tmp) {
595                                         free(buf);
596                                         save_errno = errno;
597                                         perror("allocating buf for read\n");
598                                         exit(save_errno);
599                                 }
600                                 buf = tmp;
601                                 bufsize = len;
602                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
603                                                      ~ALIGN_LEN);
604                         }
605                         while (len > 0) {
606                                 rc = read(fd, buf_align, len);
607                                 if (rc == -1) {
608                                         save_errno = errno;
609                                         perror("read");
610                                         exit(save_errno);
611                                 }
612                                 if (rc < len) {
613                                         fprintf(stderr, "short read: %lld/%u\n",
614                                                 rc, len);
615                                         if (rc == 0)
616                                                 exit(ENODATA);
617                                 }
618                                 len -= rc;
619                                 if (verbose >= 2)
620                                         printf("%.*s\n", (int)rc, buf_align);
621                         }
622                         break;
623                 case 'R':
624                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
625                                 junk += mmap_ptr[i];
626                         break;
627                 case 's':
628                         if (stat(fname, &st) == -1) {
629                                 save_errno = errno;
630                                 perror("stat");
631                                 exit(save_errno);
632                         }
633                         break;
634                 case 'S':
635                         if (fstat(fd, &st) == -1) {
636                                 save_errno = errno;
637                                 perror("fstat");
638                                 exit(save_errno);
639                         }
640                         break;
641                 case 't':
642                         if (fchmod(fd, 0) == -1) {
643                                 save_errno = errno;
644                                 perror("fchmod");
645                                 exit(save_errno);
646                         }
647                         break;
648                 case 'T':
649                         len = atoi(commands + 1);
650                         if (ftruncate(fd, len) == -1) {
651                                 save_errno = errno;
652                                 printf("ftruncate (%d,%d)\n", fd, len);
653                                 perror("ftruncate");
654                                 exit(save_errno);
655                         }
656                         break;
657                 case 'u':
658                         if (unlink(fname) == -1) {
659                                 save_errno = errno;
660                                 perror("unlink");
661                                 exit(save_errno);
662                         }
663                         break;
664                 case 'U':
665                         if (munmap(mmap_ptr, mmap_len)) {
666                                 save_errno = errno;
667                                 perror("munmap");
668                                 exit(save_errno);
669                         }
670                         break;
671                 case 'v':
672                         verbose++;
673                         break;
674                 case 'V':
675                         len = get_flags(commands + 1, &flags);
676                         commands += len;
677                         len = -1; /* mdt index */
678                         if (commands[1] >= '0' && commands[1] <= '9')
679                                 len = atoi(commands + 1);
680                         fd = llapi_create_volatile_idx(fname, len, flags);
681                         if (fd < 0) {
682                                 perror("llapi_create_volatile");
683                                 exit(fd);
684                         }
685                         rc = fd;
686                         break;
687                 case 'w':
688                         len = atoi(commands + 1);
689                         if (len <= 0)
690                                 len = 1;
691                         if (bufsize < len) {
692                                 void *tmp;
693
694                                 tmp = realloc(buf, len + ALIGN_LEN);
695                                 if (!tmp) {
696                                         free(buf);
697                                         save_errno = errno;
698                                         perror("allocating buf for write\n");
699                                         exit(save_errno);
700                                 }
701                                 buf = tmp;
702                                 bufsize = len;
703                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
704                                                      ~ALIGN_LEN);
705                                 strncpy(buf_align, msg, bufsize);
706                         }
707                         while (len > 0) {
708                                 rc = write(fd, buf_align, len);
709                                 if (rc == -1) {
710                                         save_errno = errno;
711                                         perror("write");
712                                         exit(save_errno);
713                                 }
714                                 if (rc < len)
715                                         fprintf(stderr,
716                                                 "short write: %lld/%u\n",
717                                                 rc, len);
718                                 len -= rc;
719                         }
720                         break;
721                 case 'W':
722                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
723                                 mmap_ptr[i] += junk++;
724                         break;
725                 case 'x': {
726                         __u64 dv;
727
728                         rc = llapi_get_data_version(fd, &dv, 0);
729                         if (rc) {
730                                 fprintf(stderr,
731                                         "cannot get file data version %lld\n",
732                                         rc);
733                                 exit(-rc);
734                         }
735                         printf("dataversion is %ju\n", (uintmax_t)dv);
736                         break;
737                 }
738                 case 'X': {
739                         __u32 layout_version;
740
741                         rc = llapi_get_ost_layout_version(fd, &layout_version);
742                         if (rc) {
743                                 fprintf(stderr,
744                                         "cannot get ost layout version %lld\n",
745                                         rc);
746                                 exit(-rc);
747                         }
748                         printf("ostlayoutversion: %u\n", layout_version);
749                         break;
750                 }
751                 case 'y':
752                         if (fsync(fd) == -1) {
753                                 save_errno = errno;
754                                 perror("fsync");
755                                 exit(save_errno);
756                         }
757                         break;
758                 case 'Y':
759                         if (fdatasync(fd) == -1) {
760                                 save_errno = errno;
761                                 perror("fdatasync");
762                                 exit(save_errno);
763                         }
764                         break;
765                 case 'z': {
766                         off_t off;
767
768                         len = atoi(commands + 1);
769                         off = lseek(fd, len, SEEK_SET);
770                         if (off == (off_t)-1) {
771                                 save_errno = errno;
772                                 perror("lseek");
773                                 exit(save_errno);
774                         }
775
776                         rc = off;
777                         break;
778                 }
779                 case 'Z': {
780                         off_t off;
781
782                         len = atoi(commands + 1);
783                         off = lseek(fd, len, SEEK_CUR);
784                         if (off == (off_t)-1) {
785                                 save_errno = errno;
786                                 perror("lseek");
787                                 exit(save_errno);
788                         }
789
790                         rc = off;
791                         break;
792                 }
793                 case '-':
794                 case '0':
795                 case '1':
796                 case '2':
797                 case '3':
798                 case '4':
799                 case '5':
800                 case '6':
801                 case '7':
802                 case '8':
803                 case '9':
804                         break;
805                 default:
806                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
807                         fprintf(stderr, usage, argv[0]);
808                         exit(1);
809                 }
810         }
811
812         if (buf)
813                 free(buf);
814
815         return 0;
816 }