This source file includes following definitions.
- pcmk__build_path
- pcmk__real_path
- pcmk__series_filename
- pcmk__read_series_sequence
- pcmk__write_series_sequence
- pcmk__chown_series_sequence
- pcmk__daemon_user_can_write
- pcmk__daemon_group_can_write
- pcmk__daemon_can_write
- pcmk__sync_directory
- pcmk__file_contents
- pcmk__write_sync
- pcmk__set_nonblocking
- pcmk__get_tmpdir
- pcmk__close_fds_in_child
- pcmk__full_path
- crm_build_path
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/resource.h>
20
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <pwd.h>
30 #include <grp.h>
31
32 #include <crm/crm.h>
33 #include <crm/common/util.h>
34
35
36
37
38
39
40
41
42
43
44 int
45 pcmk__build_path(const char *path_c, mode_t mode)
46 {
47 int offset = 1, len = 0;
48 int rc = pcmk_rc_ok;
49 char *path = strdup(path_c);
50
51
52
53 CRM_CHECK(path != NULL, return -ENOMEM);
54 for (len = strlen(path); offset < len; offset++) {
55 if (path[offset] == '/') {
56 path[offset] = 0;
57 if ((mkdir(path, mode) < 0) && (errno != EEXIST)) {
58 rc = errno;
59 goto done;
60 }
61 path[offset] = '/';
62 }
63 }
64 if ((mkdir(path, mode) < 0) && (errno != EEXIST)) {
65 rc = errno;
66 }
67 done:
68 free(path);
69 return rc;
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83
84 int
85 pcmk__real_path(const char *path, char **resolved_path)
86 {
87 CRM_CHECK((path != NULL) && (resolved_path != NULL), return EINVAL);
88
89 #if _POSIX_VERSION >= 200809L
90
91 *resolved_path = realpath(path, NULL);
92 return (*resolved_path == NULL)? errno : pcmk_rc_ok;
93
94 #elif defined(PATH_MAX)
95
96
97 *resolved_path = malloc(PATH_MAX);
98 if ((*resolved_path == NULL) || (realpath(path, *resolved_path) == NULL)) {
99 return errno;
100 }
101 return pcmk_rc_ok;
102 #else
103 *resolved_path = NULL;
104 return ENOTSUP;
105 #endif
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120 char *
121 pcmk__series_filename(const char *directory, const char *series, int sequence,
122 bool bzip)
123 {
124 CRM_ASSERT((directory != NULL) && (series != NULL));
125 return crm_strdup_printf("%s/%s-%d.%s", directory, series, sequence,
126 (bzip? "bz2" : "raw"));
127 }
128
129
130
131
132
133
134
135
136
137
138
139 int
140 pcmk__read_series_sequence(const char *directory, const char *series,
141 unsigned int *seq)
142 {
143 int rc;
144 FILE *fp = NULL;
145 char *series_file = NULL;
146
147 if ((directory == NULL) || (series == NULL) || (seq == NULL)) {
148 return EINVAL;
149 }
150
151 series_file = crm_strdup_printf("%s/%s.last", directory, series);
152 fp = fopen(series_file, "r");
153 if (fp == NULL) {
154 rc = errno;
155 crm_debug("Could not open series file %s: %s",
156 series_file, strerror(rc));
157 free(series_file);
158 return rc;
159 }
160 errno = 0;
161 if (fscanf(fp, "%u", seq) != 1) {
162 rc = (errno == 0)? ENODATA : errno;
163 crm_debug("Could not read sequence number from series file %s: %s",
164 series_file, pcmk_rc_str(rc));
165 fclose(fp);
166 return rc;
167 }
168 fclose(fp);
169 crm_trace("Found last sequence number %u in series file %s",
170 *seq, series_file);
171 free(series_file);
172 return pcmk_rc_ok;
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186 void
187 pcmk__write_series_sequence(const char *directory, const char *series,
188 unsigned int sequence, int max)
189 {
190 int rc = 0;
191 FILE *file_strm = NULL;
192 char *series_file = NULL;
193
194 CRM_CHECK(directory != NULL, return);
195 CRM_CHECK(series != NULL, return);
196
197 if (max == 0) {
198 return;
199 }
200 if (max > 0 && sequence >= max) {
201 sequence = 0;
202 }
203
204 series_file = crm_strdup_printf("%s/%s.last", directory, series);
205 file_strm = fopen(series_file, "w");
206 if (file_strm != NULL) {
207 rc = fprintf(file_strm, "%u", sequence);
208 if (rc < 0) {
209 crm_perror(LOG_ERR, "Cannot write to series file %s", series_file);
210 }
211
212 } else {
213 crm_err("Cannot open series file %s for writing", series_file);
214 }
215
216 if (file_strm != NULL) {
217 fflush(file_strm);
218 fclose(file_strm);
219 }
220
221 crm_trace("Wrote %d to %s", sequence, series_file);
222 free(series_file);
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237 int
238 pcmk__chown_series_sequence(const char *directory, const char *series,
239 uid_t uid, gid_t gid)
240 {
241 char *series_file = NULL;
242 int rc = pcmk_rc_ok;
243
244 if ((directory == NULL) || (series == NULL)) {
245 return EINVAL;
246 }
247 series_file = crm_strdup_printf("%s/%s.last", directory, series);
248 if (chown(series_file, uid, gid) < 0) {
249 rc = errno;
250 }
251 free(series_file);
252 return rc;
253 }
254
255 static bool
256 pcmk__daemon_user_can_write(const char *target_name, struct stat *target_stat)
257 {
258 struct passwd *sys_user = NULL;
259
260 errno = 0;
261 sys_user = getpwnam(CRM_DAEMON_USER);
262 if (sys_user == NULL) {
263 crm_notice("Could not find user %s: %s",
264 CRM_DAEMON_USER, pcmk_rc_str(errno));
265 return FALSE;
266 }
267 if (target_stat->st_uid != sys_user->pw_uid) {
268 crm_notice("%s is not owned by user %s " CRM_XS " uid %d != %d",
269 target_name, CRM_DAEMON_USER, sys_user->pw_uid,
270 target_stat->st_uid);
271 return FALSE;
272 }
273 if ((target_stat->st_mode & (S_IRUSR | S_IWUSR)) == 0) {
274 crm_notice("%s is not readable and writable by user %s "
275 CRM_XS " st_mode=0%lo",
276 target_name, CRM_DAEMON_USER,
277 (unsigned long) target_stat->st_mode);
278 return FALSE;
279 }
280 return TRUE;
281 }
282
283 static bool
284 pcmk__daemon_group_can_write(const char *target_name, struct stat *target_stat)
285 {
286 struct group *sys_grp = NULL;
287
288 errno = 0;
289 sys_grp = getgrnam(CRM_DAEMON_GROUP);
290 if (sys_grp == NULL) {
291 crm_notice("Could not find group %s: %s",
292 CRM_DAEMON_GROUP, pcmk_rc_str(errno));
293 return FALSE;
294 }
295
296 if (target_stat->st_gid != sys_grp->gr_gid) {
297 crm_notice("%s is not owned by group %s " CRM_XS " uid %d != %d",
298 target_name, CRM_DAEMON_GROUP,
299 sys_grp->gr_gid, target_stat->st_gid);
300 return FALSE;
301 }
302
303 if ((target_stat->st_mode & (S_IRGRP | S_IWGRP)) == 0) {
304 crm_notice("%s is not readable and writable by group %s "
305 CRM_XS " st_mode=0%lo",
306 target_name, CRM_DAEMON_GROUP,
307 (unsigned long) target_stat->st_mode);
308 return FALSE;
309 }
310 return TRUE;
311 }
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 bool
328 pcmk__daemon_can_write(const char *dir, const char *file)
329 {
330 int s_res = 0;
331 struct stat buf;
332 char *full_file = NULL;
333 const char *target = NULL;
334
335
336 CRM_ASSERT(dir != NULL);
337
338
339 if (file != NULL) {
340 full_file = crm_strdup_printf("%s/%s", dir, file);
341 target = full_file;
342
343 s_res = stat(full_file, &buf);
344 if (s_res < 0) {
345 crm_notice("%s not found: %s", target, pcmk_rc_str(errno));
346 free(full_file);
347 full_file = NULL;
348 target = NULL;
349
350 } else if (S_ISREG(buf.st_mode) == FALSE) {
351 crm_err("%s must be a regular file " CRM_XS " st_mode=0%lo",
352 target, (unsigned long) buf.st_mode);
353 free(full_file);
354 return false;
355 }
356 }
357
358
359 if (target == NULL) {
360 target = dir;
361 s_res = stat(dir, &buf);
362 if (s_res < 0) {
363 crm_err("%s not found: %s", dir, pcmk_rc_str(errno));
364 return false;
365
366 } else if (S_ISDIR(buf.st_mode) == FALSE) {
367 crm_err("%s must be a directory " CRM_XS " st_mode=0%lo",
368 dir, (unsigned long) buf.st_mode);
369 return false;
370 }
371 }
372
373 if (!pcmk__daemon_user_can_write(target, &buf)
374 && !pcmk__daemon_group_can_write(target, &buf)) {
375
376 crm_err("%s must be owned and writable by either user %s or group %s "
377 CRM_XS " st_mode=0%lo",
378 target, CRM_DAEMON_USER, CRM_DAEMON_GROUP,
379 (unsigned long) buf.st_mode);
380 free(full_file);
381 return false;
382 }
383
384 free(full_file);
385 return true;
386 }
387
388
389
390
391
392
393
394
395 void
396 pcmk__sync_directory(const char *name)
397 {
398 int fd;
399 DIR *directory;
400
401 directory = opendir(name);
402 if (directory == NULL) {
403 crm_perror(LOG_ERR, "Could not open %s for syncing", name);
404 return;
405 }
406
407 fd = dirfd(directory);
408 if (fd < 0) {
409 crm_perror(LOG_ERR, "Could not obtain file descriptor for %s", name);
410 return;
411 }
412
413 if (fsync(fd) < 0) {
414 crm_perror(LOG_ERR, "Could not sync %s", name);
415 }
416 if (closedir(directory) < 0) {
417 crm_perror(LOG_ERR, "Could not close %s after fsync", name);
418 }
419 }
420
421
422
423
424
425
426
427
428
429
430
431 int
432 pcmk__file_contents(const char *filename, char **contents)
433 {
434 FILE *fp;
435 int length, read_len;
436 int rc = pcmk_rc_ok;
437
438 if ((filename == NULL) || (contents == NULL)) {
439 return EINVAL;
440 }
441
442 fp = fopen(filename, "r");
443 if ((fp == NULL) || (fseek(fp, 0L, SEEK_END) < 0)) {
444 rc = errno;
445 goto bail;
446 }
447
448 length = ftell(fp);
449 if (length < 0) {
450 rc = errno;
451 goto bail;
452 }
453
454 if (length == 0) {
455 *contents = NULL;
456 } else {
457 *contents = calloc(length + 1, sizeof(char));
458 if (*contents == NULL) {
459 rc = errno;
460 goto bail;
461 }
462 rewind(fp);
463
464 read_len = fread(*contents, 1, length, fp);
465 if (read_len != length) {
466 free(*contents);
467 *contents = NULL;
468 rc = EIO;
469 } else {
470
471
472
473 (*contents)[length] = '\0';
474 }
475 }
476
477 bail:
478 if (fp != NULL) {
479 fclose(fp);
480 }
481 return rc;
482 }
483
484
485
486
487
488
489
490
491
492
493 int
494 pcmk__write_sync(int fd, const char *contents)
495 {
496 int rc = 0;
497 FILE *fp = fdopen(fd, "w");
498
499 if (fp == NULL) {
500 return errno;
501 }
502 if ((contents != NULL) && (fprintf(fp, "%s", contents) < 0)) {
503 rc = EIO;
504 }
505 if (fflush(fp) != 0) {
506 rc = errno;
507 }
508 if (fsync(fileno(fp)) < 0) {
509 rc = errno;
510 }
511 fclose(fp);
512 return rc;
513 }
514
515
516
517
518
519
520
521
522
523 int
524 pcmk__set_nonblocking(int fd)
525 {
526 int flag = fcntl(fd, F_GETFL);
527
528 if (flag < 0) {
529 return errno;
530 }
531 if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
532 return errno;
533 }
534 return pcmk_rc_ok;
535 }
536
537
538
539
540
541
542
543
544
545
546 const char *
547 pcmk__get_tmpdir(void)
548 {
549 const char *dir = getenv("TMPDIR");
550
551 return (dir && (*dir == '/'))? dir : "/tmp";
552 }
553
554
555
556
557
558
559
560
561
562
563
564 void
565 pcmk__close_fds_in_child(bool all)
566 {
567 DIR *dir;
568 struct rlimit rlim;
569 rlim_t max_fd;
570 int min_fd = (all? 0 : (STDERR_FILENO + 1));
571
572
573
574
575 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
576 max_fd = rlim.rlim_cur - 1;
577 } else {
578 long conf_max = sysconf(_SC_OPEN_MAX);
579
580 max_fd = (conf_max > 0)? conf_max : 1024;
581 }
582
583
584
585
586
587
588 #if HAVE_LINUX_PROCFS
589 dir = opendir("/proc/self/fd");
590 if (dir == NULL) {
591 dir = opendir("/dev/fd");
592 }
593 #else
594 dir = opendir("/dev/fd");
595 #endif
596 if (dir != NULL) {
597 struct dirent *entry;
598 int dir_fd = dirfd(dir);
599
600 while ((entry = readdir(dir)) != NULL) {
601 int lpc = atoi(entry->d_name);
602
603
604
605
606
607
608
609 if ((lpc >= min_fd) && (lpc <= max_fd) && (lpc != dir_fd)) {
610 close(lpc);
611 }
612 }
613 closedir(dir);
614 return;
615 }
616
617
618
619
620 for (int lpc = max_fd; lpc >= min_fd; lpc--) {
621 close(lpc);
622 }
623 }
624
625
626
627
628
629
630
631
632
633 char *
634 pcmk__full_path(const char *filename, const char *dirname)
635 {
636 CRM_ASSERT(filename != NULL);
637
638 if (filename[0] == '/') {
639 return pcmk__str_copy(filename);
640 }
641 CRM_ASSERT(dirname != NULL);
642 return crm_strdup_printf("%s/%s", dirname, filename);
643 }
644
645
646
647
648 #include <crm/common/util_compat.h>
649
650 void
651 crm_build_path(const char *path_c, mode_t mode)
652 {
653 int rc = pcmk__build_path(path_c, mode);
654
655 if (rc != pcmk_rc_ok) {
656 crm_err("Could not create directory '%s': %s",
657 path_c, pcmk_rc_str(rc));
658 }
659 }
660
661
662