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