c-hglib
 All Data Structures Files Functions Variables Typedefs Macros
client.c
Go to the documentation of this file.
1 #define _GNU_SOURCE
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <signal.h>
11 
12 
13 #include "client.h"
14 #include "utils.h"
15 
16 #define HGPATH "hg"
17 
31 int read_header(hg_handle *handle)
32 {
33  uint32_t length;
34  char ch_char;
35 
36  if (!handle) {
37  errno = EINVAL;
38  return -1;
39  }
40 
41  if(read(handle->p_read, &ch_char, 1) < 0){
42  return -1;
43  }
44  if(read(handle->p_read, &length, sizeof(uint32_t)) < 0){
45  return -1;
46  }
47  handle->header.channel = ch_char;
48  handle->header.length = swap_uint32(length);
49 
50  return 0;
51 }
52 
67 int read_hello(hg_handle *handle)
68 {
69  char *buffer;
70  hg_header ch;
71 
72  if (!handle) {
73  errno = EINVAL;
74  return -1;
75  }
76 
77  read_header(handle);
78  ch = handle->header;
79 
80  if(ch.length == 0){
81  return -1;
82  }
83 
84  buffer = malloc(ch.length + 1);
85 
86  if(read(handle->p_read, buffer, ch.length) < 0){
87  free(buffer);
88  return -1;
89  }
90  buffer[ch.length] = '\0';
91 
92  printf("%c%u", ch.channel, ch.length);
93  printf("%s\n", buffer);
94 
95  free(buffer);
96 
97  return 0;
98 }
99 
100 /*
101  * Open the connection with the mercurial command server.
102  * */
103 hg_handle *hg_open(const char *path, char *encoding)
104 {
105  hg_handle *handle = malloc(sizeof(hg_handle));
106  char command[100];
107  int wpipe[2];
108  int rpipe[2];
109  int c_write;
110  int c_read;
111 
112  sprintf(command,
113  "%s serve --cmdserver pipe --config ui.interactive=True",
114  HGPATH);
115 
116  if (path)
117  sprintf(command, "%s -R %s", command, path);
118 
119  if (pipe(wpipe) < 0 || pipe(rpipe) < 0) {
120  return NULL;
121  }
122  handle->p_read = rpipe[0];
123  c_write = rpipe[1];
124  c_read = wpipe[0];
125  handle->p_write = wpipe[1];
126 
127  if ((handle->childpid = fork()) < 0) {
128  return NULL;
129 
130  } else if (handle->childpid == 0) { /* child */
131  close(handle->p_write);
132  close(handle->p_read);
133  if(dup2(c_read, STDIN_FILENO) < 0){
134  return NULL;
135  }
136  close(c_read);
137  if(dup2(c_write, STDOUT_FILENO) < 0){
138  return NULL;
139  }
140  close(c_write);
141  if(execl("/bin/sh", "sh", "-c", command, NULL) < 0){
142  return NULL;
143  }
144 
145  } else { /* parent */
146  close(c_read);
147  close(c_write);
148  }
149 
150  if(read_hello(handle) < 0)
151  return NULL;
152 
153  return handle;
154 }
155 
156 /*
157  * Close the connection for the given handle.
158  * */
159 int hg_close(hg_handle **handle)
160 {
161  if (!(*handle)) {
162  errno = EINVAL;
163  return -1;
164  }
165 
166  if(kill((*handle)->childpid, SIGKILL) < 0){
167  return -1;
168  }
169 
170  close((*handle)->p_read);
171  close((*handle)->p_write);
172 
173  free(*handle);
174  *handle = NULL;
175 
176  return 0;
177 }
178 
195 char *cmd_prepare(char *const command[], size_t *cmd_size)
196 {
197  size_t cmd_length = 0;
198  char *new_cmd;
199  int i;
200 
201  for(i = 0; i < *cmd_size; ++i){
202  if(!command[i]){
203  *cmd_size = i;
204  break;
205  }
206  cmd_length += strlen(command[i]) + 1;
207  }
208 
209  new_cmd = malloc(cmd_length + 1);
210 
211  for(i = 0; i < *cmd_size; ++i){
212  strcpy(new_cmd, command[i]);
213  new_cmd += strlen(command[i]) + 1;
214  }
215  new_cmd -= cmd_length;
216 
217  *cmd_size = cmd_length - 1;
218  return new_cmd;
219 }
220 
221 /*
222  * Sending a command to the mercurial command server, through the given handle.
223  * */
224 int hg_rawcommand(hg_handle *handle, char *const command[], size_t cmd_size)
225 {
226  if (!handle) {
227  errno = EINVAL;
228  return -1;
229  }
230 
231  char runcommand[] = "runcommand\n";
232  char *cmd_send = cmd_prepare(command, &cmd_size);
233  uint32_t big_endian_size = swap_uint32(cmd_size);
234 
235  if(write(handle->p_write, runcommand, strlen(runcommand)) < 0){
236  free(cmd_send);
237  return -1;
238  }
239  if(write(handle->p_write, &big_endian_size, sizeof(uint32_t)) < 0){
240  free(cmd_send);
241  return -1;
242  }
243  if(write(handle->p_write, cmd_send, cmd_size) < 0){
244  free(cmd_send);
245  return -1;
246  }
247  if(read_header(handle) < 0){
248  free(cmd_send);
249  return -1;
250  }
251 
252  free(cmd_send);
253  return 0;
254 }
255 
256 /*
257  * Reading some unparse data from the server.
258  * */
259 int hg_rawread(hg_handle *handle, char *buffer, size_t sizebuff)
260 {
261  int length = handle->header.length;
262  if (!handle) {
263  errno = EINVAL;
264  return -1;
265  }
266 
267  /* If the current channel is not an input channel return 0. */
268  if(!(hg_channel(handle) == 'o' || hg_channel(handle) == 'e'))
269  return 0;
270 
271  length = (length > sizebuff)? sizebuff : length;
272 
273  if(read(handle->p_read, buffer, length) < 0){
274  return -1;
275  }
276 
277  buffer[length] = '\0';
278  handle->header.length -= length;
279 
280  if(!handle->header.length){
281  if(read_header(handle) < 0){
282  return -1;
283  }
284  }
285 
286  return length;
287 }
288 
289 /*
290  * Will write the buffer to the server.
291  * */
292 int hg_rawwrite(hg_handle *handle, const char *buffer, size_t buff_size)
293 {
294  int length = handle->header.length;
295  uint32_t swap_size;
296  if (!handle) {
297  errno = EINVAL;
298  return -1;
299  }
300  length = (length > buff_size)? buff_size : length;
301  swap_size = swap_uint32(length);
302 
303  if(write(handle->p_write, &swap_size, sizeof(uint32_t)) < 0){
304  return -1;
305  }
306  if(write(handle->p_write, buffer, length) < 0){
307  return -1;
308  }
309 
310  if(read_header(handle) < 0){
311  return -1;
312  }
313  return length;
314 }
315 
316 /*
317  * The channel for the next chunk of data.
318  * */
319 char hg_channel(hg_handle *handle)
320 {
321  if (!handle) {
322  errno = EINVAL;
323  return -1;
324  }
325 
326  return handle->header.channel;
327 }
328 
329 /*
330  * The header for the next chunk of data.
331  * */
333 {
334  return handle->header;
335 }
336 
337 /*
338  * The exitcode for the current command.
339  * */
340 int hg_exitcode(hg_handle *handle)
341 {
342  int exitcode;
343 
344  if (!handle) {
345  errno = EINVAL;
346  return -1;
347  }
348 
349  if(read(handle->p_read, &exitcode, sizeof(int)) < 0){
350  return -1;
351  }
352 
353  return swap_uint32(exitcode);
354 }