]>
Commit | Line | Data |
---|---|---|
92658f56 PR |
1 | #include <errno.h> |
2 | #include <stdio.h> | |
3 | #include <malloc.h> | |
4 | #include <string.h> | |
4fcbeed6 | 5 | #include "daemon-shared.h" |
92658f56 PR |
6 | |
7 | /* | |
8 | * Read a single message from a (socket) filedescriptor. Messages are delimited | |
9 | * by blank lines. This call will block until all of a message is received. The | |
10 | * memory will be allocated from heap. Upon error, all memory is freed and the | |
11 | * buffer pointer is set to NULL. | |
4fcbeed6 PR |
12 | * |
13 | * See also write_buffer about blocking (read_buffer has identical behaviour). | |
92658f56 PR |
14 | */ |
15 | int read_buffer(int fd, char **buffer) { | |
16 | int bytes = 0; | |
17 | int buffersize = 32; | |
18 | *buffer = malloc(buffersize + 1); | |
19 | ||
20 | while (1) { | |
21 | int result = read(fd, (*buffer) + bytes, buffersize - bytes); | |
22 | if (result > 0) | |
23 | bytes += result; | |
24 | if (result == 0) | |
25 | goto fail; /* we should never encounter EOF here */ | |
26 | if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK) | |
27 | goto fail; | |
28 | ||
29 | if (bytes == buffersize) { | |
30 | buffersize += 1024; | |
31 | char *new = realloc(*buffer, buffersize + 1); | |
32 | if (new) | |
33 | *buffer = new; | |
34 | else | |
35 | goto fail; | |
36 | } else { | |
37 | (*buffer)[bytes] = 0; | |
38 | char *end; | |
39 | if ((end = strstr((*buffer) + bytes - 2, "\n\n"))) { | |
40 | *end = 0; | |
41 | break; /* success, we have the full message now */ | |
42 | } | |
43 | /* TODO call select here if we encountered EAGAIN/EWOULDBLOCK */ | |
44 | } | |
45 | } | |
46 | return 1; | |
47 | fail: | |
48 | free(*buffer); | |
49 | *buffer = NULL; | |
50 | return 0; | |
51 | } | |
52 | ||
53 | /* | |
54 | * Write a buffer to a filedescriptor. Keep trying. Blocks (even on | |
55 | * SOCK_NONBLOCK) until all of the write went through. | |
56 | * | |
57 | * TODO use select on EWOULDBLOCK/EAGAIN to avoid useless spinning | |
58 | */ | |
59 | int write_buffer(int fd, char *buffer, int length) { | |
60 | int written = 0; | |
61 | while (1) { | |
62 | int result = write(fd, buffer + written, length - written); | |
63 | if (result > 0) | |
64 | written += result; | |
65 | if (result < 0 && errno != EWOULDBLOCK && errno != EAGAIN) | |
66 | break; /* too bad */ | |
67 | if (written == length) | |
68 | return 1; /* done */ | |
69 | } | |
70 | return 0; | |
71 | } | |
4fcbeed6 | 72 | |
14e01287 | 73 | char *format_buffer(const char *what, const char *id, va_list ap) |
4fcbeed6 PR |
74 | { |
75 | char *buffer, *old; | |
76 | char *next; | |
77 | char *format; | |
78 | ||
14e01287 | 79 | dm_asprintf(&buffer, "%s = \"%s\"\n", what, id); |
4fcbeed6 PR |
80 | if (!buffer) goto fail; |
81 | ||
82 | while (next = va_arg(ap, char *)) { | |
83 | old = buffer; | |
84 | if (strstr(next, "%d") || strstr(next, "%s")) { | |
85 | dm_asprintf(&format, "%%s%s\n", next); | |
86 | if (!format) goto fail; | |
87 | ||
88 | if (strstr(format, "%d")) | |
89 | dm_asprintf(&buffer, format, buffer, va_arg(ap, int)); | |
90 | else | |
91 | dm_asprintf(&buffer, format, buffer, va_arg(ap, char *)); | |
92 | ||
93 | dm_free(format); | |
94 | dm_free(old); | |
95 | if (!buffer) goto fail; | |
96 | } else { | |
97 | dm_asprintf(&buffer, "%s%s", buffer, next); | |
98 | dm_free(old); | |
99 | if (!buffer) goto fail; | |
100 | } | |
101 | } | |
102 | ||
103 | old = buffer; | |
104 | dm_asprintf(&buffer, "%s\n", buffer); | |
105 | dm_free(old); | |
106 | ||
107 | return buffer; | |
108 | fail: | |
109 | dm_free(buffer); | |
110 | return NULL; | |
111 | } |