This source file includes following definitions.
- pcmk__is_user_in_group
- crm_user_lookup
- pcmk_daemon_user
- version_helper
- compare_version
- crm_parse_interval_spec
- log_assertion_as
- abort_as
- fail_assert_as
- crm_abort
- pcmk__daemonize
- crm_meta_name
- crm_meta_value
- crm_generate_uuid
- crm_gnutls_global_init
- pcmk_hostname
- pcmk_str_is_infinity
- pcmk_str_is_minus_infinity
- pcmk__sleep_ms
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/types.h>
17 #include <sys/wait.h>
18 #include <sys/stat.h>
19 #include <sys/utsname.h>
20
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <limits.h>
26 #include <pwd.h>
27 #include <time.h>
28 #include <libgen.h>
29 #include <signal.h>
30 #include <grp.h>
31
32 #include <qb/qbdefs.h>
33
34 #include <crm/crm.h>
35 #include <crm/services.h>
36 #include <crm/msg_xml.h>
37 #include <crm/cib/internal.h>
38 #include <crm/common/xml.h>
39 #include <crm/common/util.h>
40 #include <crm/common/ipc.h>
41 #include <crm/common/iso8601.h>
42 #include <crm/common/mainloop.h>
43 #include <libxml2/libxml/relaxng.h>
44
45 #include "crmcommon_private.h"
46
47 CRM_TRACE_INIT_DATA(common);
48
49 gboolean crm_config_error = FALSE;
50 gboolean crm_config_warning = FALSE;
51 char *crm_system_name = NULL;
52
53 bool
54 pcmk__is_user_in_group(const char *user, const char *group)
55 {
56 struct group *grent;
57 char **gr_mem;
58
59 if (user == NULL || group == NULL) {
60 return false;
61 }
62
63 setgrent();
64 while ((grent = getgrent()) != NULL) {
65 if (grent->gr_mem == NULL) {
66 continue;
67 }
68
69 if(strcmp(group, grent->gr_name) != 0) {
70 continue;
71 }
72
73 gr_mem = grent->gr_mem;
74 while (*gr_mem != NULL) {
75 if (!strcmp(user, *gr_mem++)) {
76 endgrent();
77 return true;
78 }
79 }
80 }
81 endgrent();
82 return false;
83 }
84
85 int
86 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
87 {
88 int rc = pcmk_ok;
89 char *buffer = NULL;
90 struct passwd pwd;
91 struct passwd *pwentry = NULL;
92
93 buffer = calloc(1, PCMK__PW_BUFFER_LEN);
94 if (buffer == NULL) {
95 return -ENOMEM;
96 }
97
98 rc = getpwnam_r(name, &pwd, buffer, PCMK__PW_BUFFER_LEN, &pwentry);
99 if (pwentry) {
100 if (uid) {
101 *uid = pwentry->pw_uid;
102 }
103 if (gid) {
104 *gid = pwentry->pw_gid;
105 }
106 crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
107
108 } else {
109 rc = rc? -rc : -EINVAL;
110 crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
111 }
112
113 free(buffer);
114 return rc;
115 }
116
117
118
119
120
121
122
123
124
125 int
126 pcmk_daemon_user(uid_t *uid, gid_t *gid)
127 {
128 static uid_t daemon_uid;
129 static gid_t daemon_gid;
130 static bool found = false;
131 int rc = pcmk_ok;
132
133 if (!found) {
134 rc = crm_user_lookup(CRM_DAEMON_USER, &daemon_uid, &daemon_gid);
135 if (rc == pcmk_ok) {
136 found = true;
137 }
138 }
139 if (found) {
140 if (uid) {
141 *uid = daemon_uid;
142 }
143 if (gid) {
144 *gid = daemon_gid;
145 }
146 }
147 return rc;
148 }
149
150
151
152
153
154
155
156
157 static int
158 version_helper(const char *text, const char **end_text)
159 {
160 int atoi_result = -1;
161
162 CRM_ASSERT(end_text != NULL);
163
164 errno = 0;
165
166 if (text != NULL && text[0] != 0) {
167
168
169
170
171
172
173 atoi_result = (int) strtol(text, (char **) end_text, 10);
174
175 if (errno == EINVAL) {
176 crm_err("Conversion of '%s' %c failed", text, text[0]);
177 atoi_result = -1;
178 }
179 }
180 return atoi_result;
181 }
182
183
184
185
186
187
188 int
189 compare_version(const char *version1, const char *version2)
190 {
191 int rc = 0;
192 int lpc = 0;
193 const char *ver1_iter, *ver2_iter;
194
195 if (version1 == NULL && version2 == NULL) {
196 return 0;
197 } else if (version1 == NULL) {
198 return -1;
199 } else if (version2 == NULL) {
200 return 1;
201 }
202
203 ver1_iter = version1;
204 ver2_iter = version2;
205
206 while (1) {
207 int digit1 = 0;
208 int digit2 = 0;
209
210 lpc++;
211
212 if (ver1_iter == ver2_iter) {
213 break;
214 }
215
216 if (ver1_iter != NULL) {
217 digit1 = version_helper(ver1_iter, &ver1_iter);
218 }
219
220 if (ver2_iter != NULL) {
221 digit2 = version_helper(ver2_iter, &ver2_iter);
222 }
223
224 if (digit1 < digit2) {
225 rc = -1;
226 break;
227
228 } else if (digit1 > digit2) {
229 rc = 1;
230 break;
231 }
232
233 if (ver1_iter != NULL && *ver1_iter == '.') {
234 ver1_iter++;
235 }
236 if (ver1_iter != NULL && *ver1_iter == '\0') {
237 ver1_iter = NULL;
238 }
239
240 if (ver2_iter != NULL && *ver2_iter == '.') {
241 ver2_iter++;
242 }
243 if (ver2_iter != NULL && *ver2_iter == 0) {
244 ver2_iter = NULL;
245 }
246 }
247
248 if (rc == 0) {
249 crm_trace("%s == %s (%d)", version1, version2, lpc);
250 } else if (rc < 0) {
251 crm_trace("%s < %s (%d)", version1, version2, lpc);
252 } else if (rc > 0) {
253 crm_trace("%s > %s (%d)", version1, version2, lpc);
254 }
255
256 return rc;
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270 guint
271 crm_parse_interval_spec(const char *input)
272 {
273 long long msec = -1;
274
275 errno = 0;
276 if (input == NULL) {
277 return 0;
278
279 } else if (input[0] == 'P') {
280 crm_time_t *period_s = crm_time_parse_duration(input);
281
282 if (period_s) {
283 msec = 1000 * crm_time_get_seconds(period_s);
284 crm_time_free(period_s);
285 }
286
287 } else {
288 msec = crm_get_msec(input);
289 }
290
291 if (msec < 0) {
292 crm_warn("Using 0 instead of '%s'", input);
293 errno = EINVAL;
294 return 0;
295 }
296 return (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
297 }
298
299
300
301
302
303
304
305
306
307
308 static void
309 log_assertion_as(const char *file, const char *function, int line,
310 const char *assert_condition)
311 {
312 if (!pcmk__is_daemon) {
313 crm_enable_stderr(TRUE);
314 }
315 crm_err("%s: Triggered fatal assertion at %s:%d : %s",
316 function, file, line, assert_condition);
317 }
318
319
320
321
322
323
324
325
326
327
328
329
330
331 static _Noreturn void
332 abort_as(const char *file, const char *function, int line,
333 const char *assert_condition)
334 {
335 log_assertion_as(file, function, line, assert_condition);
336 abort();
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352 static void
353 fail_assert_as(const char *file, const char *function, int line,
354 const char *assert_condition)
355 {
356 int status = 0;
357 pid_t pid = 0;
358
359 if (!pcmk__is_daemon) {
360 abort_as(file, function, line, assert_condition);
361 }
362
363 pid = fork();
364 switch (pid) {
365 case -1:
366 crm_warn("%s: Cannot dump core for non-fatal assertion at %s:%d "
367 ": %s", function, file, line, assert_condition);
368 break;
369
370 case 0:
371 abort();
372 break;
373
374 default:
375 crm_err("%s: Forked child [%d] to record non-fatal assertion at "
376 "%s:%d : %s", function, pid, file, line, assert_condition);
377 crm_write_blackbox(SIGTRAP, NULL);
378 do {
379 if (waitpid(pid, &status, 0) == pid) {
380 return;
381 }
382 } while (errno == EINTR);
383 if (errno == ECHILD) {
384
385 crm_trace("Cannot wait on forked child [%d] "
386 "(SIGCHLD is probably ignored)", pid);
387 } else {
388 crm_err("Cannot wait on forked child [%d]: %s",
389 pid, pcmk_rc_str(errno));
390 }
391 break;
392 }
393 }
394
395
396 void
397 crm_abort(const char *file, const char *function, int line,
398 const char *assert_condition, gboolean do_core, gboolean do_fork)
399 {
400 if (!do_fork) {
401 abort_as(file, function, line, assert_condition);
402 } else if (do_core) {
403 fail_assert_as(file, function, line, assert_condition);
404 } else {
405 log_assertion_as(file, function, line, assert_condition);
406 }
407 }
408
409
410
411
412
413
414
415
416
417
418
419
420 void
421 pcmk__daemonize(const char *name, const char *pidfile)
422 {
423 int rc;
424 pid_t pid;
425
426
427 rc = pcmk__pidfile_matches(pidfile, 1, name, &pid);
428 if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
429 crm_err("%s: already running [pid %lld in %s]",
430 name, (long long) pid, pidfile);
431 printf("%s: already running [pid %lld in %s]\n",
432 name, (long long) pid, pidfile);
433 crm_exit(CRM_EX_ERROR);
434 }
435
436 pid = fork();
437 if (pid < 0) {
438 fprintf(stderr, "%s: could not start daemon\n", name);
439 crm_perror(LOG_ERR, "fork");
440 crm_exit(CRM_EX_OSERR);
441
442 } else if (pid > 0) {
443 crm_exit(CRM_EX_OK);
444 }
445
446 rc = pcmk__lock_pidfile(pidfile, name);
447 if (rc != pcmk_rc_ok) {
448 crm_err("Could not lock '%s' for %s: %s " CRM_XS " rc=%d",
449 pidfile, name, pcmk_rc_str(rc), rc);
450 printf("Could not lock '%s' for %s: %s (%d)\n",
451 pidfile, name, pcmk_rc_str(rc), rc);
452 crm_exit(CRM_EX_ERROR);
453 }
454
455 umask(S_IWGRP | S_IWOTH | S_IROTH);
456
457 close(STDIN_FILENO);
458 pcmk__open_devnull(O_RDONLY);
459
460 close(STDOUT_FILENO);
461 pcmk__open_devnull(O_WRONLY);
462
463 close(STDERR_FILENO);
464 pcmk__open_devnull(O_WRONLY);
465 }
466
467 char *
468 crm_meta_name(const char *field)
469 {
470 int lpc = 0;
471 int max = 0;
472 char *crm_name = NULL;
473
474 CRM_CHECK(field != NULL, return NULL);
475 crm_name = crm_strdup_printf(CRM_META "_%s", field);
476
477
478 max = strlen(crm_name);
479 for (; lpc < max; lpc++) {
480 switch (crm_name[lpc]) {
481 case '-':
482 crm_name[lpc] = '_';
483 break;
484 }
485 }
486 return crm_name;
487 }
488
489 const char *
490 crm_meta_value(GHashTable * hash, const char *field)
491 {
492 char *key = NULL;
493 const char *value = NULL;
494
495 key = crm_meta_name(field);
496 if (key) {
497 value = g_hash_table_lookup(hash, key);
498 free(key);
499 }
500
501 return value;
502 }
503
504 #ifdef HAVE_UUID_UUID_H
505 # include <uuid/uuid.h>
506 #endif
507
508 char *
509 crm_generate_uuid(void)
510 {
511 unsigned char uuid[16];
512 char *buffer = malloc(37);
513
514 CRM_ASSERT(buffer != NULL);
515 uuid_generate(uuid);
516 uuid_unparse(uuid, buffer);
517 return buffer;
518 }
519
520 #ifdef HAVE_GNUTLS_GNUTLS_H
521 void
522 crm_gnutls_global_init(void)
523 {
524 signal(SIGPIPE, SIG_IGN);
525 gnutls_global_init();
526 }
527 #endif
528
529
530
531
532
533
534 char *
535 pcmk_hostname(void)
536 {
537 struct utsname hostinfo;
538
539 return (uname(&hostinfo) < 0)? NULL : strdup(hostinfo.nodename);
540 }
541
542 bool
543 pcmk_str_is_infinity(const char *s) {
544 return pcmk__str_any_of(s, CRM_INFINITY_S, CRM_PLUS_INFINITY_S, NULL);
545 }
546
547 bool
548 pcmk_str_is_minus_infinity(const char *s) {
549 return pcmk__str_eq(s, CRM_MINUS_INFINITY_S, pcmk__str_none);
550 }
551
552
553
554
555
556
557
558
559
560 void
561 pcmk__sleep_ms(unsigned int ms)
562 {
563
564
565
566
567 if (ms >= 1000) {
568 sleep(ms / 1000);
569 ms -= ms / 1000;
570 }
571
572 if (ms == 0) {
573 return;
574 }
575
576 #if defined(HAVE_NANOSLEEP)
577
578 {
579 struct timespec req = { .tv_sec = 0, .tv_nsec = (long) (ms * 1000000) };
580
581 nanosleep(&req, NULL);
582 }
583 #elif defined(HAVE_USLEEP)
584
585 usleep((useconds_t) ms);
586 #else
587
588 {
589 struct timeval tv = { .tv_sec = 0, .tv_usec = (suseconds_t) ms };
590
591 select(0, NULL, NULL, NULL, &tv);
592 }
593 #endif
594 }