cmd_read.c (4854B)
1 #include <errno.h> 2 #include <unistd.h> 3 #include <sys/select.h> 4 #include <stdlib.h> 5 #include <assert.h> 6 7 #include <skalibs/types.h> 8 #include <skalibs/strerr.h> 9 #include <skalibs/djbunix.h> 10 #include <skalibs/exec.h> 11 #include <skalibs/netstring.h> 12 #include <skalibs/stralloc.h> 13 #include <skalibs/env.h> 14 15 #include "common.h" 16 #include "netstring.h" 17 #include "header.h" 18 #include "fd_util.h" 19 20 #define USAGE "miniroon-read directory" 21 #define PROG "miniroon-read" 22 23 #define input_fd 0 24 25 #include "die_impl.h" 26 27 size_t read_payload_size(int fd) { 28 char read_char; 29 size_t payload_size = 0; 30 31 fd_block(fd); 32 33 while(payload_size < MAX_MINIROON_SIZE) { 34 switch(read(fd, &read_char, 1)) { 35 case 0: 36 strerr_dief1x(111, "EOF before netstring size was read"); 37 break; 38 case 1: 39 if(read_char == ':') { 40 return payload_size; 41 } else if(read_char >= '0' && read_char <= '9') { 42 payload_size *= 10; 43 payload_size += read_char - '0'; 44 } else { 45 strerr_dief1x(111, "Malformed netstring on input"); 46 } 47 break; 48 case -1: 49 if(errno != EINTR) { 50 strerr_dief1sys(111, "read() length"); 51 } 52 break; 53 default: 54 strerr_dief1x(110, "Unexpected return value from read()"); 55 break; 56 } 57 } 58 59 strerr_dief1x(111, "Input netstring too big"); 60 } 61 62 void read_payload(const bytebuffer bb) { 63 char *read_next = bb.data; 64 ssize_t read_size; 65 while(read_next - bb.data < bb.len) { 66 read_size = read(input_fd, read_next, bb.len - (read_next - bb.data)); 67 if(read_size == 0) { 68 strerr_dief1x(111, "EOF before full netstring payload was read"); 69 } 70 if(read_size == -1) { 71 if(errno != EINTR) { 72 strerr_dief1sys(111, "read() payload"); 73 } 74 continue; 75 } 76 read_next += read_size; 77 } 78 if(bb.data[bb.len - 1] != ',') { 79 strerr_dief1x(111, "Invalid netstring terminator"); 80 } 81 } 82 83 void process_header(miniroon_header *header, const bytebuffer source) { 84 die_on_error(parse_header(header, source)); 85 86 char id[header->id.len + 1]; 87 for(size_t i=0; i<header->id.len; i++) { 88 id[i] = header->id.data[i]; 89 if(id[i] == '-') { continue; } 90 if(id[i] >= '0' && id[i] <= '9') { continue; } 91 if(id[i] >= 'a' && id[i] <= 'z') { continue; } 92 strerr_dief1x(111, "Invalid character in miniroon ID"); 93 } 94 id[header->id.len] = 0; 95 96 if (chdir(id) != 0) { 97 strerr_dief1sys(111, "chdir(id)"); 98 } 99 } 100 101 void exec_verify_and_write_payload (const bytebuffer payload); 102 void process_payload(const bytebuffer payload) { 103 miniroon_header header; 104 netstring_chunk c; 105 netstring_chunk_init(&c, payload); 106 107 if(!netstring_chunk_next(&c)) { 108 strerr_dief1x(111, "Mising miniroon header"); 109 } 110 process_header(&header, c.inner); 111 exec_verify_and_write_payload(payload); 112 } 113 114 void exec_verify_and_write_payload (const bytebuffer payload) { 115 pid_t pid1=0, pid2=0; 116 int wstat ; 117 int p[2] ; 118 119 if(pipe(p) == -1) { 120 strerr_diefu1sys(111, "create pipe"); 121 } 122 123 pid1 = fork(); 124 switch(pid1) { 125 case -1: 126 strerr_diefu1sys(111, "first fork()"); 127 break; 128 case 0: /* child */ 129 fd_close(p[0]); 130 pid2 = fork(); 131 switch(pid2) { 132 case -1: 133 strerr_diefu1sys(111, "second fork()"); 134 break; 135 case 0: /* child */ 136 ssize_t payload_write = fd_write(p[1], payload.data, payload.len); 137 if(payload_write < 0 ) { 138 strerr_dief1sys(111, "write(payload)"); 139 } 140 if(payload_write != payload.len) { 141 strerr_dief1x(111, "could not write whole payload"); 142 } 143 exit(0); 144 break; 145 default: /* parent */ 146 exit(0); 147 break; 148 } 149 break; 150 default: /* parent */ 151 waitpid_nointr(pid1, &wstat, 0); 152 if(!WIFEXITED(wstat) || WEXITSTATUS(wstat) != 0) { 153 strerr_dief1x(111, "child terminated abnormally"); 154 } 155 156 char cmd[] = "./verify"; 157 char fmt_fd[UINT64_FMT], fmt_len[UINT64_FMT]; 158 fmt_fd[uint64_fmt(fmt_fd, (uint64_t)p[0])] = 0; 159 fmt_len[uint64_fmt(fmt_len, (uint64_t)payload.len)] = 0; 160 const char *cmd_argv[4] = {cmd, fmt_fd, fmt_len, 0}; 161 162 fd_close(p[1]); 163 xexec(cmd_argv); 164 break; 165 } 166 } 167 168 int main (int argc, char const *const *argv) 169 { 170 171 if (argc != 2) { 172 strerr_dieusage(100, USAGE); 173 } 174 175 if (chdir(argv[1]) != 0) { 176 strerr_dief1sys(111, "chdir()"); 177 } 178 size_t payload_size = read_payload_size(input_fd); 179 char payload_data[payload_size + 1]; 180 bytebuffer payload = {payload_data, payload_size + 1}; 181 read_payload(payload); 182 payload.len -= 1; /* strip final netstring terminator */ 183 dbg_print_bb1("Got payload", payload); 184 process_payload(payload); 185 assert(0); 186 strerr_dief1x(110, "Internal logic error, should not get here"); 187 return 110; 188 } 189 190 /* vim: sts=2 sw=2 et 191 */