This source file includes following definitions.
- pcmk__is_user_in_group
- crm_user_lookup
- pcmk_daemon_user
- version_helper
- compare_version
- pcmk__daemonize
- crm_generate_uuid
- crm_gnutls_global_init
- pcmk_str_is_infinity
- pcmk_str_is_minus_infinity
- pcmk__sleep_ms
- crm_parse_interval_spec
- pcmk_hostname
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/stat.h>
17 #include <sys/utsname.h>
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include <pwd.h>
25 #include <time.h>
26 #include <libgen.h>
27 #include <signal.h>
28 #include <grp.h>
29
30 #include <qb/qbdefs.h>
31
32 #include <crm/crm.h>
33 #include <crm/services.h>
34 #include <crm/cib/internal.h>
35 #include <crm/common/xml.h>
36 #include <crm/common/util.h>
37 #include <crm/common/ipc.h>
38 #include <crm/common/iso8601.h>
39 #include <crm/common/mainloop.h>
40 #include <libxml2/libxml/relaxng.h>
41
42 #include "crmcommon_private.h"
43
44 CRM_TRACE_INIT_DATA(common);
45
46 gboolean crm_config_error = FALSE;
47 gboolean crm_config_warning = FALSE;
48 char *crm_system_name = NULL;
49
50 bool
51 pcmk__is_user_in_group(const char *user, const char *group)
52 {
53 struct group *grent;
54 char **gr_mem;
55
56 if (user == NULL || group == NULL) {
57 return false;
58 }
59
60 setgrent();
61 while ((grent = getgrent()) != NULL) {
62 if (grent->gr_mem == NULL) {
63 continue;
64 }
65
66 if(strcmp(group, grent->gr_name) != 0) {
67 continue;
68 }
69
70 gr_mem = grent->gr_mem;
71 while (*gr_mem != NULL) {
72 if (!strcmp(user, *gr_mem++)) {
73 endgrent();
74 return true;
75 }
76 }
77 }
78 endgrent();
79 return false;
80 }
81
82 int
83 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
84 {
85 int rc = pcmk_ok;
86 char *buffer = NULL;
87 struct passwd pwd;
88 struct passwd *pwentry = NULL;
89
90 buffer = calloc(1, PCMK__PW_BUFFER_LEN);
91 if (buffer == NULL) {
92 return -ENOMEM;
93 }
94
95 rc = getpwnam_r(name, &pwd, buffer, PCMK__PW_BUFFER_LEN, &pwentry);
96 if (pwentry) {
97 if (uid) {
98 *uid = pwentry->pw_uid;
99 }
100 if (gid) {
101 *gid = pwentry->pw_gid;
102 }
103 crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
104
105 } else {
106 rc = rc? -rc : -EINVAL;
107 crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
108 }
109
110 free(buffer);
111 return rc;
112 }
113
114
115
116
117
118
119
120
121
122 int
123 pcmk_daemon_user(uid_t *uid, gid_t *gid)
124 {
125 static uid_t daemon_uid;
126 static gid_t daemon_gid;
127 static bool found = false;
128 int rc = pcmk_ok;
129
130 if (!found) {
131 rc = crm_user_lookup(CRM_DAEMON_USER, &daemon_uid, &daemon_gid);
132 if (rc == pcmk_ok) {
133 found = true;
134 }
135 }
136 if (found) {
137 if (uid) {
138 *uid = daemon_uid;
139 }
140 if (gid) {
141 *gid = daemon_gid;
142 }
143 }
144 return rc;
145 }
146
147
148
149
150
151
152
153
154 static int
155 version_helper(const char *text, const char **end_text)
156 {
157 int atoi_result = -1;
158
159 pcmk__assert(end_text != NULL);
160
161 errno = 0;
162
163 if (text != NULL && text[0] != 0) {
164
165
166
167
168
169
170 atoi_result = (int) strtol(text, (char **) end_text, 10);
171
172 if (errno == EINVAL) {
173 crm_err("Conversion of '%s' %c failed", text, text[0]);
174 atoi_result = -1;
175 }
176 }
177 return atoi_result;
178 }
179
180
181
182
183
184
185 int
186 compare_version(const char *version1, const char *version2)
187 {
188 int rc = 0;
189 int lpc = 0;
190 const char *ver1_iter, *ver2_iter;
191
192 if (version1 == NULL && version2 == NULL) {
193 return 0;
194 } else if (version1 == NULL) {
195 return -1;
196 } else if (version2 == NULL) {
197 return 1;
198 }
199
200 ver1_iter = version1;
201 ver2_iter = version2;
202
203 while (1) {
204 int digit1 = 0;
205 int digit2 = 0;
206
207 lpc++;
208
209 if (ver1_iter == ver2_iter) {
210 break;
211 }
212
213 if (ver1_iter != NULL) {
214 digit1 = version_helper(ver1_iter, &ver1_iter);
215 }
216
217 if (ver2_iter != NULL) {
218 digit2 = version_helper(ver2_iter, &ver2_iter);
219 }
220
221 if (digit1 < digit2) {
222 rc = -1;
223 break;
224
225 } else if (digit1 > digit2) {
226 rc = 1;
227 break;
228 }
229
230 if (ver1_iter != NULL && *ver1_iter == '.') {
231 ver1_iter++;
232 }
233 if (ver1_iter != NULL && *ver1_iter == '\0') {
234 ver1_iter = NULL;
235 }
236
237 if (ver2_iter != NULL && *ver2_iter == '.') {
238 ver2_iter++;
239 }
240 if (ver2_iter != NULL && *ver2_iter == 0) {
241 ver2_iter = NULL;
242 }
243 }
244
245 if (rc == 0) {
246 crm_trace("%s == %s (%d)", version1, version2, lpc);
247 } else if (rc < 0) {
248 crm_trace("%s < %s (%d)", version1, version2, lpc);
249 } else if (rc > 0) {
250 crm_trace("%s > %s (%d)", version1, version2, lpc);
251 }
252
253 return rc;
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267 void
268 pcmk__daemonize(const char *name, const char *pidfile)
269 {
270 int rc;
271 pid_t pid;
272
273
274 rc = pcmk__pidfile_matches(pidfile, 1, name, &pid);
275 if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
276 crm_err("%s: already running [pid %lld in %s]",
277 name, (long long) pid, pidfile);
278 printf("%s: already running [pid %lld in %s]\n",
279 name, (long long) pid, pidfile);
280 crm_exit(CRM_EX_ERROR);
281 }
282
283 pid = fork();
284 if (pid < 0) {
285 fprintf(stderr, "%s: could not start daemon\n", name);
286 crm_perror(LOG_ERR, "fork");
287 crm_exit(CRM_EX_OSERR);
288
289 } else if (pid > 0) {
290 crm_exit(CRM_EX_OK);
291 }
292
293 rc = pcmk__lock_pidfile(pidfile, name);
294 if (rc != pcmk_rc_ok) {
295 crm_err("Could not lock '%s' for %s: %s " CRM_XS " rc=%d",
296 pidfile, name, pcmk_rc_str(rc), rc);
297 printf("Could not lock '%s' for %s: %s (%d)\n",
298 pidfile, name, pcmk_rc_str(rc), rc);
299 crm_exit(CRM_EX_ERROR);
300 }
301
302 umask(S_IWGRP | S_IWOTH | S_IROTH);
303
304 close(STDIN_FILENO);
305 pcmk__open_devnull(O_RDONLY);
306
307 close(STDOUT_FILENO);
308 pcmk__open_devnull(O_WRONLY);
309
310 close(STDERR_FILENO);
311 pcmk__open_devnull(O_WRONLY);
312 }
313
314 #ifdef HAVE_UUID_UUID_H
315 # include <uuid/uuid.h>
316 #endif
317
318 char *
319 crm_generate_uuid(void)
320 {
321 unsigned char uuid[16];
322 char *buffer = malloc(37);
323
324 pcmk__mem_assert(buffer);
325 uuid_generate(uuid);
326 uuid_unparse(uuid, buffer);
327 return buffer;
328 }
329
330 #ifdef HAVE_GNUTLS_GNUTLS_H
331 void
332 crm_gnutls_global_init(void)
333 {
334 signal(SIGPIPE, SIG_IGN);
335 gnutls_global_init();
336 }
337 #endif
338
339 bool
340 pcmk_str_is_infinity(const char *s) {
341 return pcmk__str_any_of(s, PCMK_VALUE_INFINITY, PCMK_VALUE_PLUS_INFINITY,
342 NULL);
343 }
344
345 bool
346 pcmk_str_is_minus_infinity(const char *s) {
347 return pcmk__str_eq(s, PCMK_VALUE_MINUS_INFINITY, pcmk__str_none);
348 }
349
350
351
352
353
354
355
356
357
358 void
359 pcmk__sleep_ms(unsigned int ms)
360 {
361
362
363
364
365 if (ms >= 1000) {
366 sleep(ms / 1000);
367 ms -= ms / 1000;
368 }
369
370 if (ms == 0) {
371 return;
372 }
373
374 #if defined(HAVE_NANOSLEEP)
375
376 {
377 struct timespec req = { .tv_sec = 0, .tv_nsec = (long) (ms * 1000000) };
378
379 nanosleep(&req, NULL);
380 }
381 #elif defined(HAVE_USLEEP)
382
383 usleep((useconds_t) ms);
384 #else
385
386 {
387 struct timeval tv = { .tv_sec = 0, .tv_usec = (suseconds_t) ms };
388
389 select(0, NULL, NULL, NULL, &tv);
390 }
391 #endif
392 }
393
394
395
396
397 #include <crm/common/util_compat.h>
398
399 guint
400 crm_parse_interval_spec(const char *input)
401 {
402 long long msec = -1;
403
404 errno = 0;
405 if (input == NULL) {
406 return 0;
407
408 } else if (input[0] == 'P') {
409 crm_time_t *period_s = crm_time_parse_duration(input);
410
411 if (period_s) {
412 msec = 1000 * crm_time_get_seconds(period_s);
413 crm_time_free(period_s);
414 }
415
416 } else {
417 msec = crm_get_msec(input);
418 }
419
420 if (msec < 0) {
421 crm_warn("Using 0 instead of '%s'", input);
422 errno = EINVAL;
423 return 0;
424 }
425 return (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
426 }
427
428 char *
429 pcmk_hostname(void)
430 {
431 struct utsname hostinfo;
432
433 return (uname(&hostinfo) < 0)? NULL : strdup(hostinfo.nodename);
434 }
435
436
437