blob: ff933954ceb77fe8c5253dc14d0f62738b9d3fd2 [file] [log] [blame]
/*
* Copyright (c) 2013 SGI. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* 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;
}