1 /* SPDX-License-Identifier: GPL-2.0+ */
9 void *xrealloc(void *p, size_t size)
12 assert((p = realloc(p, size)));
16 void *xmalloc(size_t size)
18 return xrealloc(NULL, size);
21 void *xzmalloc(size_t size)
23 void *p = xrealloc(NULL, size);
28 void *xstrdup(const char *s)
30 char *ret = strdup(s? s: "");
36 char *msg(const char *fmt, ...)
46 /* Try to print in the allocated space. */
48 n = vsnprintf(m, size, fmt, ap);
50 /* If that worked, return the string. */
53 /* Else try again with more space. */
54 size = n + 1; /* precisely what is needed */
55 m = xrealloc(m, size);
59 bool fd2buf(int fd, char **buf)
61 ssize_t ret, nread = 0, sz = 100;
65 ret = read(fd, *buf + nread, sz - nread - 1);
67 if (errno == EAGAIN || errno == EINTR)
69 ERROR_LOG("read error: %s\n", strerror(errno));
77 if (nread >= sz - 1) {
79 *buf = xrealloc(*buf, sz);
84 bool xexec(char * const argv[], char **buf)
87 int pipefd[2] = {-1, -1};
90 for (n = 0; argv[n]; n++)
91 DEBUG_LOG("argv[%u]=%s\n", n, argv[n]);
96 if ((pid = fork()) < 0)
98 if (pid > 0) { /* parent */
103 success = fd2buf(pipefd[0], buf);
106 if (waitpid(pid, &wstatus, 0) < 0)
110 if (!WIFEXITED(wstatus))
112 if (WEXITSTATUS(wstatus) != EXIT_SUCCESS)
118 if (pipefd[1] >= 0 && pipefd[1] != STDOUT_FILENO) {
119 if (dup2(pipefd[1], STDOUT_FILENO) < 0)
123 execvp(argv[0], argv);
124 EMERG_LOG("execvp error: %s\n", strerror(errno));
128 void die_empty_arg(const char *opt)
130 die("argument to --%s must not be empty", opt);
133 void die_range(const char *opt)
135 die("argument to --%s is out of range", opt);
138 void check_range(uint32_t val, uint32_t min, uint32_t max, const char *opt)
140 if (val < min || val > max)
144 static uint32_t atou32(const char *str, const char *opt)
149 errno = 0; /* To distinguish success/failure after call */
150 tmp = strtoll(str, &endptr, 10);
151 if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN))
153 if (tmp < 0 || tmp > (uint32_t)-1)
156 * If there were no digits at all, strtoll() stores the original value
162 * The implementation may also set errno and return 0 in case no
163 * conversion was performed.
165 if (errno != 0 && tmp == 0)
167 if (*endptr != '\0') /* Further characters after number */
168 die("--%s: trailing characters after number", opt);
172 static void split_arg(const char *arg, const char *context,
173 char **prefix, char **suffix)
176 char *tmp = xstrdup(arg);
179 die_empty_arg(context);
180 colon = strchr(tmp, ':');
187 if (colon == tmp || !colon[1])
188 die("%s: invalid argument", context);
189 *prefix = xstrdup(tmp);
190 *suffix = xstrdup(colon + 1);
194 void parse_lvmspec(const char *arg, const char *context,
195 struct lvmspec *result)
198 char *tmp = xstrdup(arg);
200 slash = strchr(tmp, '/');
202 if (slash == tmp || !slash[1])
203 die("%s: invalid argument", context);
205 result->scope = LS_ORIGIN;
206 result->tlv = xstrdup(slash + 1);
209 pipe = strchr(tmp, '|');
211 if (pipe == tmp || !pipe[1])
212 die("%s: invalid argument", context);
214 result->scope = LS_POOL;
215 result->pool = xstrdup(pipe + 1);
218 result->scope = LS_VG;
220 result->vg = xstrdup(tmp);
224 void free_lvmspec(struct lvmspec *spec)
226 if (spec->scope == LS_GLOBAL)
229 if (spec->scope == LS_POOL)
231 else if (spec->scope == LS_ORIGIN)
235 void parse_threshold_arg(const char *arg, const char *context,
236 struct threshold_arg *result)
238 char *prefix, *suffix, *comma;
241 split_arg(arg, context, &prefix, &suffix);
243 parse_lvmspec(prefix, context, &result->lvmspec);
244 if (result->lvmspec.scope == LS_ORIGIN)
245 die("invalid scope for threshold lvmspec");
247 result->lvmspec.scope = LS_GLOBAL;
249 comma = strchr(suffix, ',');
251 die("%s: invalid argument", context);
253 val = atou32(suffix, context);
254 check_range(val, 1, 99, context);
255 result->threshold.data = val;
256 val = atou32(comma + 1, context);
257 check_range(val, 1, 99, context);
258 result->threshold.meta = val;
262 unsigned parse_timespec(const char *spec, const char *context)
264 char *p, *tmp = xstrdup(spec);
265 uint64_t val, multiplier;
267 for (p = tmp; isdigit(*p); p++)
270 die("%s: timepec lacks trailing time unit", context);
272 case 's': multiplier = 1; break;
273 case 'm': multiplier = 60; break;
274 case 'h': multiplier = 3600; break;
275 case 'd': multiplier = 86400; break;
276 case 'y': multiplier = 365 * 86400; break;
278 die("%s: invalid time unit in timepec argument", context);
282 die("%s: trailing characters after time unit", context);
283 val = atou32(tmp, context) * multiplier;
285 if (val > (uint32_t)-1)
290 void parse_time_arg(const char *arg, const char *context,
291 struct time_arg *result)
293 char *prefix, *suffix;
295 split_arg(arg, context, &prefix, &suffix);
297 parse_lvmspec(prefix, context, &result->lvmspec);
299 result->lvmspec.scope = LS_GLOBAL;
301 result->seconds = parse_timespec(suffix, context);
305 void line_iter_init(struct line_iter *liter, char *text)
307 liter->line = liter->base = text;
310 char *line_iter_get(struct line_iter *liter)
314 if (!liter->line || !liter->line[0])
317 cr = strchr(liter->line, '\n');
320 liter->line = cr + 1;
326 void valid_fd012(void)
328 /* Ensure that file descriptors 0, 1, and 2 are valid. */
330 int fd = open("/dev/null", O_RDWR);
340 int daemonize(const char *logfile)
343 int nullfd, logfd, pipefd[2];
345 if (pipe(pipefd) < 0)
347 if ((pid = fork()) < 0)
349 if (pid) { /* parent exits after reading from the pipe */
352 if (read(pipefd[0], &c, 1) <= 0)
353 die("child terminated unsuccessfully");
357 /* become session leader */
360 if ((nullfd = open("/dev/null", O_RDWR)) < 0)
361 die_errno("open /dev/null");
362 logfile = logfile? logfile : "/dev/null";
363 if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0666)) < 0)
364 die_errno("open %s", logfile);
365 INFO_LOG("subsequent log messages go to %s\n", logfile);
366 if (dup2(nullfd, STDIN_FILENO) < 0)
369 if (dup2(logfd, STDOUT_FILENO) < 0)
371 if (dup2(logfd, STDERR_FILENO) < 0)
380 static int super_dull_hash(const char *input)
382 const uint8_t *x = (typeof(x))input;
383 const unsigned p1 = 16777619, p2 = 2971215073;
384 unsigned n, m, h, result = 0;
386 for (n = 0; n < 4; n++) {
388 for (m = 1; x[m] != 0; m++)
390 result = (result << 8) | (h % 256);
396 * We use a semaphore set with two semaphores. The first semaphore is modified
397 * in both misma_lock() and get_misma_pid() while the second one is modified
398 * only in misma_lock(). This allows us to obtain the PID of the running misma
399 * process by querying the PID that last performed an operation on the second
400 * semaphore. This is achieved by passing GETPID as the control operation to
404 bool misma_lock(const char *string)
407 struct sembuf sops[4];
408 key_t key = super_dull_hash(string);
410 ret = semget(key, 2, IPC_CREAT | 0600);
414 DEBUG_LOG("key: 0x%0x, semid: %d\n", (unsigned)key, semid);
417 sops[0].sem_flg = SEM_UNDO | IPC_NOWAIT;
421 sops[1].sem_flg = SEM_UNDO | IPC_NOWAIT;
425 sops[2].sem_flg = SEM_UNDO | IPC_NOWAIT;
429 sops[3].sem_flg = SEM_UNDO | IPC_NOWAIT;
431 return semop(semid, sops, 4) >= 0;
434 /* returns zero if misma is not running */
435 pid_t get_misma_pid(const char *string)
438 struct sembuf sops = {
441 .sem_flg = SEM_UNDO | IPC_NOWAIT
443 key_t key = super_dull_hash(string);
445 ret = semget(key, 2, 0);
449 DEBUG_LOG("key: 0x%0x, semid: %d\n", (unsigned)key, semid);
450 if (semop(semid, &sops, 1) >= 0)
452 ret = semctl(semid, 1, GETPID);
458 /* Simplistic min-heap implementation (see e.g. Cormen et al. Chapter 6) */
460 void ***aa; /* array address */
461 unsigned n; /* num elements */
462 int (*compare)(const void *data1, const void *data2);
465 static unsigned heap_parent(unsigned idx)
467 return (idx + 1) / 2 - 1;
470 static unsigned heap_left(unsigned idx)
472 return (idx + 1) * 2 - 1;
475 static unsigned heap_right(unsigned idx)
477 return (idx + 1) * 2;
480 static void heapify(struct heap *h, unsigned idx)
482 unsigned l = heap_left(idx), r = heap_right(idx), smallest;
483 void **array = *(h->aa);
486 if (l < h->n && h->compare(array[l], array[idx]) > 0)
490 if (r < h->n && h->compare(array[r], array[smallest]) > 0)
492 if (smallest != idx) { /* exchange idx and smallest */
493 void *tmp = array[idx];
494 array[idx] = array[smallest];
495 array[smallest] = tmp;
496 heapify(h, smallest);
500 struct heap *heap_init(void *aa, unsigned num_elements,
501 int (*compare)(const void *data1, const void *data2))
503 struct heap *h = xmalloc(sizeof(*h));
505 INFO_LOG("creating heap with %u elements\n", num_elements);
508 h->compare = compare;
509 for (unsigned j = h->n / 2 - 1; j != ~0U; j--)
514 void *heap_min(const struct heap *h)
517 return (*(h->aa))[0];
520 unsigned heap_num_elements(const struct heap *h)
525 void *heap_extract_min(struct heap *h)
527 void *smallest = heap_min(h);
528 void **array = *(h->aa);
530 array[0] = array[h->n - 1];
532 *(h->aa) = xrealloc((*h->aa), h->n * sizeof(void *));
537 void heap_insert(void *new_element, struct heap *h)
543 *(h->aa) = xrealloc((*h->aa), h->n * sizeof(void *));
545 array[h->n - 1] = new_element;
546 for (unsigned j = h->n - 1; j > 0; j = parent) {
548 parent = heap_parent(j);
549 if (h->compare(array[j], array[parent]) <= 0)
552 array[j] = array[parent];
557 void heap_dump(const struct heap *h, void (*dumper)(const void *))
559 void **array = *(h->aa);
560 for (unsigned j = 0; j < h->n; j++)