1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
/* ----------------------------------------------------------------------- *
*
* Copyright 2010-2011 Gene Cumm
*
* 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, Inc., 53 Temple Place Ste 330,
* Boston MA 02111-1307, USA; either version 2 of the License, or
* (at your option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/*
* cptime.c Version 1.4
*
* Timed copy; read entire file then output total time, bytes transferred,
* and compute transfer rate.
*
* cptime [-s|-l] [-v|-q] [-b _SIZE_] [-n _LEN_] _FILE_...
* -s Change to simple output mode without computing transfer rate
* -l Change to long output mode (to allow for overriding previous -s)
* -v Verbose output
* -q Quiet output
* -b _SIZE_ use _SIZE_ for transfer size
* -n _LEN_ maximum length to fetch
* _FILE_... Space delimited list of files to dump
* Note: The last instance of -s or -l wins, along with the last use of -b and -n and the winning option will be applied to all operations
*
* Hisory:
* 1.4 Use fread() rather than read(); use CLK_TCK when available.
* 1.3 Added -v/-q; rework some argument processing.
* 1.2 Added -n
* 1.1 Added -l and -b switches; more flexible command line processing
* 1.0 First release
*/
/*
* ToDos:
* - Refine timing to be more precise. Low priority.
* - Add -o for offset. Wishlist.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/times.h>
#include <consoles.h>
#include <minmax.h>
#include <limits.h>
#include <string.h>
#include <stdint.h>
#include <console.h>
#ifdef __COM32__
# define BUFSZ_DEF (size_t)2048
/* What's optimal? Under 4k?
* layout.inc: xfer_buf_seg equ 1000h
* com32.inc: push dword (1 << 16) ; 64K bounce buffer
*/
/* typedef size_t off_t */
# define TPS_T float
# ifdef CLK_TCK
static inline TPS_T get_tps(void) { return CLK_TCK; }
# else
static inline TPS_T get_tps(void) { return 18.2; }
# endif
#else /* __COM32__ */
# define BUFSZ_DEF (size_t)16384
/* Need to check what might be a "best" buffer/fetch block size here */
# define TPS_T long
static inline TPS_T get_tps(void) { return sysconf(_SC_CLK_TCK); }
#endif /* __COM32__ */
#ifndef SSIZE_MAX
# define SSIZE_MAX PTRDIFF_MAX
#endif
/* typedef ptrdiff_t ssize_t; */
#define BUFSZ_MAX (size_t)SSIZE_MAX
/* ssize_t max */
#define BUFSZ_MIN (size_t)1
/* Please note: I don't know the origin of these two macros nor their license */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
#define TYPE_MAX(t) \
((t) (! TYPE_SIGNED (t) \
? (t) -1 \
: ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
#ifndef OFF_T_MAX
# define OFF_T_MAX TYPE_MAX(off_t)
#endif
/* Can't be SIZE_MAX or SSIZE_MAX as Syslinux/COM32 is unsigned while Linux
* is signed.
*/
#define LEN_MAX OFF_T_MAX
/* off_t max */
#define LEN_MIN (off_t)0
void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs)
{
size_t dr;
/* prevent divide by 0 */
dr = max(bcnt, (bcnt * tps)) / max((clock_t)1, (et + offs));
printf(" %+d %zu B/s; %zu KiB/s; %zu MiB/s\n", offs, dr, dr/1024, dr/1048576);
} /* void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs) */
void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose)
{
TPS_T tps;
if (do_verbose > 2)
printf("Enter print_cp_result_long()\n");
tps = get_tps();
printf(" %zu B in %d ticks from '%s'\n", bcnt, (int)(ec - bc), fn);
printf(" ~%d ticks per second; %zu B block/transfer size\n", (int)tps, bufsz);
print_cp_result_tick(bcnt, (ec - bc), tps, 0);
print_cp_result_tick(bcnt, (ec - bc), tps, 1);
print_cp_result_tick(bcnt, (ec - bc), tps, -1);
} /* void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz) */
void print_cp_result_simple(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose)
{
if (do_verbose) {}
printf(" %zuB %dt %zux '%s'\n", bcnt, (int)(ec - bc), bufsz, fn);
} /* void print_cp_result_simple(char *fn, int bcnt, clock_t bc, clock_t ec, char do_verbose) */
size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen)
{
return min(bufsz, (maxlen - bcnt));
} /* size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen) */
int time_copy(char *fn, char do_simple, char do_verbose, size_t ibufsz, off_t maxlen)
{
// int fd;
int rv = 0;
int i = 0;
FILE *f;
size_t bufsz, bcnt = 0;
int numrd;
struct tms tm;
clock_t bc, ec;
char buf[ibufsz + 1];
buf[0] = 0;
if (do_verbose)
printf("Trying file '%s'\n", fn);
errno = 0;
// fd = open(fn, O_RDONLY);
f = fopen(fn, "r");
// if (fd == -1) {
if (!f) {
switch (errno) {
case ENOENT :
printf("File '%s' does not exist\n", fn);
break;
case EBADF:
printf("File '%s': Bad File Descriptor\n", fn);
break;
default :
printf("Error '%d' opening file '%s'\n", errno, fn);
}
rv = 1;
} else {
if (do_verbose)
printf("File '%s' opened\n", fn);
bufsz = time_copy_bufsz(ibufsz, bcnt, maxlen);
bc = times(&tm);
// numrd = read(fd, buf, bufsz);
// numrd = fread(buf, bufsz, 1, f);
numrd = fread(buf, 1, bufsz, f);
i++;
if (numrd > 0)
bcnt = numrd;
while ((numrd > 0) && (bufsz > 0)) {
bufsz = time_copy_bufsz(bufsz, bcnt, maxlen);
// numrd = read(fd, buf, bufsz);
// numrd = fread(buf, bufsz, 1, f);
numrd = fread(buf, 1, bufsz, f);
i++;
if (numrd >= 0)
// bcnt = bcnt + numrd;
bcnt += numrd;
}
ec = times(&tm);
// close(fd);
fclose(f);
if (do_verbose)
printf("File '%s' closed\n", fn);
if (numrd < 0) {
switch (errno) {
case EIO :
printf("IO Error at %zu B reading file '%s'\n", bcnt, fn);
break;
case EINVAL :
printf("Invalid Mode at %zu B reading file '%s'\n", bcnt, fn);
break;
default :
printf("Error '%d' at %zu B reading file '%s'\n", errno, bcnt, fn);
}
rv = 2;
}
if (bcnt > 0) {
if (bufsz == 0)
printf("maxed out on maxln\n");
if (do_simple)
print_cp_result_simple(fn, bcnt, bc, ec, ibufsz, do_verbose);
else
print_cp_result_long(fn, bcnt, bc, ec, ibufsz, do_verbose);
}
if (do_verbose)
printf(" numrd %d bcnt %d bufsz %d i %d\n", numrd, bcnt, bufsz, i);
}
return rv;
} /* int time_copy(char *fn, char do_simple, int bufsz, off_t maxlen) */
int main(int argc, char *argv[])
{
int i;
char do_simple = 0, do_pbuf = 0, do_plen = 0, do_verbose = 0;
char *arg;
size_t tbufsz, bufsz = min((BUFSZ_DEF), (BUFSZ_MAX));
off_t tmaxlen, maxlen = LEN_MAX;
int numfl = 0;
console_ansi_std();
// openconsole(&dev_stdcon_r, &dev_stdcon_w);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
arg = argv[i] + 1;
if (strcmp(arg, "b") == 0) {
i++;
if (i < argc) {
tbufsz = atoi(argv[i]);
if (tbufsz > 0)
bufsz = min(max((BUFSZ_MIN), tbufsz), (BUFSZ_MAX));
do_pbuf = 1;
}
} else if (strcmp(arg, "n") == 0) {
i++;
if (i < argc) {
tmaxlen = atoi(argv[i]);
if (tmaxlen > 0)
maxlen = min(max((LEN_MIN), tmaxlen), (LEN_MAX));
do_plen = 1;
}
} else if (strcmp(arg, "s") == 0)
do_simple = 1;
else if (strcmp(arg, "l") == 0)
do_simple = 0;
else if (strcmp(arg, "v") == 0)
do_verbose = 1;
else if (strcmp(arg, "q") == 0)
do_verbose = 0;
}
}
if (do_pbuf || do_verbose)
printf("Using bufsz %zu\n", bufsz);
if (do_plen || do_verbose)
printf("Using maxlen %zu\n", maxlen);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
arg = argv[i] + 1;
if ((strcmp(arg, "b") == 0) || (strcmp(arg, "n") == 0))
i++; /* Skip next arg */
else if (!((strcmp(arg, "s") == 0) || (strcmp(arg, "l") == 0) || (strcmp(arg, "v") == 0) || (strcmp(arg, "q") == 0))) {
time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen);
numfl++;
}
} else {
time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen);
numfl++;
}
}
if (numfl == 0)
fprintf(stderr, "%s: Please specify a file\n", argv[0]);
return 0;
} /* int main(int argc, char *argv[]) */
|