-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsend.c
136 lines (113 loc) · 2.65 KB
/
send.c
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
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sysexits.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "loader.h"
#define NSEC_PER_SEC (1000000000ULL)
#define DEFAULT_BAUD_RATE 115200
#define BLOCK_SIZE 32
__attribute__((noreturn)) static void usage(void) {
fprintf(stderr, "usage: send [-b baud] -s /dev/node input ...\n");
exit(EX_USAGE);
}
static void configure(const int fd, const speed_t baud) {
struct termios tty = {0};
if (tcgetattr(fd, &tty) != 0) {
err(EX_NOINPUT, "tcgetattr");
}
cfsetispeed(&tty, baud);
cfsetospeed(&tty, baud);
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
err(EX_OSERR, "tcsetattr");
}
}
static size_t rate(struct timespec start, struct timespec now, size_t bytes) {
struct timespec diff;
diff.tv_sec = now.tv_sec - start.tv_sec;
diff.tv_nsec = now.tv_nsec - start.tv_nsec;
size_t rate = 0;
if (diff.tv_sec != 0) {
rate += bytes/diff.tv_sec;
}
if (diff.tv_nsec != 0) {
rate += bytes/diff.tv_nsec/NSEC_PER_SEC;
}
return rate;
}
static void send(const int sock, const char *filename) {
struct stat s;
if(stat(filename, &s)) {
errx(EX_IOERR, "stat");
}
const size_t totalSize = s.st_size;
struct timespec start;
clock_gettime(CLOCK_MONOTONIC, &start);
FILE *in = fopen(filename, "r");
char buf[BLOCK_SIZE];
size_t offset = 0;
size_t bytesRead;
struct timespec now;
size_t bps;
long remaining = 0;
while((bytesRead = fread(buf, 1, BLOCK_SIZE, in))) {
offset += bytesRead;
clock_gettime(CLOCK_MONOTONIC, &now);
bps = rate(start, now, offset);
if (bps) {
remaining = (totalSize - offset) / bps;
}
fprintf(stderr,
"%#08zx - "
"%zu/%zu bytes - "
"%zu bytes/sec - "
"%zu%% - "
"%lum%lus remaining \r",
offset + (size_t)LOAD_ADDR,
offset, totalSize,
bps,
(offset * 100) / totalSize,
remaining / 60, remaining % 60
);
write(sock, buf, bytesRead);
}
fclose(in);
}
int main(int argc, char * const argv[]) {
/*
* The expected usage is something along the lines of:
* send -b 9600 -s /dev/sttynode file_to_send ...
*/
speed_t baud = DEFAULT_BAUD_RATE;
int ch;
const char *node = NULL;
while ((ch = getopt(argc, argv, "b:s:")) != -1) {
switch (ch) {
case 'b': {
baud = strtoul(optarg, NULL, 10);
} break;
case 's': {
node = optarg;
} break;
case '?':
default: {
usage();
}
}
}
argc -= optind;
argv += optind;
if (!node) {
warnx("You must specify a valid serial device node");
usage();
}
const int out = open(node, O_RDWR | O_NOCTTY | O_SYNC);
configure(out, baud);
send(out, argv[0]);
close(out);
return EX_OK;
}