first somewhat working version.
[apps/agl-service-data-persistence.git] / idkey / main.c
1 #include <fcntl.h>
2 #include <stdarg.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8
9 #define EXIT_SUCCESS            0
10 #define EXIT_CMDLINE            1
11 #define EXIT_FILEOPEN           2
12 #define EXIT_FILEREAD           3
13 #define EXIT_FILEWRITE          4
14 #define EXIT_INVALID            5
15 #define EXIT_ALLOC                      6
16
17 #define BLOCK_SIZE                      4096
18
19 /// @brief Header of the datas.
20 typedef struct header_
21 {
22         char mn[4];
23         size_t size;
24 } header;
25
26 /// @brief Check if the @c v is a valid magick number.
27 /// @param[in] v magick number.
28 /// @return 1 if valid, zero otherwise.
29 int is_valid_nm(const char* v)
30 {
31         return v && v[0] == 'I' && v[1] == 'D' && v[2] == 'K' && v[3] == 'Y';
32 }
33
34 /// @brief Close the file descriptor if valid then print a formatted error message then return the specified code.
35 /// @param[in] fd File descriptor to close.
36 /// @param[in] code The exit code to return.
37 /// @param[in] format The message to print.
38 /// @param[in] ... Values for formatting.
39 /// @return The exit code provided by @c code.
40 int close_and_fail(int fd, int code, const char* format, ...)
41 {
42         va_list arglist;
43         fprintf(stderr, "Error: ");
44         va_start(arglist, format);
45         vfprintf(stderr, format, arglist);
46         va_end(arglist);
47         fprintf(stderr, "\n");
48         return code;
49 }
50
51 /// @brief Read the device @c devname and print it's data to stdout.
52 /// @param[in] devname Device's name.
53 /// @return Exit code, zero if success.
54 int read_device(const char* devname)
55 {
56         int fd = open(devname, O_RDONLY);
57         if (fd == -1) return close_and_fail(fd, EXIT_FILEOPEN, "Failed to open '%s'!", devname);
58
59         header h;
60         ssize_t sz = read(fd, &h, sizeof(header));
61         if (sz != sizeof(header)) return close_and_fail(fd, EXIT_FILEREAD, "Failed to read the header!");
62         if (!is_valid_nm(h.mn)) return close_and_fail(fd, EXIT_INVALID, "Not a valid identity key!");
63
64         while(h.size)
65         {
66                 char datas[BLOCK_SIZE + 1];
67                 memset(datas, BLOCK_SIZE +1, 0);
68                 size_t count = BLOCK_SIZE > h.size ? h.size : BLOCK_SIZE;
69
70                 sz = read(fd, datas, count);
71
72                 if (sz != count) close_and_fail(fd, EXIT_FILEREAD, "Failed to read a data block!");
73                 h.size = (h.size - count);
74
75                 printf(datas);
76         }
77         printf("\n");
78         close(fd);
79         return EXIT_SUCCESS;
80 }
81
82 /// @brief Write the specified data to the specified device.
83 /// @param[in] devname Name of the device.
84 /// @param[in] datas Datas to write.
85 /// @return Exit code, zero if success, non-zero otherwise.
86 int write_device(const char* devname, const char* datas)
87 {
88         header h = {
89                 .mn = {'I', 'D', 'K', 'Y'},
90                 .size = strlen(datas)
91         };
92         if (h.size < 1) return close_and_fail(-1, EXIT_CMDLINE, "No data to write!");
93
94         int fd = open(devname, O_WRONLY);
95         if (fd == -1) return close_and_fail(fd, EXIT_FILEOPEN, "Failed to open device '%s'!", devname);
96         if (write(fd, &h, sizeof(header)) != sizeof(header)) return close_and_fail(fd, EXIT_FILEWRITE, "Failed to write the header!");
97         if (write(fd, datas, h.size) != h.size) return close_and_fail(fd, EXIT_FILEWRITE, "Failed to write datas!");
98         
99         close(fd);
100         return EXIT_SUCCESS;
101 }
102
103 /// @brief Entry point.
104 /// @param[in] argc Number of arguments in @c argv.
105 /// @param[in] argv Arguments array.
106 /// @return Exit code, zero if success, non-zero otherwise.
107 int main(int argc, char** argv)
108 {
109         switch(argc)
110         {
111         case 0:
112         case 1:
113                 fprintf(stderr, "ERROR: too few arguments!\n");
114                 return EXIT_CMDLINE;
115
116         case 2: // Read the device
117                 return read_device(argv[1]);
118
119         case 3: // Write the device
120                 return write_device(argv[1], argv[2]);
121
122         default:
123                 fprintf(stderr, "ERROR: too many arguments!\n");
124                 return EXIT_CMDLINE;
125         }
126 }
127