Whamcloud - gitweb
LU-14119 lfsck: check linkea if it's newly added
[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 = 0;
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 == NULL) {
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 = 0;
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, &(const struct sigaction){.sa_handler = &usr1_handler},
270                   NULL);
271
272         fname = argv[1];
273
274         for (commands = argv[2]; *commands; commands++) {
275                 /* XXX Most commands return 0 or we exit so we only
276                  * update rc where really needed. */
277                 last_rc = rc;
278                 rc = 0;
279
280                 switch (*commands) {
281                 case '_':
282                         if (verbose) {
283                                 printf("PAUSING\n");
284                                 fflush(stdout);
285                         }
286                         len = atoi(commands+1);
287                         if (len <= 0)
288                                 len = 3600; /* 1 hour */
289                         ts.tv_sec = time(NULL) + len;
290                         ts.tv_nsec = 0;
291                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
292                         break;
293                 case 'A':
294                         if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
295                                 save_errno = errno;
296                                 perror("fsetxattr");
297                                 exit(save_errno);
298                         }
299                         break;
300                 case 'a':
301                         len = atoi(commands + 1);
302                         if (xattr_buf_size < len) {
303                                 xattr_buf = realloc(xattr_buf, len);
304                                 if (xattr_buf == NULL) {
305                                         save_errno = errno;
306                                         perror("allocating xattr buffer\n");
307                                         exit(save_errno);
308                                 }
309
310                                 xattr_buf_size = len;
311                         }
312
313                         rc = fgetxattr(fd, XATTR, xattr_buf, len);
314                         if (rc < 0) {
315                                 save_errno = errno;
316                                 perror("fgetxattr");
317                                 exit(save_errno);
318                         }
319                         break;
320                 case 'c':
321                         if (close(fd) == -1) {
322                                 save_errno = errno;
323                                 perror("close");
324                                 exit(save_errno);
325                         }
326                         fd = -1;
327                         break;
328                 case 'B':
329                         lum = (struct lov_user_md_v3) {
330                                 .lmm_magic = LOV_USER_MAGIC_V3,
331                                 .lmm_stripe_count = atoi(commands + 1),
332                         };
333
334                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
335                                 save_errno = errno;
336                                 perror("LL_IOC_LOV_SETSTRIPE");
337                                 exit(save_errno);
338                         }
339                         break;
340                 case 'C':
341                         len = atoi(commands+1);
342                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
343                                              0, 0, len, 0);
344                         if (fd == -1) {
345                                 save_errno = errno;
346                                 perror("create stripe file");
347                                 exit(save_errno);
348                         }
349                         rc = fd;
350                         break;
351                 case 'd':
352                         if (mkdir(fname, 0755) == -1) {
353                                 save_errno = errno;
354                                 perror("mkdir(0755)");
355                                 exit(save_errno);
356                         }
357                         break;
358                 case 'D':
359                         fd = open(fname, O_DIRECTORY);
360                         if (fd == -1) {
361                                 save_errno = errno;
362                                 perror("open(O_DIRECTORY)");
363                                 exit(save_errno);
364                         }
365                         rc = fd;
366                         break;
367                 case 'e':
368                         commands++;
369                         switch (*commands) {
370                         case 'U':
371                                 rc = llapi_lease_release(fd);
372                                 break;
373                         case 'R':
374                                 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
375                                 break;
376                         case 'W':
377                                 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
378                                 break;
379                         default:
380                                 errx(-1, "unknown mode: %c", *commands);
381                         }
382                         if (rc < 0)
383                                 err(errno, "apply/unlock lease error");
384
385                         if (flags != LL_LEASE_UNLCK)
386                                 break;
387
388                         /* F_UNLCK, interpret return code */
389                         if (rc > 0) {
390                                 const char *str = "unknown";
391                                 if (rc == LL_LEASE_RDLCK)
392                                         str = "read";
393                                 else if (rc == LL_LEASE_WRLCK)
394                                         str = "write";
395                                 fprintf(stdout, "%s lease(%lld) released.\n",
396                                         str, rc);
397                         } else if (rc == 0) {
398                                 fprintf(stdout, "lease already broken.\n");
399                         }
400                         break;
401                 case 'E':
402                         commands++;
403                         if (*commands != '-' && *commands != '+')
404                                 errx(-1, "unknown mode: %c\n", *commands);
405
406                         rc = llapi_lease_check(fd);
407                         if (rc > 0) {
408                                 const char *str = "unknown";
409
410                                 if (rc == LL_LEASE_RDLCK)
411                                         str = "read";
412                                 else if (rc == LL_LEASE_WRLCK)
413                                         str = "write";
414                                 fprintf(stdout, "%s lease(%lld) has applied.\n",
415                                         str, rc);
416                                 if (*commands == '-')
417                                         errx(-1, "expect lease to not exist");
418                         } else if (rc == 0) {
419                                 fprintf(stdout, "no lease applied.\n");
420                                 if (*commands == '+')
421                                         errx(-1, "expect lease exists");
422                         } else {
423                                 err(errno, "free lease error");
424                         }
425                         break;
426                 case 'f':
427                         if (statfs(fname, &stfs) == -1)
428                                 errx(-1, "statfs()");
429                         break;
430                 case 'F':
431                         if (fd == -1)
432                                 rc = llapi_path2fid(fname, &fid);
433                         else
434                                 rc = llapi_fd2fid(fd, &fid);
435                         if (rc != 0)
436                                 fprintf(stderr,
437                                         "llapi_path/fd2fid() on %d, rc=%lld\n",
438                                         fd, rc);
439                         else
440                                 printf(DFID"\n", PFID(&fid));
441                         fflush(stdout);
442                         break;
443                 case 'G':
444                         gid = atoi(commands+1);
445                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
446                                 save_errno = errno;
447                                 perror("ioctl(GROUP_LOCK)");
448                                 exit(save_errno);
449                         }
450                         break;
451                 case 'g':
452                         gid = atoi(commands+1);
453                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
454                                 save_errno = errno;
455                                 perror("ioctl(GROUP_UNLOCK)");
456                                 exit(save_errno);
457                         }
458                         break;
459                 case 'H':
460                         len = atoi(commands+1);
461                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
462                                 0644, 0, 0, len,
463                                 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
464                         if (fd == -1) {
465                                 save_errno = errno;
466                                 perror("create stripe file");
467                                 exit(save_errno);
468                         }
469                         rc = fd;
470                         break;
471                 case 'j':
472                         if (flock(fd, LOCK_EX) == -1)
473                                 errx(-1, "flock()");
474                         break;
475                 case 'K':
476                         oldpath = POP_ARG();
477                         if (oldpath == NULL)
478                                 oldpath = fname;
479
480                         if (link(oldpath, fname)) {
481                                 save_errno = errno;
482                                 perror("link()");
483                                 exit(save_errno);
484                         }
485                         break;
486                 case 'l':
487                         newfile = POP_ARG();
488                         if (!newfile)
489                                 newfile = fname;
490                         if (symlink(fname, newfile)) {
491                                 save_errno = errno;
492                                 perror("symlink()");
493                                 exit(save_errno);
494                         }
495                         break;
496                 case 'L':
497                         newfile = POP_ARG();
498                         if (newfile == NULL)
499                                 newfile = fname;
500
501                         if (link(fname, newfile)) {
502                                 save_errno = errno;
503                                 perror("link()");
504                                 exit(save_errno);
505                         }
506                         break;
507                 case 'm':
508                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
509                                 save_errno = errno;
510                                 perror("mknod(S_IFREG|0644, 0)");
511                                 exit(save_errno);
512                         }
513                         break;
514                 case 'M':
515                         if (st.st_size == 0) {
516                                 fprintf(stderr, "mmap without preceeding stat, or on"
517                                         " zero length file.\n");
518                                 exit(-1);
519                         }
520                         mmap_len = st.st_size;
521                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
522                                         MAP_SHARED, fd, 0);
523                         if (mmap_ptr == MAP_FAILED) {
524                                 save_errno = errno;
525                                 perror("mmap");
526                                 exit(save_errno);
527                         }
528                         break;
529                 case 'n':
530                         oldpath = POP_ARG();
531                         if (oldpath == NULL)
532                                 oldpath = fname;
533
534                         if (rename(oldpath, fname) < 0) {
535                                 save_errno = errno;
536                                 perror("rename()");
537                                 exit(save_errno);
538                         }
539                         break;
540                 case 'N':
541                         newfile = POP_ARG();
542                         if (!newfile)
543                                 newfile = fname;
544                         if (rename (fname, newfile)) {
545                                 save_errno = errno;
546                                 perror("rename()");
547                                 exit(save_errno);
548                         }
549                         break;
550                 case 'O':
551                         fd = open(fname, O_CREAT|O_RDWR, 0644);
552                         if (fd == -1) {
553                                 save_errno = errno;
554                                 perror("open(O_RDWR|O_CREAT)");
555                                 exit(save_errno);
556                         }
557                         rc = fd;
558                         break;
559                 case 'o':
560                         len = get_flags(commands+1, &flags);
561                         commands += len;
562                         if (flags & O_CREAT)
563                                 fd = open(fname, flags, 0666);
564                         else
565                                 fd = open(fname, flags);
566                         if (fd == -1) {
567                                 save_errno = errno;
568                                 perror("open");
569                                 exit(save_errno);
570                         }
571                         rc = fd;
572                         break;
573                 case 'p':
574                         printf("%lld\n", last_rc);
575                         break;
576                 case 'Q':
577                         save_errno = statahead(fname);
578                         if (save_errno) {
579                                 perror("statahead");
580                                 exit(save_errno);
581                         }
582                         break;
583                 case 'r':
584                         len = atoi(commands+1);
585                         if (len <= 0)
586                                 len = 1;
587                         if (bufsize < len) {
588                                 void *tmp;
589                                 tmp = realloc(buf, len + ALIGN_LEN);
590                                 if (tmp == NULL) {
591                                         free(buf);
592                                         save_errno = errno;
593                                         perror("allocating buf for read\n");
594                                         exit(save_errno);
595                                 }
596                                 buf = tmp;
597                                 bufsize = len;
598                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
599                                                      ~ALIGN_LEN);
600                         }
601                         while (len > 0) {
602                                 rc = read(fd, buf_align, len);
603                                 if (rc == -1) {
604                                         save_errno = errno;
605                                         perror("read");
606                                         exit(save_errno);
607                                 }
608                                 if (rc < len) {
609                                         fprintf(stderr, "short read: %lld/%u\n",
610                                                 rc, len);
611                                         if (rc == 0)
612                                                 exit(ENODATA);
613                                 }
614                                 len -= rc;
615                                 if (verbose >= 2)
616                                         printf("%.*s\n", (int)rc, buf_align);
617                         }
618                         break;
619                 case 'R':
620                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
621                                 junk += mmap_ptr[i];
622                         break;
623                 case 's':
624                         if (stat(fname, &st) == -1) {
625                                 save_errno = errno;
626                                 perror("stat");
627                                 exit(save_errno);
628                         }
629                         break;
630                 case 'S':
631                         if (fstat(fd, &st) == -1) {
632                                 save_errno = errno;
633                                 perror("fstat");
634                                 exit(save_errno);
635                         }
636                         break;
637                 case 't':
638                         if (fchmod(fd, 0) == -1) {
639                                 save_errno = errno;
640                                 perror("fchmod");
641                                 exit(save_errno);
642                         }
643                         break;
644                 case 'T':
645                         len = atoi(commands+1);
646                         if (ftruncate(fd, len) == -1) {
647                                 save_errno = errno;
648                                 printf("ftruncate (%d,%d)\n", fd, len);
649                                 perror("ftruncate");
650                                 exit(save_errno);
651                         }
652                         break;
653                 case 'u':
654                         if (unlink(fname) == -1) {
655                                 save_errno = errno;
656                                 perror("unlink");
657                                 exit(save_errno);
658                         }
659                         break;
660                 case 'U':
661                         if (munmap(mmap_ptr, mmap_len)) {
662                                 save_errno = errno;
663                                 perror("munmap");
664                                 exit(save_errno);
665                         }
666                         break;
667                 case 'v':
668                         verbose++;
669                         break;
670                 case 'V':
671                         len = get_flags(commands + 1, &flags);
672                         commands += len;
673                         len = -1; /* mdt index */
674                         if (commands[1] >= '0' && commands[1] <= '9')
675                                 len = atoi(commands+1);
676                         fd = llapi_create_volatile_idx(fname, len, flags);
677                         if (fd < 0) {
678                                 perror("llapi_create_volatile");
679                                 exit(fd);
680                         }
681                         rc = fd;
682                         break;
683                 case 'w':
684                         len = atoi(commands+1);
685                         if (len <= 0)
686                                 len = 1;
687                         if (bufsize < len) {
688                                 void *tmp;
689                                 tmp = realloc(buf, len + ALIGN_LEN);
690                                 if (tmp == NULL) {
691                                         free(buf);
692                                         save_errno = errno;
693                                         perror("allocating buf for write\n");
694                                         exit(save_errno);
695                                 }
696                                 buf = tmp;
697                                 bufsize = len;
698                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
699                                                      ~ALIGN_LEN);
700                                 strncpy(buf_align, msg, bufsize);
701                         }
702                         while (len > 0) {
703                                 rc = write(fd, buf_align, len);
704                                 if (rc == -1) {
705                                         save_errno = errno;
706                                         perror("write");
707                                         exit(save_errno);
708                                 }
709                                 if (rc < len)
710                                         fprintf(stderr, "short write: %lld/%u\n",
711                                                 rc, len);
712                                 len -= rc;
713                         }
714                         break;
715                 case 'W':
716                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
717                                 mmap_ptr[i] += junk++;
718                         break;
719                 case 'x': {
720                         __u64 dv;
721
722                         rc = llapi_get_data_version(fd, &dv, 0);
723                         if (rc) {
724                                 fprintf(stderr, "cannot get file data version"
725                                         " %lld\n", rc);
726                                 exit(-rc);
727                         }
728                         printf("dataversion is %ju\n", (uintmax_t)dv);
729                         break;
730                 }
731                 case 'X': {
732                         __u32 layout_version;
733
734                         rc = llapi_get_ost_layout_version(fd, &layout_version);
735                         if (rc) {
736                                 fprintf(stderr, "cannot get ost layout version"
737                                         " %lld\n", rc);
738                                 exit(-rc);
739                         }
740                         printf("ostlayoutversion: %u\n", layout_version);
741                         break;
742                 }
743                 case 'y':
744                         if (fsync(fd) == -1) {
745                                 save_errno = errno;
746                                 perror("fsync");
747                                 exit(save_errno);
748                         }
749                         break;
750                 case 'Y':
751                         if (fdatasync(fd) == -1) {
752                                 save_errno = errno;
753                                 perror("fdatasync");
754                                 exit(save_errno);
755                         }
756                         break;
757                 case 'z': {
758                         off_t off;
759
760                         len = atoi(commands + 1);
761                         off = lseek(fd, len, SEEK_SET);
762                         if (off == (off_t)-1) {
763                                 save_errno = errno;
764                                 perror("lseek");
765                                 exit(save_errno);
766                         }
767
768                         rc = off;
769                         break;
770                 }
771                 case 'Z': {
772                         off_t off;
773
774                         len = atoi(commands + 1);
775                         off = lseek(fd, len, SEEK_CUR);
776                         if (off == (off_t)-1) {
777                                 save_errno = errno;
778                                 perror("lseek");
779                                 exit(save_errno);
780                         }
781
782                         rc = off;
783                         break;
784                 }
785                 case '-':
786                 case '0':
787                 case '1':
788                 case '2':
789                 case '3':
790                 case '4':
791                 case '5':
792                 case '6':
793                 case '7':
794                 case '8':
795                 case '9':
796                         break;
797                 default:
798                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
799                         fprintf(stderr, usage, argv[0]);
800                         exit(1);
801                 }
802         }
803
804         if (buf)
805                 free(buf);
806
807         return 0;
808 }