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