pacemaker  1.1.16-94ff4df
Scalable High-Availability cluster resource manager
io.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE
23 #endif
24 
25 #include <sys/param.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <dirent.h>
34 #include <pwd.h>
35 #include <grp.h>
36 
37 #include <crm/crm.h>
38 #include <crm/common/util.h>
39 
48 void
49 crm_build_path(const char *path_c, mode_t mode)
50 {
51  int offset = 1, len = 0;
52  char *path = strdup(path_c);
53 
54  CRM_CHECK(path != NULL, return);
55  for (len = strlen(path); offset < len; offset++) {
56  if (path[offset] == '/') {
57  path[offset] = 0;
58  if (mkdir(path, mode) < 0 && errno != EEXIST) {
59  crm_perror(LOG_ERR, "Could not create directory '%s'", path);
60  break;
61  }
62  path[offset] = '/';
63  }
64  }
65  if (mkdir(path, mode) < 0 && errno != EEXIST) {
66  crm_perror(LOG_ERR, "Could not create directory '%s'", path);
67  }
68 
69  free(path);
70 }
71 
84 char *
85 generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
86 {
87  int len = 40;
88  char *filename = NULL;
89  const char *ext = "raw";
90 
91  CRM_CHECK(directory != NULL, return NULL);
92  CRM_CHECK(series != NULL, return NULL);
93 
94 #if !HAVE_BZLIB_H
95  bzip = FALSE;
96 #endif
97 
98  len += strlen(directory);
99  len += strlen(series);
100  filename = malloc(len);
101  CRM_CHECK(filename != NULL, return NULL);
102 
103  if (bzip) {
104  ext = "bz2";
105  }
106  sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext);
107 
108  return filename;
109 }
110 
120 int
121 get_last_sequence(const char *directory, const char *series)
122 {
123  FILE *file_strm = NULL;
124  int start = 0, length = 0, read_len = 0;
125  char *series_file = NULL;
126  char *buffer = NULL;
127  int seq = 0;
128  int len = 36;
129 
130  CRM_CHECK(directory != NULL, return 0);
131  CRM_CHECK(series != NULL, return 0);
132 
133  len += strlen(directory);
134  len += strlen(series);
135  series_file = malloc(len);
136  CRM_CHECK(series_file != NULL, return 0);
137  sprintf(series_file, "%s/%s.last", directory, series);
138 
139  file_strm = fopen(series_file, "r");
140  if (file_strm == NULL) {
141  crm_debug("Series file %s does not exist", series_file);
142  free(series_file);
143  return 0;
144  }
145 
146  /* see how big the file is */
147  start = ftell(file_strm);
148  fseek(file_strm, 0L, SEEK_END);
149  length = ftell(file_strm);
150  fseek(file_strm, 0L, start);
151 
152  CRM_ASSERT(length >= 0);
153  CRM_ASSERT(start == ftell(file_strm));
154 
155  if (length <= 0) {
156  crm_info("%s was not valid", series_file);
157  free(buffer);
158  buffer = NULL;
159 
160  } else {
161  crm_trace("Reading %d bytes from file", length);
162  buffer = calloc(1, (length + 1));
163  read_len = fread(buffer, 1, length, file_strm);
164  if (read_len != length) {
165  crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len);
166  free(buffer);
167  buffer = NULL;
168  }
169  }
170 
171  seq = crm_parse_int(buffer, "0");
172  fclose(file_strm);
173 
174  crm_trace("Found %d in %s", seq, series_file);
175 
176  free(series_file);
177  free(buffer);
178  return seq;
179 }
180 
192 void
193 write_last_sequence(const char *directory, const char *series, int sequence, int max)
194 {
195  int rc = 0;
196  int len = 36;
197  FILE *file_strm = NULL;
198  char *series_file = NULL;
199 
200  CRM_CHECK(directory != NULL, return);
201  CRM_CHECK(series != NULL, return);
202 
203  if (max == 0) {
204  return;
205  }
206  if (max > 0 && sequence >= max) {
207  sequence = 0;
208  }
209 
210  len += strlen(directory);
211  len += strlen(series);
212  series_file = malloc(len);
213 
214  if (series_file) {
215  sprintf(series_file, "%s/%s.last", directory, series);
216  file_strm = fopen(series_file, "w");
217  }
218 
219  if (file_strm != NULL) {
220  rc = fprintf(file_strm, "%d", sequence);
221  if (rc < 0) {
222  crm_perror(LOG_ERR, "Cannot write to series file %s", series_file);
223  }
224 
225  } else {
226  crm_err("Cannot open series file %s for writing", series_file);
227  }
228 
229  if (file_strm != NULL) {
230  fflush(file_strm);
231  fclose(file_strm);
232  }
233 
234  crm_trace("Wrote %d to %s", sequence, series_file);
235  free(series_file);
236 }
237 
249 int
250 crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
251 {
252  char *series_file = NULL;
253  int rc;
254 
255  CRM_CHECK((directory != NULL) && (series != NULL), errno = EINVAL; return -1);
256 
257  series_file = crm_strdup_printf("%s/%s.last", directory, series);
258  CRM_CHECK(series_file != NULL, return -1);
259 
260  rc = chown(series_file, uid, gid);
261  free(series_file);
262  return rc;
263 }
264 
277 gboolean
278 crm_is_writable(const char *dir, const char *file,
279  const char *user, const char *group, gboolean need_both)
280 {
281  int s_res = -1;
282  struct stat buf;
283  char *full_file = NULL;
284  const char *target = NULL;
285 
286  gboolean pass = TRUE;
287  gboolean readwritable = FALSE;
288 
289  CRM_ASSERT(dir != NULL);
290  if (file != NULL) {
291  full_file = crm_concat(dir, file, '/');
292  target = full_file;
293  s_res = stat(full_file, &buf);
294  if (s_res == 0 && S_ISREG(buf.st_mode) == FALSE) {
295  crm_err("%s must be a regular file", target);
296  pass = FALSE;
297  goto out;
298  }
299  }
300 
301  if (s_res != 0) {
302  target = dir;
303  s_res = stat(dir, &buf);
304  if (s_res != 0) {
305  crm_err("%s must exist and be a directory", dir);
306  pass = FALSE;
307  goto out;
308 
309  } else if (S_ISDIR(buf.st_mode) == FALSE) {
310  crm_err("%s must be a directory", dir);
311  pass = FALSE;
312  }
313  }
314 
315  if (user) {
316  struct passwd *sys_user = NULL;
317 
318  sys_user = getpwnam(user);
319  readwritable = (sys_user != NULL
320  && buf.st_uid == sys_user->pw_uid && (buf.st_mode & (S_IRUSR | S_IWUSR)));
321  if (readwritable == FALSE) {
322  crm_err("%s must be owned and r/w by user %s", target, user);
323  if (need_both) {
324  pass = FALSE;
325  }
326  }
327  }
328 
329  if (group) {
330  struct group *sys_grp = getgrnam(group);
331 
332  readwritable = (sys_grp != NULL
333  && buf.st_gid == sys_grp->gr_gid && (buf.st_mode & (S_IRGRP | S_IWGRP)));
334  if (readwritable == FALSE) {
335  if (need_both || user == NULL) {
336  pass = FALSE;
337  crm_err("%s must be owned and r/w by group %s", target, group);
338  } else {
339  crm_warn("%s should be owned and r/w by group %s", target, group);
340  }
341  }
342  }
343 
344  out:
345  free(full_file);
346  return pass;
347 }
348 
356 void
357 crm_sync_directory(const char *name)
358 {
359  int fd;
360  DIR *directory;
361 
362  directory = opendir(name);
363  if (directory == NULL) {
364  crm_perror(LOG_ERR, "Could not open %s for syncing", name);
365  return;
366  }
367 
368  fd = dirfd(directory);
369  if (fd < 0) {
370  crm_perror(LOG_ERR, "Could not obtain file descriptor for %s", name);
371  return;
372  }
373 
374  if (fsync(fd) < 0) {
375  crm_perror(LOG_ERR, "Could not sync %s", name);
376  }
377  if (closedir(directory) < 0) {
378  crm_perror(LOG_ERR, "Could not close %s after fsync", name);
379  }
380 }
381 
393 char *
394 crm_read_contents(const char *filename)
395 {
396  char *contents = NULL;
397  FILE *fp;
398  int length, read_len;
399 
400  errno = 0; /* enable caller to distinguish error from empty file */
401 
402  fp = fopen(filename, "r");
403  if (fp == NULL) {
404  return NULL;
405  }
406 
407  fseek(fp, 0L, SEEK_END);
408  length = ftell(fp);
409 
410  if (length > 0) {
411  contents = calloc(length + 1, sizeof(char));
412  if (contents == NULL) {
413  fclose(fp);
414  return NULL;
415  }
416 
417  crm_trace("Reading %d bytes from %s", length, filename);
418  rewind(fp);
419  read_len = fread(contents, 1, length, fp); /* Coverity: False positive */
420  if (read_len != length) {
421  free(contents);
422  contents = NULL;
423  }
424  }
425 
426  fclose(fp);
427  return contents;
428 }
429 
439 int
440 crm_write_sync(int fd, const char *contents)
441 {
442  int rc = 0;
443  FILE *fp = fdopen(fd, "w");
444 
445  if (fp == NULL) {
446  return -1;
447  }
448  if ((contents != NULL) && (fprintf(fp, "%s", contents) < 0)) {
449  rc = -1;
450  }
451  if (fflush(fp) != 0) {
452  rc = -1;
453  }
454  if (fsync(fileno(fp)) < 0) {
455  rc = -1;
456  }
457  fclose(fp);
458  return rc;
459 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
A dumping ground.
void write_last_sequence(const char *directory, const char *series, int sequence, int max)
Definition: io.c:193
gboolean crm_is_writable(const char *dir, const char *file, const char *user, const char *group, gboolean need_both)
Definition: io.c:278
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:125
#define crm_warn(fmt, args...)
Definition: logging.h:249
int crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Definition: io.c:250
#define crm_debug(fmt, args...)
Definition: logging.h:253
Utility functions.
void crm_build_path(const char *path_c, mode_t mode)
Create a directory, including any parent directories needed.
Definition: io.c:49
#define crm_trace(fmt, args...)
Definition: logging.h:254
int get_last_sequence(const char *directory, const char *series)
Definition: io.c:121
int crm_write_sync(int fd, const char *contents)
Definition: io.c:440
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define crm_err(fmt, args...)
Definition: logging.h:248
#define CRM_ASSERT(expr)
Definition: error.h:35
void crm_sync_directory(const char *name)
Definition: io.c:357
char * crm_read_contents(const char *filename)
Definition: io.c:394
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define crm_info(fmt, args...)
Definition: logging.h:251
char * generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
Definition: io.c:85