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