gencache: Bail out of stabilize if we can not get the allrecord lock
[kai/samba-autobuild/.git] / source3 / lib / util_file.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * SMB parameters and setup
4  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5  *
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "replace.h"
21 #include "lib/util_file.h"
22 #include "lib/util/debug.h"
23 #include "lib/util/samba_util.h"
24 #include "lib/util/sys_rw.h"
25 #include "lib/sys_popen.h"
26 #include "lib/async_req/async_sock.h"
27 #include "lib/util/tevent_unix.h"
28
29 struct file_pload_state {
30         struct tevent_context *ev;
31         size_t maxsize;
32         int fd;
33         uint8_t *buf;
34 };
35
36 static int file_pload_state_destructor(struct file_pload_state *s);
37 static void file_pload_readable(struct tevent_req *subreq);
38
39 struct tevent_req *file_pload_send(TALLOC_CTX *mem_ctx,
40                                    struct tevent_context *ev,
41                                    const char *syscmd, size_t maxsize)
42 {
43         struct tevent_req *req, *subreq;
44         struct file_pload_state *state;
45
46         req = tevent_req_create(mem_ctx, &state, struct file_pload_state);
47         if (req == NULL) {
48                 return NULL;
49         }
50         state->ev = ev;
51         state->maxsize = maxsize;
52
53         state->fd = sys_popen(syscmd);
54         if (state->fd == -1) {
55                 tevent_req_error(req, errno);
56                 return tevent_req_post(req, ev);
57         }
58         talloc_set_destructor(state, file_pload_state_destructor);
59
60         subreq = wait_for_read_send(state, state->ev, state->fd, false);
61         if (tevent_req_nomem(subreq, req)) {
62                 return tevent_req_post(req, ev);
63         }
64         tevent_req_set_callback(subreq, file_pload_readable, req);
65         return req;
66 }
67
68 static int file_pload_state_destructor(struct file_pload_state *s)
69 {
70         if (s->fd != -1) {
71                 sys_pclose(s->fd);
72                 s->fd = -1;
73         }
74         return 0;
75 }
76
77 static void file_pload_readable(struct tevent_req *subreq)
78 {
79         struct tevent_req *req = tevent_req_callback_data(
80                 subreq, struct tevent_req);
81         struct file_pload_state *state = tevent_req_data(
82                 req, struct file_pload_state);
83         uint8_t buf[1024];
84         uint8_t *tmp;
85         ssize_t nread;
86         size_t bufsize;
87         int err;
88         bool ok;
89
90         ok = wait_for_read_recv(subreq, &err);
91         TALLOC_FREE(subreq);
92         if (!ok) {
93                 tevent_req_error(req, err);
94                 return;
95         }
96
97         nread = sys_read(state->fd, buf, sizeof(buf));
98         if (nread == -1) {
99                 tevent_req_error(req, errno);
100                 return;
101         }
102         if (nread == 0) {
103                 tevent_req_done(req);
104                 return;
105         }
106
107         bufsize = talloc_get_size(state->buf);
108
109         if (((bufsize + nread) < bufsize) ||
110             ((bufsize + nread + 1) < bufsize)) {
111                 /* overflow */
112                 tevent_req_error(req, EMSGSIZE);
113                 return;
114         }
115
116         if ((state->maxsize != 0) && ((bufsize + nread) > state->maxsize)) {
117                 tevent_req_error(req, EMSGSIZE);
118                 return;
119         }
120
121         tmp = talloc_realloc(state, state->buf, uint8_t, bufsize + nread + 1);
122         if (tevent_req_nomem(tmp, req)) {
123                 return;
124         }
125         state->buf = tmp;
126
127         memcpy(state->buf + bufsize, buf, nread);
128         state->buf[bufsize+nread] = '\0';
129
130         subreq = wait_for_read_send(state, state->ev, state->fd, false);
131         if (tevent_req_nomem(subreq, req)) {
132                 return;
133         }
134         tevent_req_set_callback(subreq, file_pload_readable, req);
135 }
136
137 int file_pload_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
138                     uint8_t **buf)
139 {
140         struct file_pload_state *state = tevent_req_data(
141                 req, struct file_pload_state);
142         int err;
143
144         if (tevent_req_is_unix_error(req, &err)) {
145                 return err;
146         }
147         *buf = talloc_move(mem_ctx, &state->buf);
148
149         tevent_req_received(req);
150
151         return 0;
152 }
153
154 /**
155  Load from a pipe into memory.
156 **/
157
158 static char *file_pload(const char *syscmd, size_t *size)
159 {
160         int fd, n;
161         char *p;
162         char buf[1024];
163         size_t total;
164
165         fd = sys_popen(syscmd);
166         if (fd == -1) {
167                 return NULL;
168         }
169
170         p = NULL;
171         total = 0;
172
173         while ((n = sys_read(fd, buf, sizeof(buf))) > 0) {
174                 p = talloc_realloc(NULL, p, char, total + n + 1);
175                 if (!p) {
176                         DEBUG(0,("file_pload: failed to expand buffer!\n"));
177                         close(fd);
178                         return NULL;
179                 }
180                 memcpy(p+total, buf, n);
181                 total += n;
182         }
183
184         if (p) {
185                 p[total] = 0;
186         }
187
188         /* FIXME: Perhaps ought to check that the command completed
189          * successfully (returned 0); if not the data may be
190          * truncated. */
191         sys_pclose(fd);
192
193         if (size) {
194                 *size = total;
195         }
196
197         return p;
198 }
199
200
201
202 /**
203  Load a pipe into memory and return an array of pointers to lines in the data
204  must be freed with TALLOC_FREE.
205 **/
206
207 char **file_lines_pload(TALLOC_CTX *mem_ctx, const char *syscmd,
208                         int *numlines)
209 {
210         char *p;
211         size_t size;
212
213         p = file_pload(syscmd, &size);
214         if (!p) {
215                 return NULL;
216         }
217
218         return file_lines_parse(p, size, numlines, mem_ctx);
219 }