* Add utility functions to allocate pointers in variable size chunks.
[rrdtool.git] / src / rrd_utils.c
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  **/
23
24 #include "rrd_tool.h"
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <libgen.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34
35 #ifdef WIN32
36 #       define random() rand()
37 #       define srandom(x) srand(x)
38 #       define getpid() 0
39 #endif /* WIN32 */
40
41 /* make sure that the random number generator seeded EXACTLY ONCE */
42 long rrd_random(void)
43 {
44     static int rand_init = 0;
45     if (!rand_init) {
46         srandom((unsigned int) time(NULL) + (unsigned int) getpid());
47         rand_init++;
48     }
49
50     return random();
51 }
52
53 /* rrd_add_ptr_chunk: add a pointer to a dynamically sized array of
54  * pointers, realloc as necessary in multiples of "chunk".
55  *
56  * "alloc" is the number of pointers allocated
57  * "dest_size" is the number of valid pointers
58  *
59  * returns 1 on success, 0 on failure.
60  */
61
62 int rrd_add_ptr_chunk(void ***dest, size_t *dest_size, void *src,
63                       size_t *alloc, size_t chunk)
64 {
65     void **temp;
66
67     assert(dest != NULL);
68     assert(alloc != NULL);
69     assert(*alloc >= *dest_size);
70
71     if (*alloc == *dest_size)
72     {
73         temp = (void **) rrd_realloc(*dest, (*alloc+chunk) * sizeof(*dest));
74         if (!temp)
75             return 0;
76
77         *dest = temp;
78         *alloc += chunk;
79     }
80
81     (*dest)[*dest_size] = src;
82     (*dest_size)++;
83
84     return 1;
85 }
86
87 /* rrd_add_ptr: add a pointer to a dynamically sized array of pointers,
88  * realloc as necessary.  returns 1 on success, 0 on failure.
89  */
90 int rrd_add_ptr(void ***dest, size_t *dest_size, void *src)
91 {
92     size_t alloc = *dest_size;
93
94     return rrd_add_ptr_chunk(dest, dest_size, src, &alloc, 1);
95 }
96
97 /* like rrd_add_ptr_chunk, but calls strdup() on a string first. */
98 int rrd_add_strdup_chunk(char ***dest, size_t *dest_size, char *src,
99                          size_t *alloc, size_t chunk)
100 {
101     char *dup_src;
102     int add_ok;
103
104     assert(dest != NULL);
105     assert(src  != NULL);
106
107     dup_src = strdup(src);
108     if (!dup_src)
109         return 0;
110
111     add_ok = rrd_add_ptr_chunk((void ***)dest, dest_size, (void *)dup_src, alloc, chunk);
112     if (!add_ok)
113         free(dup_src);
114
115     return add_ok;
116 }
117
118 int rrd_add_strdup(char ***dest, size_t *dest_size, char *src)
119 {
120     size_t alloc = *dest_size;
121
122     return rrd_add_strdup_chunk(dest, dest_size, src, &alloc, 1);
123 }
124
125 void rrd_free_ptrs(void ***src, size_t *cnt)
126 {
127     void **sp;
128
129     assert(src != NULL);
130     sp = *src;
131
132     if (sp == NULL)
133         return;
134
135     while (*cnt > 0) {
136         (*cnt)--;
137         free(sp[*cnt]);
138     }
139
140     free (sp);
141     *src = NULL;
142 }
143
144 /* recursively create the directory named by 'pathname'
145  * (similar to "mkdir -p" on the command line) */
146 int rrd_mkdir_p(const char *pathname, mode_t mode)
147 {
148     struct stat sb;
149
150     char *pathname_copy;
151     char *base_dir;
152
153     if ((NULL == pathname) || ('\0' == *pathname)) {
154         errno = EINVAL;
155         return -1;
156     }
157
158     if (0 == stat(pathname, &sb)) {
159         if (! S_ISDIR(sb.st_mode)) {
160             errno = ENOTDIR;
161             return -1;
162         }
163         return 0;
164     }
165
166     /* keep errno as set by stat() */
167     if (ENOENT != errno)
168         return -1;
169
170     /* dirname might modify its first argument */
171     if (NULL == (pathname_copy = strdup(pathname)))
172         return -1;
173
174     base_dir = dirname(pathname_copy);
175
176     if (0 != rrd_mkdir_p(base_dir, mode)) {
177         int orig_errno = errno;
178         free(pathname_copy);
179         errno = orig_errno;
180         return -1;
181     }
182
183     free(pathname_copy);
184
185     /* keep errno as set by mkdir() */
186     if (0 != mkdir(pathname, mode))
187         return -1;
188     return 0;
189 } /* rrd_mkdir_p */
190