pacemaker  1.1.18-7fdfbbe
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <fcntl.h>
34 #include <dirent.h>
35 #include <pwd.h>
36 #include <grp.h>
37 
38 #include <crm/crm.h>
39 #include <crm/common/util.h>
40 
49 void
50 crm_build_path(const char *path_c, mode_t mode)
51 {
52  int offset = 1, len = 0;
53  char *path = strdup(path_c);
54 
55  CRM_CHECK(path != NULL, return);
56  for (len = strlen(path); offset < len; offset++) {
57  if (path[offset] == '/') {
58  path[offset] = 0;
59  if (mkdir(path, mode) < 0 && errno != EEXIST) {
60  crm_perror(LOG_ERR, "Could not create directory '%s'", path);
61  break;
62  }
63  path[offset] = '/';
64  }
65  }
66  if (mkdir(path, mode) < 0 && errno != EEXIST) {
67  crm_perror(LOG_ERR, "Could not create directory '%s'", path);
68  }
69 
70  free(path);
71 }
72 
85 char *
86 generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
87 {
88  int len = 40;
89  char *filename = NULL;
90  const char *ext = "raw";
91 
92  CRM_CHECK(directory != NULL, return NULL);
93  CRM_CHECK(series != NULL, return NULL);
94 
95 #if !HAVE_BZLIB_H
96  bzip = FALSE;
97 #endif
98 
99  len += strlen(directory);
100  len += strlen(series);
101  filename = malloc(len);
102  CRM_CHECK(filename != NULL, return NULL);
103 
104  if (bzip) {
105  ext = "bz2";
106  }
107  sprintf(filename, "%s/%s-%d.%s", directory, series, sequence, ext);
108 
109  return filename;
110 }
111 
121 int
122 get_last_sequence(const char *directory, const char *series)
123 {
124  FILE *file_strm = NULL;
125  int start = 0, length = 0, read_len = 0;
126  char *series_file = NULL;
127  char *buffer = NULL;
128  int seq = 0;
129  int len = 36;
130 
131  CRM_CHECK(directory != NULL, return 0);
132  CRM_CHECK(series != NULL, return 0);
133 
134  len += strlen(directory);
135  len += strlen(series);
136  series_file = malloc(len);
137  CRM_CHECK(series_file != NULL, return 0);
138  sprintf(series_file, "%s/%s.last", directory, series);
139 
140  file_strm = fopen(series_file, "r");
141  if (file_strm == NULL) {
142  crm_debug("Series file %s does not exist", series_file);
143  free(series_file);
144  return 0;
145  }
146 
147  /* see how big the file is */
148  start = ftell(file_strm);
149  fseek(file_strm, 0L, SEEK_END);
150  length = ftell(file_strm);
151  fseek(file_strm, 0L, start);
152 
153  CRM_ASSERT(length >= 0);
154  CRM_ASSERT(start == ftell(file_strm));
155 
156  if (length <= 0) {
157  crm_info("%s was not valid", series_file);
158  free(buffer);
159  buffer = NULL;
160 
161  } else {
162  crm_trace("Reading %d bytes from file", length);
163  buffer = calloc(1, (length + 1));
164  read_len = fread(buffer, 1, length, file_strm);
165  if (read_len != length) {
166  crm_err("Calculated and read bytes differ: %d vs. %d", length, read_len);
167  free(buffer);
168  buffer = NULL;
169  }
170  }
171 
172  seq = crm_parse_int(buffer, "0");
173  fclose(file_strm);
174 
175  crm_trace("Found %d in %s", seq, series_file);
176 
177  free(series_file);
178  free(buffer);
179  return seq;
180 }
181 
193 void
194 write_last_sequence(const char *directory, const char *series, int sequence, int max)
195 {
196  int rc = 0;
197  int len = 36;
198  FILE *file_strm = NULL;
199  char *series_file = NULL;
200 
201  CRM_CHECK(directory != NULL, return);
202  CRM_CHECK(series != NULL, return);
203 
204  if (max == 0) {
205  return;
206  }
207  if (max > 0 && sequence >= max) {
208  sequence = 0;
209  }
210 
211  len += strlen(directory);
212  len += strlen(series);
213  series_file = malloc(len);
214 
215  if (series_file) {
216  sprintf(series_file, "%s/%s.last", directory, series);
217  file_strm = fopen(series_file, "w");
218  }
219 
220  if (file_strm != NULL) {
221  rc = fprintf(file_strm, "%d", sequence);
222  if (rc < 0) {
223  crm_perror(LOG_ERR, "Cannot write to series file %s", series_file);
224  }
225 
226  } else {
227  crm_err("Cannot open series file %s for writing", series_file);
228  }
229 
230  if (file_strm != NULL) {
231  fflush(file_strm);
232  fclose(file_strm);
233  }
234 
235  crm_trace("Wrote %d to %s", sequence, series_file);
236  free(series_file);
237 }
238 
250 int
251 crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
252 {
253  char *series_file = NULL;
254  int rc;
255 
256  CRM_CHECK((directory != NULL) && (series != NULL), errno = EINVAL; return -1);
257 
258  series_file = crm_strdup_printf("%s/%s.last", directory, series);
259  CRM_CHECK(series_file != NULL, return -1);
260 
261  rc = chown(series_file, uid, gid);
262  free(series_file);
263  return rc;
264 }
265 
278 gboolean
279 crm_is_writable(const char *dir, const char *file,
280  const char *user, const char *group, gboolean need_both)
281 {
282  int s_res = -1;
283  struct stat buf;
284  char *full_file = NULL;
285  const char *target = NULL;
286 
287  gboolean pass = TRUE;
288  gboolean readwritable = FALSE;
289 
290  CRM_ASSERT(dir != NULL);
291  if (file != NULL) {
292  full_file = crm_concat(dir, file, '/');
293  target = full_file;
294  s_res = stat(full_file, &buf);
295  if (s_res == 0 && S_ISREG(buf.st_mode) == FALSE) {
296  crm_err("%s must be a regular file", target);
297  pass = FALSE;
298  goto out;
299  }
300  }
301 
302  if (s_res != 0) {
303  target = dir;
304  s_res = stat(dir, &buf);
305  if (s_res != 0) {
306  crm_err("%s must exist and be a directory", dir);
307  pass = FALSE;
308  goto out;
309 
310  } else if (S_ISDIR(buf.st_mode) == FALSE) {
311  crm_err("%s must be a directory", dir);
312  pass = FALSE;
313  }
314  }
315 
316  if (user) {
317  struct passwd *sys_user = NULL;
318 
319  sys_user = getpwnam(user);
320  readwritable = (sys_user != NULL
321  && buf.st_uid == sys_user->pw_uid && (buf.st_mode & (S_IRUSR | S_IWUSR)));
322  if (readwritable == FALSE) {
323  crm_err("%s must be owned and r/w by user %s", target, user);
324  if (need_both) {
325  pass = FALSE;
326  }
327  }
328  }
329 
330  if (group) {
331  struct group *sys_grp = getgrnam(group);
332 
333  readwritable = (sys_grp != NULL
334  && buf.st_gid == sys_grp->gr_gid && (buf.st_mode & (S_IRGRP | S_IWGRP)));
335  if (readwritable == FALSE) {
336  if (need_both || user == NULL) {
337  pass = FALSE;
338  crm_err("%s must be owned and r/w by group %s", target, group);
339  } else {
340  crm_warn("%s should be owned and r/w by group %s", target, group);
341  }
342  }
343  }
344 
345  out:
346  free(full_file);
347  return pass;
348 }
349 
357 void
358 crm_sync_directory(const char *name)
359 {
360  int fd;
361  DIR *directory;
362 
363  directory = opendir(name);
364  if (directory == NULL) {
365  crm_perror(LOG_ERR, "Could not open %s for syncing", name);
366  return;
367  }
368 
369  fd = dirfd(directory);
370  if (fd < 0) {
371  crm_perror(LOG_ERR, "Could not obtain file descriptor for %s", name);
372  return;
373  }
374 
375  if (fsync(fd) < 0) {
376  crm_perror(LOG_ERR, "Could not sync %s", name);
377  }
378  if (closedir(directory) < 0) {
379  crm_perror(LOG_ERR, "Could not close %s after fsync", name);
380  }
381 }
382 
394 char *
395 crm_read_contents(const char *filename)
396 {
397  char *contents = NULL;
398  FILE *fp;
399  int length, read_len;
400 
401  errno = 0; /* enable caller to distinguish error from empty file */
402 
403  fp = fopen(filename, "r");
404  if (fp == NULL) {
405  return NULL;
406  }
407 
408  fseek(fp, 0L, SEEK_END);
409  length = ftell(fp);
410 
411  if (length > 0) {
412  contents = calloc(length + 1, sizeof(char));
413  if (contents == NULL) {
414  fclose(fp);
415  return NULL;
416  }
417 
418  crm_trace("Reading %d bytes from %s", length, filename);
419  rewind(fp);
420  read_len = fread(contents, 1, length, fp); /* Coverity: False positive */
421  if (read_len != length) {
422  free(contents);
423  contents = NULL;
424  }
425  }
426 
427  fclose(fp);
428  return contents;
429 }
430 
440 int
441 crm_write_sync(int fd, const char *contents)
442 {
443  int rc = 0;
444  FILE *fp = fdopen(fd, "w");
445 
446  if (fp == NULL) {
447  return -1;
448  }
449  if ((contents != NULL) && (fprintf(fp, "%s", contents) < 0)) {
450  rc = -1;
451  }
452  if (fflush(fp) != 0) {
453  rc = -1;
454  }
455  if (fsync(fileno(fp)) < 0) {
456  rc = -1;
457  }
458  fclose(fp);
459  return rc;
460 }
461 
470 int
472 {
473  int flag = fcntl(fd, F_GETFL);
474 
475  if (flag < 0) {
476  return -errno;
477  }
478  if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
479  return -errno;
480  }
481  return pcmk_ok;
482 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
A dumping ground.
void crm_build_path(const char *path_c, mode_t mode)
Create a directory, including any parent directories needed.
Definition: io.c:50
int get_last_sequence(const char *directory, const char *series)
Definition: io.c:122
#define pcmk_ok
Definition: error.h:42
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:125
char * generate_series_filename(const char *directory, const char *series, int sequence, gboolean bzip)
Definition: io.c:86
char * crm_read_contents(const char *filename)
Definition: io.c:395
#define crm_warn(fmt, args...)
Definition: logging.h:249
#define crm_debug(fmt, args...)
Definition: logging.h:253
Utility functions.
#define crm_trace(fmt, args...)
Definition: logging.h:254
int crm_set_nonblocking(int fd)
Definition: io.c:471
gboolean crm_is_writable(const char *dir, const char *file, const char *user, const char *group, gboolean need_both)
Definition: io.c:279
void write_last_sequence(const char *directory, const char *series, int sequence, int max)
Definition: io.c:194
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define crm_err(fmt, args...)
Definition: logging.h:248
int crm_write_sync(int fd, const char *contents)
Definition: io.c:441
#define CRM_ASSERT(expr)
Definition: error.h:35
int crm_chown_last_sequence(const char *directory, const char *series, uid_t uid, gid_t gid)
Definition: io.c:251
void crm_sync_directory(const char *name)
Definition: io.c:358
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