aboutsummaryrefslogtreecommitdiffstats
path: root/idkey/main.c
blob: 16b223257f2ae6d3f856e578e8abb5b118e544be (plain)
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
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define EXIT_SUCCESS		0
#define EXIT_CMDLINE		1
#define EXIT_FILEOPEN		2
#define EXIT_FILEREAD		3
#define EXIT_FILEWRITE		4
#define EXIT_INVALID		5
#define EXIT_ALLOC			6

#define BLOCK_SIZE			4096

/// @brief Header of the datas.
typedef struct header_
{
	char mn[4];
	size_t size;
} header;

/// @brief Check if the @c v is a valid magick number.
/// @param[in] v magick number.
/// @return 1 if valid, zero otherwise.
int is_valid_nm(const char* v)
{
	return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y';
}

/// @brief Close the file descriptor if valid then print a formatted error message then return the specified code.
/// @param[in] fd File descriptor to close.
/// @param[in] code The exit code to return.
/// @param[in] format The message to print.
/// @param[in] ... Values for formatting.
/// @return The exit code provided by @c code.
int close_and_fail(int fd, int code, const char* format, ...)
{
	va_list arglist;
	fprintf(stderr, "Error: ");
	va_start(arglist, format);
	vfprintf(stderr, format, arglist);
	va_end(arglist);
	fprintf(stderr, "\n");
	return code;
}

/// @brief Read the device @c devname and print it's data to stdout.
/// @param[in] devname Device's name.
/// @return Exit code, zero if success.
int read_device(const char* devname)
{
	int fd = open(devname, O_RDONLY);
	if (fd == -1) return close_and_fail(fd, EXIT_FILEOPEN, "Failed to open '%s'!", devname);

	header h;
	ssize_t sz = read(fd, &h, sizeof(header));
	if (sz != sizeof(header)) return close_and_fail(fd, EXIT_FILEREAD, "Failed to read the header!");
	if (!is_valid_nm(h.mn)) return close_and_fail(fd, EXIT_INVALID, "Not a valid identity key!");

	while(h.size)
	{
		char datas[BLOCK_SIZE + 1];
		memset(datas, BLOCK_SIZE +1, 0);
		size_t count = BLOCK_SIZE > h.size ? h.size : BLOCK_SIZE;

		sz = read(fd, datas, count);

		if (sz != count) close_and_fail(fd, EXIT_FILEREAD, "Failed to read a data block!");
		h.size = (h.size - count);

		printf(datas);
	}
	printf("\n");
	close(fd);
	return EXIT_SUCCESS;
}

/// @brief Write the specified data to the specified device.
/// @param[in] devname Name of the device.
/// @param[in] datas Datas to write.
/// @return Exit code, zero if success, non-zero otherwise.
int write_device(const char* devname, const char* datas)
{
	header h = {
		.mn = {'I', 'D', 'K', 'Y'},
		.size = strlen(datas)
	};
	if (h.size < 1) return close_and_fail(-1, EXIT_CMDLINE, "No data to write!");

	int fd = open(devname, O_WRONLY);
	if (fd == -1) return close_and_fail(fd, EXIT_FILEOPEN, "Failed to open device '%s'!", devname);
	if (write(fd, &h, sizeof(header)) != sizeof(header)) return close_and_fail(fd, EXIT_FILEWRITE, "Failed to write the header!");
	if (write(fd, datas, h.size) != h.size) return close_and_fail(fd, EXIT_FILEWRITE, "Failed to write datas!");
	
	close(fd);
	return EXIT_SUCCESS;
}

/// @brief Entry point.
/// @param[in] argc Number of arguments in @c argv.
/// @param[in] argv Arguments array.
/// @return Exit code, zero if success, non-zero otherwise.
int main(int argc, char** argv)
{
	switch(argc)
	{
	case 0:
	case 1:
		fprintf(stderr, "ERROR: too few arguments!\n");
		return EXIT_CMDLINE;

	case 2: // Read the device
		return read_device(argv[1]);

	case 3: // Write the device
		return write_device(argv[1], argv[2]);

	default:
		fprintf(stderr, "ERROR: too many arguments!\n");
		return EXIT_CMDLINE;
	}
}