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)? pcmk_rc_unknown_format : 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 int
237 pcmk__chown_series_sequence(const char *directory, const char *series,
238 uid_t uid, gid_t gid)
239 {
240 char *series_file = NULL;
241 int rc = pcmk_rc_ok;
242
243 if ((directory == NULL) || (series == NULL)) {
244 return EINVAL;
245 }
246 series_file = crm_strdup_printf("%s/%s.last", directory, series);
247 if (chown(series_file, uid, gid) < 0) {
248 rc = errno;
249 }
250 free(series_file);
251 return rc;
252 }
253
254 static bool
255 pcmk__daemon_user_can_write(const char *target_name, struct stat *target_stat)
256 {
257 struct passwd *sys_user = NULL;
258
259 errno = 0;
260 sys_user = getpwnam(CRM_DAEMON_USER);
261 if (sys_user == NULL) {
262 crm_notice("Could not find user %s: %s",
263 CRM_DAEMON_USER, pcmk_strerror(errno));
264 return FALSE;
265 }
266 if (target_stat->st_uid != sys_user->pw_uid) {
267 crm_notice("%s is not owned by user %s " CRM_XS " uid %d != %d",
268 target_name, CRM_DAEMON_USER, sys_user->pw_uid,
269 target_stat->st_uid);
270 return FALSE;
271 }
272 if ((target_stat->st_mode & (S_IRUSR | S_IWUSR)) == 0) {
273 crm_notice("%s is not readable and writable by user %s "
274 CRM_XS " st_mode=0%lo",
275 target_name, CRM_DAEMON_USER,
276 (unsigned long) target_stat->st_mode);
277 return FALSE;
278 }
279 return TRUE;
280 }
281
282 static bool
283 pcmk__daemon_group_can_write(const char *target_name, struct stat *target_stat)
284 {
285 struct group *sys_grp = NULL;
286
287 errno = 0;
288 sys_grp = getgrnam(CRM_DAEMON_GROUP);
289 if (sys_grp == NULL) {
290 crm_notice("Could not find group %s: %s",
291 CRM_DAEMON_GROUP, pcmk_strerror(errno));
292 return FALSE;
293 }
294
295 if (target_stat->st_gid != sys_grp->gr_gid) {
296 crm_notice("%s is not owned by group %s " CRM_XS " uid %d != %d",
297 target_name, CRM_DAEMON_GROUP,
298 sys_grp->gr_gid, target_stat->st_gid);
299 return FALSE;
300 }
301
302 if ((target_stat->st_mode & (S_IRGRP | S_IWGRP)) == 0) {
303 crm_notice("%s is not readable and writable by group %s "
304 CRM_XS " st_mode=0%lo",
305 target_name, CRM_DAEMON_GROUP,
306 (unsigned long) target_stat->st_mode);
307 return FALSE;
308 }
309 return TRUE;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326 bool
327 pcmk__daemon_can_write(const char *dir, const char *file)
328 {
329 int s_res = 0;
330 struct stat buf;
331 char *full_file = NULL;
332 const char *target = NULL;
333
334
335 CRM_ASSERT(dir != NULL);
336
337
338 if (file != NULL) {
339 full_file = crm_strdup_printf("%s/%s", dir, file);
340 target = full_file;
341
342 s_res = stat(full_file, &buf);
343 if (s_res < 0) {
344 crm_notice("%s not found: %s", target, pcmk_strerror(errno));
345 free(full_file);
346 full_file = NULL;
347 target = NULL;
348
349 } else if (S_ISREG(buf.st_mode) == FALSE) {
350 crm_err("%s must be a regular file " CRM_XS " st_mode=0%lo",
351 target, (unsigned long) buf.st_mode);
352 free(full_file);
353 return false;
354 }
355 }
356
357
358 if (target == NULL) {
359 target = dir;
360 s_res = stat(dir, &buf);
361 if (s_res < 0) {
362 crm_err("%s not found: %s", dir, pcmk_strerror(errno));
363 return false;
364
365 } else if (S_ISDIR(buf.st_mode) == FALSE) {
366 crm_err("%s must be a directory " CRM_XS " st_mode=0%lo",
367 dir, (unsigned long) buf.st_mode);
368 return false;
369 }
370 }
371
372 if (!pcmk__daemon_user_can_write(target, &buf)
373 && !pcmk__daemon_group_can_write(target, &buf)) {
374
375 crm_err("%s must be owned and writable by either user %s or group %s "
376 CRM_XS " st_mode=0%lo",
377 target, CRM_DAEMON_USER, CRM_DAEMON_GROUP,
378 (unsigned long) buf.st_mode);
379 free(full_file);
380 return false;
381 }
382
383 free(full_file);
384 return true;
385 }
386
387
388
389
390
391
392
393
394 void
395 pcmk__sync_directory(const char *name)
396 {
397 int fd;
398 DIR *directory;
399
400 directory = opendir(name);
401 if (directory == NULL) {
402 crm_perror(LOG_ERR, "Could not open %s for syncing", name);
403 return;
404 }
405
406 fd = dirfd(directory);
407 if (fd < 0) {
408 crm_perror(LOG_ERR, "Could not obtain file descriptor for %s", name);
409 return;
410 }
411
412 if (fsync(fd) < 0) {
413 crm_perror(LOG_ERR, "Could not sync %s", name);
414 }
415 if (closedir(directory) < 0) {
416 crm_perror(LOG_ERR, "Could not close %s after fsync", name);
417 }
418 }
419
420
421
422
423
424
425
426
427
428
429
430 int
431 pcmk__file_contents(const char *filename, char **contents)
432 {
433 FILE *fp;
434 int length, read_len;
435 int rc = pcmk_rc_ok;
436
437 if ((filename == NULL) || (contents == NULL)) {
438 return EINVAL;
439 }
440
441 fp = fopen(filename, "r");
442 if ((fp == NULL) || (fseek(fp, 0L, SEEK_END) < 0)) {
443 rc = errno;
444 goto bail;
445 }
446
447 length = ftell(fp);
448 if (length < 0) {
449 rc = errno;
450 goto bail;
451 }
452
453 if (length == 0) {
454 *contents = NULL;
455 } else {
456 *contents = calloc(length + 1, sizeof(char));
457 if (*contents == NULL) {
458 rc = errno;
459 goto bail;
460 }
461 rewind(fp);
462 read_len = fread(*contents, 1, length, fp);
463 if (read_len != length) {
464 free(*contents);
465 *contents = NULL;
466 rc = EIO;
467 }
468 }
469
470 bail:
471 if (fp != NULL) {
472 fclose(fp);
473 }
474 return rc;
475 }
476
477
478
479
480
481
482
483
484
485
486 int
487 pcmk__write_sync(int fd, const char *contents)
488 {
489 int rc = 0;
490 FILE *fp = fdopen(fd, "w");
491
492 if (fp == NULL) {
493 return errno;
494 }
495 if ((contents != NULL) && (fprintf(fp, "%s", contents) < 0)) {
496 rc = EIO;
497 }
498 if (fflush(fp) != 0) {
499 rc = errno;
500 }
501 if (fsync(fileno(fp)) < 0) {
502 rc = errno;
503 }
504 fclose(fp);
505 return rc;
506 }
507
508
509
510
511
512
513
514
515
516 int
517 pcmk__set_nonblocking(int fd)
518 {
519 int flag = fcntl(fd, F_GETFL);
520
521 if (flag < 0) {
522 return errno;
523 }
524 if (fcntl(fd, F_SETFL, flag | O_NONBLOCK) < 0) {
525 return errno;
526 }
527 return pcmk_rc_ok;
528 }
529
530
531
532
533
534
535
536
537
538
539 const char *
540 pcmk__get_tmpdir()
541 {
542 const char *dir = getenv("TMPDIR");
543
544 return (dir && (*dir == '/'))? dir : "/tmp";
545 }
546
547
548
549
550
551
552
553
554
555
556
557 void
558 pcmk__close_fds_in_child(bool all)
559 {
560 DIR *dir;
561 struct rlimit rlim;
562 rlim_t max_fd;
563 int min_fd = (all? 0 : (STDERR_FILENO + 1));
564
565
566
567
568 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
569 max_fd = rlim.rlim_cur - 1;
570 } else {
571 long conf_max = sysconf(_SC_OPEN_MAX);
572
573 max_fd = (conf_max > 0)? conf_max : 1024;
574 }
575
576
577
578
579
580
581 #if SUPPORT_PROCFS
582 dir = opendir("/proc/self/fd");
583 if (dir == NULL) {
584 dir = opendir("/dev/fd");
585 }
586 #else
587 dir = opendir("/dev/fd");
588 #endif
589 if (dir != NULL) {
590 struct dirent *entry;
591 int dir_fd = dirfd(dir);
592
593 while ((entry = readdir(dir)) != NULL) {
594 int lpc = atoi(entry->d_name);
595
596
597
598
599
600
601
602 if ((lpc >= min_fd) && (lpc <= max_fd) && (lpc != dir_fd)) {
603 close(lpc);
604 }
605 }
606 closedir(dir);
607 return;
608 }
609
610
611
612
613 for (int lpc = max_fd; lpc >= min_fd; lpc--) {
614 close(lpc);
615 }
616 }
617
618
619
620
621
622
623
624
625
626 char *
627 pcmk__full_path(const char *filename, const char *dirname)
628 {
629 char *path = NULL;
630
631 CRM_ASSERT(filename != NULL);
632
633 if (filename[0] == '/') {
634 path = strdup(filename);
635 CRM_ASSERT(path != NULL);
636
637 } else {
638 CRM_ASSERT(dirname != NULL);
639 path = crm_strdup_printf("%s/%s", dirname, filename);
640 }
641
642 return path;
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