| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Copyright (c) 2013 SGI. All Rights Reserved. | |
| */ | |
| /* dxm - 28/2/2 */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <malloc.h> | |
| #include <fcntl.h> | |
| #include <errno.h> | |
| #include <string.h> | |
| #include <sys/stat.h> | |
| #include <sys/socket.h> | |
| #include <unistd.h> | |
| #include <sys/types.h> | |
| FILE *fp = NULL; | |
| #define LL "ll" | |
| #define PERROR(a,b) perror(a) | |
| #define GET_LAST_ERROR errno | |
| #define HANDLE int | |
| #define INVALID_HANDLE -1 | |
| #define TRUNCATE_ERROR -1 | |
| #define FLUSH_ERROR EOF | |
| #define FILE_BEGIN SEEK_SET | |
| #define FILE_CURRENT SEEK_CUR | |
| #define OPEN(N, F) open(N, O_CREAT|O_RDWR|F, 0644); fp = fdopen(f, "r+") | |
| #define SEEK(H, O, F) (lseek(H, O, F)) | |
| #define READ(H, B, L) (read(H, B, L)) | |
| #define WRITE(H, B, L) (write(H, B, L)) | |
| #define CLOSE(H) (close(H)) | |
| #define DELETE_FILE(F) (unlink(F)) | |
| #define FLUSH(F) (fflush(fp)) | |
| #define TRUNCATE(F) (ftruncate(F, 0)) | |
| #define ALLOC_ALIGNED(S) (memalign(65536, S)) | |
| #define FREE_ALIGNED(P) (free(P)) | |
| #define DIRECT_IO_FLAG O_DIRECT | |
| enum { | |
| FLAG_OPENCLOSE = 1, | |
| FLAG_READ = 2, | |
| FLAG_WRITE = 4, | |
| FLAG_VERBOSE = 8, | |
| FLAG_TRUNCATE = 16, | |
| FLAG_SEQUENTIAL = 32, | |
| FLAG_FLUSH = 64, | |
| FLAG_DELETE = 128, | |
| FLAG_DIRECT = 256, | |
| }; | |
| void | |
| usage(char *argv0) | |
| { | |
| printf( | |
| "Usage: %s [switches] <filename>\n" | |
| " -i <count> = repeat count (default forever)\n" | |
| " -o = open/close\n" | |
| " -r = read\n" | |
| " -w = write\n" | |
| " -t = truncate\n" | |
| " -d = delete\n" | |
| " -b <size> = buffer size\n" | |
| " -v = verbose\n" | |
| " -s = sequential\n" | |
| " -f = flush\n" | |
| " -D = direct-IO\n" | |
| " -h = usage\n", | |
| argv0); | |
| } | |
| extern int optind; | |
| extern char *optarg; | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| HANDLE f = INVALID_HANDLE; | |
| char *filename; | |
| int i; | |
| int c; | |
| int count = -1; | |
| int bufsize = 4096; | |
| int flags = 0; | |
| char *buf = NULL; | |
| int64_t seek_to = 0; | |
| while ((c = getopt(argc, argv, "i:orwb:svthfFDd?")) != EOF) { | |
| switch (c) { | |
| case 'i': | |
| count = atoi(optarg); | |
| break; | |
| case 'o': | |
| flags |= FLAG_OPENCLOSE; | |
| break; | |
| case 'r': | |
| flags |= FLAG_READ; | |
| break; | |
| case 'w': | |
| flags |= FLAG_WRITE; | |
| break; | |
| case 't': | |
| flags |= FLAG_TRUNCATE; | |
| break; | |
| case 'v': | |
| flags |= FLAG_VERBOSE; | |
| break; | |
| case 'b': | |
| bufsize = atoi(optarg); | |
| break; | |
| case 's': | |
| flags |= FLAG_SEQUENTIAL; | |
| break; | |
| case 'f': | |
| flags |= FLAG_FLUSH; | |
| break; | |
| case 'D': | |
| flags |= FLAG_DIRECT; | |
| break; | |
| case 'd': | |
| flags |= FLAG_DELETE; | |
| break; | |
| case '?': | |
| case 'h': | |
| default: | |
| usage(argv[0]); | |
| return 1; | |
| } | |
| } | |
| if (optind != argc - 1) { | |
| usage(argv[0]); | |
| return 1; | |
| } | |
| filename = argv[optind]; | |
| if (!flags) { | |
| fprintf(stderr, "nothing to do!\n"); | |
| exit(1); | |
| } | |
| if (flags & FLAG_DIRECT) | |
| buf = (char *)ALLOC_ALIGNED(bufsize); | |
| else | |
| buf = (char *)malloc(bufsize); | |
| if (!buf) | |
| PERROR("malloc", GET_LAST_ERROR); | |
| for (i = 0; i < bufsize; i++) { | |
| buf[i] = i & 127; | |
| } | |
| for (i = 0; count < 0 || i < count; i++) { | |
| if ((flags & FLAG_OPENCLOSE) || !i) { | |
| int fileflags; | |
| if (flags & FLAG_VERBOSE) | |
| printf("open %s\n", filename); | |
| fileflags = 0; | |
| if (flags & FLAG_DIRECT) | |
| fileflags |= DIRECT_IO_FLAG; | |
| f = OPEN(filename, fileflags); | |
| if (f == INVALID_HANDLE) | |
| PERROR("OPEN", GET_LAST_ERROR); | |
| } | |
| if ((flags & FLAG_OPENCLOSE) && (flags & FLAG_SEQUENTIAL)) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("seek %" LL "d\n", (long long)seek_to); | |
| if (SEEK(f, seek_to, FILE_BEGIN) < 0) | |
| PERROR("SEEK", GET_LAST_ERROR); | |
| } | |
| if (flags & FLAG_WRITE) { | |
| int sizewritten; | |
| if (!(flags & FLAG_SEQUENTIAL)) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("seek %" LL "d\n", (long long)seek_to); | |
| if (SEEK(f, seek_to, FILE_BEGIN) < 0) | |
| PERROR("SEEK", GET_LAST_ERROR); | |
| } | |
| if (flags & FLAG_VERBOSE) | |
| printf("write %d\n", bufsize); | |
| if ((sizewritten = WRITE(f, buf, bufsize)) != bufsize) { | |
| if (sizewritten < 0) | |
| PERROR("WRITE", GET_LAST_ERROR); | |
| else | |
| fprintf(stderr, "short write: %d of %d\n", | |
| sizewritten, bufsize); | |
| } | |
| } | |
| if (flags & FLAG_READ) { | |
| int sizeread; | |
| if (!(flags & FLAG_SEQUENTIAL) || (flags & FLAG_WRITE)) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("seek %" LL "d\n", (long long)seek_to); | |
| if (SEEK(f, seek_to, FILE_BEGIN) < 0) | |
| PERROR("SEEK", GET_LAST_ERROR); | |
| } | |
| if (flags & FLAG_VERBOSE) | |
| printf("read %d\n", bufsize); | |
| if ((sizeread = READ(f, buf, bufsize)) != bufsize) { | |
| if (sizeread < 0) | |
| PERROR("READ", GET_LAST_ERROR); | |
| else if (sizeread) | |
| fprintf(stderr, "short read: %d of %d\n", | |
| sizeread, bufsize); | |
| else { | |
| fprintf(stderr, "Read past EOF\n"); | |
| exit(0); | |
| } | |
| } | |
| } | |
| if (flags & FLAG_TRUNCATE) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("seek 0\n"); | |
| if (SEEK(f, 0, FILE_BEGIN) < 0) | |
| PERROR("SEEK", GET_LAST_ERROR); | |
| if (flags & FLAG_VERBOSE) | |
| printf("truncate\n"); | |
| if (TRUNCATE(f) == TRUNCATE_ERROR) | |
| PERROR("TRUNCATE", GET_LAST_ERROR); | |
| } | |
| if (flags & FLAG_FLUSH) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("flush\n"); | |
| if (FLUSH(f) == FLUSH_ERROR) | |
| PERROR("FLUSH", GET_LAST_ERROR); | |
| } | |
| if (flags & FLAG_SEQUENTIAL) { | |
| seek_to += bufsize; | |
| if (flags & FLAG_TRUNCATE) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("seek %" LL "d\n", (long long)seek_to); | |
| if (SEEK(f, seek_to, FILE_BEGIN) < 0) | |
| PERROR("SEEK", GET_LAST_ERROR); | |
| } | |
| } | |
| if (flags & FLAG_OPENCLOSE) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("close %s\n", filename); | |
| CLOSE(f); | |
| } | |
| if (flags & FLAG_DELETE) { | |
| if (flags & FLAG_VERBOSE) | |
| printf("delete %s\n", filename); | |
| DELETE_FILE(filename); | |
| } | |
| } | |
| if (buf) { | |
| if (flags & FLAG_DIRECT) | |
| FREE_ALIGNED(buf); | |
| else | |
| free(buf); | |
| } | |
| return 0; | |
| } |