1 /**
2 * RRDtool - src/rrd_utils.c
3 * Copyright (C) 2009 Kevin Brintnall
4 * Copyright (C) 2008 Sebastian Harl
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Authors:
20 * kevin brintnall <kbrint@rufus.net>
21 * Sebastian Harl <sh@tokkee.org>
22 **/
24 #include "rrd_tool.h"
26 #include <assert.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #ifndef _MSC_VER
33 #include <libgen.h>
34 #include <unistd.h>
35 #endif
36 #ifdef WIN32
37 # define random() rand()
38 # define srandom(x) srand(x)
39 # define getpid() 0
40 #endif /* WIN32 */
42 #ifndef S_ISDIR
43 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
44 #endif
46 /* make sure that the random number generator seeded EXACTLY ONCE */
47 long rrd_random(void)
48 {
49 static int rand_init = 0;
50 if (!rand_init) {
51 srandom((unsigned int) time(NULL) + (unsigned int) getpid());
52 rand_init++;
53 }
55 return random();
56 }
58 /* rrd_add_ptr_chunk: add a pointer to a dynamically sized array of
59 * pointers, realloc as necessary in multiples of "chunk".
60 *
61 * "alloc" is the number of pointers allocated
62 * "dest_size" is the number of valid pointers
63 *
64 * returns 1 on success, 0 on failure.
65 */
67 int rrd_add_ptr_chunk(void ***dest, size_t *dest_size, void *src,
68 size_t *alloc, size_t chunk)
69 {
70 void **temp;
72 assert(dest != NULL);
73 assert(alloc != NULL);
74 assert(*alloc >= *dest_size);
76 if (*alloc == *dest_size)
77 {
78 temp = (void **) rrd_realloc(*dest, (*alloc+chunk) * sizeof(*dest));
79 if (!temp)
80 return 0;
82 *dest = temp;
83 *alloc += chunk;
84 }
86 (*dest)[*dest_size] = src;
87 (*dest_size)++;
89 return 1;
90 }
92 /* rrd_add_ptr: add a pointer to a dynamically sized array of pointers,
93 * realloc as necessary. returns 1 on success, 0 on failure.
94 */
95 int rrd_add_ptr(void ***dest, size_t *dest_size, void *src)
96 {
97 size_t alloc = *dest_size;
99 return rrd_add_ptr_chunk(dest, dest_size, src, &alloc, 1);
100 }
102 /* like rrd_add_ptr_chunk, but calls strdup() on a string first. */
103 int rrd_add_strdup_chunk(char ***dest, size_t *dest_size, char *src,
104 size_t *alloc, size_t chunk)
105 {
106 char *dup_src;
107 int add_ok;
109 assert(dest != NULL);
110 assert(src != NULL);
112 dup_src = strdup(src);
113 if (!dup_src)
114 return 0;
116 add_ok = rrd_add_ptr_chunk((void ***)dest, dest_size, (void *)dup_src, alloc, chunk);
117 if (!add_ok)
118 free(dup_src);
120 return add_ok;
121 }
123 int rrd_add_strdup(char ***dest, size_t *dest_size, char *src)
124 {
125 size_t alloc = *dest_size;
127 return rrd_add_strdup_chunk(dest, dest_size, src, &alloc, 1);
128 }
130 void rrd_free_ptrs(void ***src, size_t *cnt)
131 {
132 void **sp;
134 assert(src != NULL);
135 sp = *src;
137 if (sp == NULL)
138 return;
140 while (*cnt > 0) {
141 (*cnt)--;
142 free(sp[*cnt]);
143 }
145 free (sp);
146 *src = NULL;
147 }
149 /* recursively create the directory named by 'pathname'
150 * (similar to "mkdir -p" on the command line) */
151 int rrd_mkdir_p(const char *pathname, mode_t mode)
152 {
153 struct stat sb;
155 char *pathname_copy;
156 char *base_dir;
158 if ((NULL == pathname) || ('\0' == *pathname)) {
159 errno = EINVAL;
160 return -1;
161 }
163 if (0 == stat(pathname, &sb)) {
164 if (! S_ISDIR(sb.st_mode)) {
165 errno = ENOTDIR;
166 return -1;
167 }
168 return 0;
169 }
171 /* keep errno as set by stat() */
172 if (ENOENT != errno)
173 return -1;
175 /* dirname might modify its first argument */
176 if (NULL == (pathname_copy = strdup(pathname)))
177 return -1;
179 #ifndef _MSC_VER
180 base_dir = dirname(pathname_copy);
181 #else
182 _splitpath(pathname_copy, NULL, base_dir, NULL, NULL);
183 #endif
185 if (0 != rrd_mkdir_p(base_dir, mode)) {
186 int orig_errno = errno;
187 free(pathname_copy);
188 errno = orig_errno;
189 return -1;
190 }
192 free(pathname_copy);
194 /* keep errno as set by mkdir() */
195 #ifdef _MSC_VER
196 if (0 != mkdir(pathname))
197 return -1;
198 #else
199 if (0 != mkdir(pathname, mode))
200 return -1;
201 #endif
202 return 0;
203 } /* rrd_mkdir_p */