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