"Fossies" - the Fresh Open Source Software Archive 
Member "darkstat-3.0.721/conv.c" (12 Jan 2022, 9354 Bytes) of package /linux/privat/darkstat-3.0.721.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "conv.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
3.0.719_vs_3.0.721.
1 /* darkstat 3
2 * copyright (c) 2001-2014 Emil Mikulic.
3 *
4 * conv.c: convenience functions.
5 *
6 * Permission to use, copy, modify, and distribute this file for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include "conv.h"
20
21 #include <sys/wait.h>
22 #include <assert.h>
23 #include <ctype.h>
24 #include "err.h"
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <grp.h>
28 #include <limits.h>
29 #include <pwd.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35
36 #define PATH_DEVNULL "/dev/null"
37
38 /* malloc() that exits on failure. */
39 void *
40 xmalloc(const size_t size)
41 {
42 void *ptr = malloc(size);
43
44 if (ptr == NULL)
45 errx(1, "malloc(): out of memory");
46 return (ptr);
47 }
48
49 /* calloc() that exits on failure. */
50 void *
51 xcalloc(const size_t num, const size_t size)
52 {
53 void *ptr = calloc(num, size);
54
55 if (ptr == NULL)
56 errx(1, "calloc(): out of memory");
57 return (ptr);
58 }
59
60 /* realloc() that exits on failure. */
61 void *
62 xrealloc(void *original, const size_t size)
63 {
64 void *ptr = realloc(original, size);
65
66 if (ptr == NULL)
67 errx(1, "realloc(): out of memory");
68 return (ptr);
69 }
70
71 /* strdup() that exits on failure. */
72 char *
73 xstrdup(const char *s)
74 {
75 char *tmp = strdup(s);
76
77 if (tmp == NULL)
78 errx(1, "strdup(): out of memory");
79 return (tmp);
80 }
81
82 /* ---------------------------------------------------------------------------
83 * Split string out of src with range [left:right-1]
84 */
85 char *
86 split_string(const char *src, const size_t left, const size_t right)
87 {
88 char *dest;
89 assert(left <= right);
90 assert(left < strlen(src)); /* [left means must be smaller */
91 assert(right <= strlen(src)); /* right) means can be equal or smaller */
92
93 dest = xmalloc(right - left + 1);
94 memcpy(dest, src+left, right-left);
95 dest[right-left] = '\0';
96 return (dest);
97 }
98
99 /* ---------------------------------------------------------------------------
100 * Uppercasify all characters in a string of given length.
101 */
102 void
103 strntoupper(char *str, const size_t length)
104 {
105 size_t i;
106
107 for (i=0; i<length; i++)
108 str[i] = toupper(str[i]);
109 }
110
111 /* ---------------------------------------------------------------------------
112 * Returns non-zero if haystack starts with needle.
113 */
114 int
115 str_starts_with(const char *haystack, const char *needle)
116 {
117 int i = 0;
118
119 while (needle[i] != '\0') {
120 if ((haystack[i] == '\0') || (haystack[i] != needle[i]))
121 return (0);
122 i++;
123 }
124 return (1);
125 }
126
127 /* split - splits a string by a delimiter character into an array of
128 * string chunks.
129 *
130 * The chunks and the array are dynamically allocated using xmalloc() so
131 * it will errx() if it runs out of memory.
132 *
133 * int num_chunks;
134 * char **chunks = split('.', "..one...two....", &num_chunks);
135 *
136 * num_chunks = 2, chunks = { "one", "two", NULL }
137 */
138 char **
139 split(const char delimiter, const char *str, unsigned int *num_chunks)
140 {
141 unsigned int num = 0;
142 char **chunks = NULL;
143 size_t left, right = 0;
144
145 #define PUSH(c) do { num++; chunks = (char**) xrealloc(chunks, \
146 sizeof(*chunks) * num); chunks[num-1] = c; } while(0)
147
148 for(;;) {
149 /* find first non-delimiter */
150 for (left = right; str[left] == delimiter; left++)
151 ;
152
153 if (str[left] == '\0')
154 break; /* ran out of string */
155
156 /* find first delimiter or end of string */
157 for (right=left+1;
158 str[right] != delimiter && str[right] != '\0';
159 right++)
160 ;
161
162 /* split chunk out */
163 PUSH( split_string(str, left, right) );
164
165 if (str[right] == '\0')
166 break; /* ran out of string */
167 else
168 right++;
169 }
170
171 /* return */
172 PUSH(NULL);
173 if (num_chunks != NULL)
174 *num_chunks = num-1; /* NULL doesn't count */
175 return (chunks);
176 #undef PUSH
177 }
178
179 /* Given an HTTP query string and a key to search for, return the value
180 * associated with it, or NULL if there is no such key or qs is NULL.
181 * The returned string needs to be freed.
182 *
183 * e.g.:
184 * qs = "sort=in&start=20";
185 * qs_get(sq, "sort") returns "in"
186 * qs_get(sq, "end") returns NULL
187 */
188 char *
189 qs_get(const char *qs, const char *key)
190 {
191 size_t pos, qslen, keylen;
192
193 if (qs == NULL) return NULL;
194
195 qslen = strlen(qs);
196 keylen = strlen(key);
197 pos = 0;
198 while (pos < qslen) {
199 if (!(pos + keylen + 1 < qslen))
200 /* not enough room for "key" + "=" */
201 return NULL;
202 else {
203 if (str_starts_with(qs+pos, key) && qs[pos+keylen] == '=') {
204 /* found key= */
205 size_t start, end;
206
207 start = pos + keylen + 1;
208 for (end=start; end<qslen && qs[end] != '&'; end++)
209 ;
210 return split_string(qs, start, end);
211 } else {
212 /* didn't find key, skip to next & */
213 do { pos++; } while ((pos < qslen) && (qs[pos] != '&'));
214 pos++; /* skip the ampersand */
215 }
216 }
217 }
218 return NULL; /* not found */
219 }
220
221 static int lifeline[2] = { -1, -1 };
222 static int fd_null = -1;
223
224 void
225 daemonize_start(void)
226 {
227 pid_t f, w;
228
229 if (pipe(lifeline) == -1)
230 err(1, "pipe(lifeline)");
231
232 fd_null = open(PATH_DEVNULL, O_RDWR, 0);
233 if (fd_null == -1)
234 err(1, "open(" PATH_DEVNULL ")");
235
236 f = fork();
237 if (f == -1)
238 err(1, "fork");
239 else if (f != 0) {
240 /* parent: wait for child */
241 char tmp[1];
242 int status;
243
244 verbosef("parent waiting");
245 if (close(lifeline[1]) == -1)
246 warn("close lifeline in parent");
247 if (read(lifeline[0], tmp, sizeof(tmp)) != 0) /* expecting EOF */
248 err(1, "lifeline read() failed");
249 verbosef("parent done reading, calling waitpid");
250 w = waitpid(f, &status, WNOHANG);
251 verbosef("waitpid ret %d, status is %d", w, status);
252 if (w == -1)
253 err(1, "waitpid");
254 else if (w == 0)
255 /* child is running happily */
256 exit(EXIT_SUCCESS);
257 else
258 /* child init failed, pass on its exit status */
259 exit(WEXITSTATUS(status));
260 }
261 /* else we are the child: continue initializing */
262 }
263
264 void
265 daemonize_finish(void)
266 {
267 if (fd_null == -1)
268 return; /* didn't daemonize_start(), i.e. we're not daemonizing */
269
270 if (setsid() == -1)
271 err(1, "setsid");
272 if (close(lifeline[0]) == -1)
273 warn("close read end of lifeline in child");
274 if (close(lifeline[1]) == -1)
275 warn("couldn't cut the lifeline");
276
277 /* close all our std fds */
278 if (dup2(fd_null, STDIN_FILENO) == -1)
279 warn("dup2(stdin)");
280 if (dup2(fd_null, STDOUT_FILENO) == -1)
281 warn("dup2(stdout)");
282 if (dup2(fd_null, STDERR_FILENO) == -1)
283 warn("dup2(stderr)");
284 if (fd_null > 2)
285 close(fd_null);
286 }
287
288 /*
289 * For security, chroot (optionally) and drop privileges.
290 * Pass a NULL chroot_dir to disable chroot() behaviour.
291 */
292 void privdrop(const char *chroot_dir, const char *privdrop_user) {
293 struct passwd *pw;
294
295 errno = 0;
296 pw = getpwnam(privdrop_user);
297
298 if (pw == NULL) {
299 if (errno == 0)
300 errx(1, "getpwnam(\"%s\") failed: no such user", privdrop_user);
301 else
302 err(1, "getpwnam(\"%s\") failed", privdrop_user);
303 }
304 if (chroot_dir == NULL) {
305 verbosef("no --chroot dir specified, darkstat will not chroot()");
306 } else {
307 /* Read /etc/localtime before we chroot. This works on FreeBSD but not
308 * on Linux / with glibc (as of 2.22) */
309 tzset();
310 if (chroot(chroot_dir) == -1)
311 err(1, "chroot(\"%s\") failed", chroot_dir);
312 if (chdir("/") == -1)
313 err(1, "chdir(\"/\") failed");
314 verbosef("chrooted into: %s", chroot_dir);
315 }
316 {
317 gid_t list[1];
318 list[0] = pw->pw_gid;
319 if (setgroups(1, list) == -1)
320 err(1, "setgroups");
321 }
322 if (setgid(pw->pw_gid) == -1)
323 err(1, "setgid");
324 if (setuid(pw->pw_uid) == -1)
325 err(1, "setuid");
326 verbosef("set uid/gid to %d/%d", (int)pw->pw_uid, (int)pw->pw_gid);
327 }
328
329 /* Make the specified file descriptor non-blocking. */
330 void
331 fd_set_nonblock(const int fd)
332 {
333 int flags;
334
335 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
336 err(1, "fcntl(fd %d) to get flags", fd);
337 flags |= O_NONBLOCK;
338 if (fcntl(fd, F_SETFL, flags) == -1)
339 err(1, "fcntl(fd %d) to set O_NONBLOCK", fd);
340 assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == O_NONBLOCK );
341 }
342
343 /* Make the specified file descriptor blocking. */
344 void
345 fd_set_block(const int fd)
346 {
347 int flags;
348
349 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
350 err(1, "fcntl(fd %d) to get flags", fd);
351 flags &= ~O_NONBLOCK;
352 if (fcntl(fd, F_SETFL, flags) == -1)
353 err(1, "fcntl(fd %d) to unset O_NONBLOCK", fd);
354 assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == 0 );
355 }
356
357 /* vim:set ts=3 sw=3 tw=78 expandtab: */