]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2011-2012 Red Hat, Inc. | |
3 | * | |
4 | * This file is part of LVM2. | |
5 | * | |
6 | * This copyrighted material is made available to anyone wishing to use, | |
7 | * modify, copy, or redistribute it subject to the terms and conditions | |
8 | * of the GNU Lesser General Public License v.2.1. | |
9 | * | |
10 | * You should have received a copy of the GNU Lesser General Public License | |
11 | * along with this program; if not, write to the Free Software Foundation, | |
12 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
13 | */ | |
14 | ||
15 | #include <errno.h> | |
16 | #include <stdio.h> | |
17 | #include <malloc.h> | |
18 | #include <string.h> | |
19 | #include <unistd.h> | |
20 | #include <assert.h> | |
21 | ||
22 | #include "daemon-shared.h" | |
23 | #include "libdevmapper.h" | |
24 | ||
25 | /* | |
26 | * Read a single message from a (socket) filedescriptor. Messages are delimited | |
27 | * by blank lines. This call will block until all of a message is received. The | |
28 | * memory will be allocated from heap. Upon error, all memory is freed and the | |
29 | * buffer pointer is set to NULL. | |
30 | * | |
31 | * See also write_buffer about blocking (read_buffer has identical behaviour). | |
32 | */ | |
33 | int read_buffer(int fd, char **buffer) { | |
34 | int bytes = 0; | |
35 | int buffersize = 32; | |
36 | char *new; | |
37 | *buffer = malloc(buffersize + 1); | |
38 | ||
39 | while (1) { | |
40 | int result = read(fd, (*buffer) + bytes, buffersize - bytes); | |
41 | if (result > 0) | |
42 | bytes += result; | |
43 | if (result == 0) { | |
44 | errno = ECONNRESET; | |
45 | goto fail; /* we should never encounter EOF here */ | |
46 | } | |
47 | if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK) | |
48 | goto fail; | |
49 | ||
50 | if (!strncmp((*buffer) + bytes - 4, "\n##\n", 4)) { | |
51 | *(*buffer + bytes - 4) = 0; | |
52 | break; /* success, we have the full message now */ | |
53 | } | |
54 | ||
55 | if (bytes == buffersize) { | |
56 | buffersize += 1024; | |
57 | if (!(new = realloc(*buffer, buffersize + 1))) | |
58 | goto fail; | |
59 | ||
60 | *buffer = new; | |
61 | } | |
62 | /* TODO call select here if we encountered EAGAIN/EWOULDBLOCK */ | |
63 | } | |
64 | return 1; | |
65 | fail: | |
66 | free(*buffer); | |
67 | *buffer = NULL; | |
68 | return 0; | |
69 | } | |
70 | ||
71 | /* | |
72 | * Write a buffer to a filedescriptor. Keep trying. Blocks (even on | |
73 | * SOCK_NONBLOCK) until all of the write went through. | |
74 | * | |
75 | * TODO use select on EWOULDBLOCK/EAGAIN to avoid useless spinning | |
76 | */ | |
77 | int write_buffer(int fd, const char *buffer, int length) { | |
78 | static const char terminate[] = "\n##\n"; | |
79 | int done = 0; | |
80 | int written = 0; | |
81 | write: | |
82 | while (1) { | |
83 | int result = write(fd, buffer + written, length - written); | |
84 | if (result > 0) | |
85 | written += result; | |
86 | if (result < 0 && errno != EWOULDBLOCK && errno != EAGAIN) | |
87 | return 0; /* too bad */ | |
88 | if (written == length) { | |
89 | if (done) | |
90 | return 1; | |
91 | else | |
92 | break; /* done */ | |
93 | } | |
94 | } | |
95 | ||
96 | buffer = terminate; | |
97 | length = 4; | |
98 | written = 0; | |
99 | done = 1; | |
100 | goto write; | |
101 | } | |
102 | ||
103 | char *format_buffer(const char *what, const char *id, va_list ap) | |
104 | { | |
105 | char *buffer, *old; | |
106 | char *next; | |
107 | int keylen; | |
108 | ||
109 | dm_asprintf(&buffer, "%s = \"%s\"\n", what, id); | |
110 | if (!buffer) goto fail; | |
111 | ||
112 | while ((next = va_arg(ap, char *))) { | |
113 | old = buffer; | |
114 | assert(strchr(next, '=')); | |
115 | keylen = strchr(next, '=') - next; | |
116 | if (strstr(next, "%d")) { | |
117 | int value = va_arg(ap, int); | |
118 | dm_asprintf(&buffer, "%s%.*s= %d\n", buffer, keylen, next, value); | |
119 | dm_free(old); | |
120 | } else if (strstr(next, "%s")) { | |
121 | char *value = va_arg(ap, char *); | |
122 | dm_asprintf(&buffer, "%s%.*s= \"%s\"\n", buffer, keylen, next, value); | |
123 | dm_free(old); | |
124 | } else if (strstr(next, "%b")) { | |
125 | char *block = va_arg(ap, char *); | |
126 | if (!block) | |
127 | continue; | |
128 | dm_asprintf(&buffer, "%s%.*s%s", buffer, keylen, next, block); | |
129 | dm_free(old); | |
130 | } else { | |
131 | dm_asprintf(&buffer, "%s%s", buffer, next); | |
132 | dm_free(old); | |
133 | } | |
134 | if (!buffer) goto fail; | |
135 | } | |
136 | ||
137 | return buffer; | |
138 | fail: | |
139 | dm_free(buffer); | |
140 | return NULL; | |
141 | } |