1 /*
2 * Utiility routines for pmlogrewrite
3 *
4 * Copyright (c) 1997-2000 Silicon Graphics, Inc. All Rights Reserved.
5 * Copyright (c) 2011 Ken McDonell. All Rights Reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "pmapi.h"
23 #include "impl.h"
24 #include "logger.h"
25 #include <assert.h>
26 #include <ctype.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 void
31 yywarn(char *s)
32 {
33 fprintf(stderr, "Warning [%s, line %d]\n%s\n", configfile, lineno, s);
34 }
35
36 void
37 yyerror(char *s)
38 {
39 fprintf(stderr, "Specification error in configuration file (%s)\n",
40 configfile);
41 fprintf(stderr, "[line %d] %s\n", lineno, s);
42 exit(1);
43 }
44
45 void
46 yysemantic(char *s)
47 {
48 fprintf(stderr, "Semantic error in configuration file (%s)\n",
49 configfile);
50 fprintf(stderr, "%s\n", s);
51 exit(1);
52 }
53
54
55 /*
56 * Walk a hash list ... mode is W_START ... W_NEXT ... W_NEXT ...
57 */
58 __pmHashNode *
59 __pmHashWalk(__pmHashCtl *hcp, int mode)
60 {
61 static int hash_idx;
62 static __pmHashNode *next;
63 __pmHashNode *this;
64
65 if (mode == W_START) {
66 hash_idx = 0;
67 next = hcp->hash[0];
68 }
69
70 while (next == NULL) {
71 hash_idx++;
72 if (hash_idx >= hcp->hsize)
73 return NULL;
74 next = hcp->hash[hash_idx];
75 }
76
77 this = next;
78 next = next->next;
79
80 return this;
81 }
82
83 /*
84 * instance name matching ... return
85 * 0 for no match
86 * 1 for match to first space
87 * 2 for complete match
88 * -1 if either name is empty or NULL
89 */
90 int
91 inst_name_eq(const char *p, const char *q)
92 {
93 if (p == NULL || *p == '\0')
94 return -1;
95 if (q == NULL || *q == '\0')
96 return -1;
97
98 for ( ; ; p++, q++) {
99 if (*p == '\0' && *q == '\0')
100 return 2;
101 if (*p == '\0' || *p == ' ') {
102 if (*q == '\0' || *q == ' ')
103 return 1;
104 break;
105 }
106 if (*q == '\0' || *q == ' ') {
107 if (*p == '\0' || *p == ' ')
108 return 1;
109 break;
110 }
111 if (*p != *q)
112 break;
113 }
114 return 0;
115 }
116
117 /*
118 * Rename all the physical archive files with basename of old to
119 * a basename of new.
120 *
121 * If _any_ error occurs, don't make any changes.
122 *
123 * Note: does not handle compressed versions of files.
124 *
125 * TODO - need global locking for PCP 4.0 version if this is promoted
126 * to libpcp
127 */
128 int
129 __pmLogRename(const char *old, const char *new)
130 {
131 int sts;
132 int nfound = 0;
133 char **found = NULL;
134 char *dname;
135 char *obase;
136 char path[MAXPATHLEN+1];
137 char opath[MAXPATHLEN+1];
138 char npath[MAXPATHLEN+1];
139 DIR *dirp;
140 struct dirent *dp;
141
142 strncpy(path, old, sizeof(path));
143 dname = dirname(path);
144
145 if ((dirp = opendir(dname)) == NULL)
146 return -oserror();
147
148 strncpy(path, old, sizeof(path));
149 obase = basename(path);
150
151 for ( ; ; ) {
152 setoserror(0);
153 if ((dp = readdir(dirp)) == NULL)
154 break;
155 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
156 continue;
157 if (strncmp(obase, dp->d_name, strlen(obase)) == 0) {
158 /*
159 * match the base part of the old archive name, now check
160 * for meta or index or a valid volume number
161 */
162 char *p = &dp->d_name[strlen(obase)];
163 int want = 0;
164 if (strcmp(p, ".meta") == 0)
165 want = 1;
166 else if (strcmp(p, ".index") == 0)
167 want = 1;
168 else if (*p == '.' && isdigit(p[1])) {
169 char *endp;
170 long vol;
171 vol = strtol(&p[1], &endp, 10);
172 if (vol >= 0 && *endp == '\0')
173 want = 1;
174 }
175 if (want) {
176 struct stat stbuf;
177 snprintf(opath, sizeof(opath), "%s%s", old, p);
178 snprintf(npath, sizeof(npath), "%s%s", new, p);
179 if (stat(npath, &stbuf) == 0) {
180 fprintf(stderr, "__pmLogRename: destination file %s already exists\n", npath);
181 goto revert;
182 }
183 if (rename(opath, npath) == -1) {
184 fprintf(stderr, "__pmLogRename: rename %s -> %s failed: %s\n", opath, npath, pmErrStr(-oserror()));
185 goto revert;
186 }
187 nfound++;
188 found = (char **)realloc(found, nfound*sizeof(found[0]));
189 if (found == NULL) {
190 __pmNoMem("__pmLogRename: realloc", nfound*sizeof(found[0]), PM_RECOV_ERR);
191 abandon();
192 }
193 if ((found[nfound-1] = strdup(p)) == NULL) {
194 __pmNoMem("__pmLogRename: strdup", strlen(p)+1, PM_RECOV_ERR);
195 abandon();
196 }
197 #ifdef PCP_DEBUG
198 if (pmDebug & DBG_TRACE_LOG)
199 fprintf(stderr, "__pmLogRename: %s -> %s\n", opath, npath);
200 #endif
201 }
202 }
203 }
204
205 if ((sts = oserror()) != 0) {
206 fprintf(stderr, "__pmLogRename: readdir for %s failed: %s\n", dname, pmErrStr(-sts));
207 goto revert;
208 }
209
210 closedir(dirp);
211 sts = 0;
212 goto cleanup;
213
214 revert:
215 while (nfound > 0) {
216 snprintf(opath, sizeof(opath), "%s%s", old, found[nfound-1]);
217 snprintf(npath, sizeof(npath), "%s%s", new, found[nfound-1]);
218 if (rename(npath, opath) == -1) {
219 fprintf(stderr, "__pmLogRename: arrgh trying to revert rename %s -> %s failed: %s\n", npath, opath, pmErrStr(-oserror()));
220 }
221 #ifdef PCP_DEBUG
222 if (pmDebug & DBG_TRACE_LOG)
223 fprintf(stderr, "__pmLogRename: revert %s <- %s\n", opath, npath);
224 #endif
225 nfound--;
226 }
227 sts = PM_ERR_GENERIC;
228
229 cleanup:
230 while (nfound > 0) {
231 free(found[nfound-1]);
232 nfound--;
233 }
234 if (found != NULL)
235 free(found);
236
237 return sts;
238 }
239
240 /*
241 * Remove all the physical archive files with basename of base.
242 *
243 * Note: does not handle compressed versions of files.
244 *
245 * TODO - need global locking for PCP 4.0 version if this is promoted
246 * to libpcp
247 */
248 int
249 __pmLogRemove(const char *name)
250 {
251 int sts;
252 int nfound = 0;
253 char *dname;
254 char *base;
255 char path[MAXPATHLEN+1];
256 DIR *dirp;
257 struct dirent *dp;
258
259 strncpy(path, name, sizeof(path));
260 dname = strdup(dirname(path));
|
Event var_compare_op: |
Comparing "dname" to null implies that "dname" might be null. |
| Also see events: |
[var_deref_model] |
|
At conditional (1): "dname == NULL": Taking true branch.
|
261 if (dname == NULL) {
262 __pmNoMem("__pmLogRemove: dirname strdup", strlen(dirname(path))+1, PM_RECOV_ERR);
263 abandon();
264 }
265
|
Event var_deref_model: |
Passing null variable "dname" to function "opendir", which dereferences it. (The dereference is assumed on the basis of the 'nonnull' parameter attribute.) |
| Also see events: |
[var_compare_op] |
266 if ((dirp = opendir(dname)) == NULL)
267 return -oserror();
268
269 strncpy(path, name, sizeof(path));
270 base = strdup(basename(path));
271 if (base == NULL) {
272 __pmNoMem("__pmLogRemove: basename strdup", strlen(basename(path))+1, PM_RECOV_ERR);
273 abandon();
274 }
275
276 for ( ; ; ) {
277 setoserror(0);
278 if ((dp = readdir(dirp)) == NULL)
279 break;
280 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
281 continue;
282 if (strncmp(base, dp->d_name, strlen(base)) == 0) {
283 /*
284 * match the base part of the old archive name, now check
285 * for meta or index or a valid volume number
286 */
287 char *p = &dp->d_name[strlen(base)];
288 int want = 0;
289 if (strcmp(p, ".meta") == 0)
290 want = 1;
291 else if (strcmp(p, ".index") == 0)
292 want = 1;
293 else if (*p == '.' && isdigit(p[1])) {
294 char *endp;
295 long vol;
296 vol = strtol(&p[1], &endp, 10);
297 if (vol >= 0 && *endp == '\0')
298 want = 1;
299 }
300 if (want) {
301 snprintf(path, sizeof(path), "%s%s", name, p);
302 unlink(path);
303 nfound++;
304 #ifdef PCP_DEBUG
305 if (pmDebug & DBG_TRACE_LOG)
306 fprintf(stderr, "__pmLogRemove: %s\n", path);
307 #endif
308 }
309 }
310 }
311
312 if ((sts = oserror()) != 0) {
313 fprintf(stderr, "__pmLogRemove: readdir for %s failed: %s\n", dname, pmErrStr(-sts));
314 sts = -sts;
315 }
316 else
317 sts = nfound;
318
319 closedir(dirp);
320
321 return sts;
322 }