335 lines
10 KiB
C
335 lines
10 KiB
C
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
|
#pragma once
|
|
|
|
/***
|
|
This file is part of systemd.
|
|
|
|
Copyright 2010 Lennart Poettering
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
***/
|
|
|
|
#include <alloca.h>
|
|
#include <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <limits.h>
|
|
#include <locale.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/inotify.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/statfs.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "formats-util.h"
|
|
#include "macro.h"
|
|
#include "missing.h"
|
|
#include "time-util.h"
|
|
|
|
/* What is interpreted as whitespace? */
|
|
#define WHITESPACE " \t\n\r"
|
|
#define NEWLINE "\n\r"
|
|
#define QUOTES "\"\'"
|
|
#define COMMENTS "#;"
|
|
#define GLOB_CHARS "*?["
|
|
|
|
size_t page_size(void) _pure_;
|
|
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
|
|
|
|
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
|
|
|
|
#define new0(t, n) ((t*) calloc((n), sizeof(t)))
|
|
|
|
#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
|
|
|
|
#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
|
|
|
|
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
|
|
|
|
#define malloc0(n) (calloc(1, (n)))
|
|
|
|
static inline void *mfree(void *memory) {
|
|
free(memory);
|
|
return NULL;
|
|
}
|
|
|
|
static inline const char* yes_no(bool b) {
|
|
return b ? "yes" : "no";
|
|
}
|
|
|
|
static inline const char* true_false(bool b) {
|
|
return b ? "true" : "false";
|
|
}
|
|
|
|
static inline const char* one_zero(bool b) {
|
|
return b ? "1" : "0";
|
|
}
|
|
|
|
bool fstype_is_network(const char *fstype);
|
|
|
|
#define xsprintf(buf, fmt, ...) \
|
|
assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \
|
|
"xsprintf: " #buf "[] must be big enough")
|
|
|
|
noreturn void freeze(void);
|
|
|
|
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
|
|
|
|
bool plymouth_running(void);
|
|
|
|
bool display_is_local(const char *display) _pure_;
|
|
int socket_from_display(const char *display, char **path);
|
|
|
|
int glob_exists(const char *path);
|
|
int glob_extend(char ***strv, const char *path);
|
|
|
|
int block_get_whole_disk(dev_t d, dev_t *ret);
|
|
|
|
#define NULSTR_FOREACH(i, l) \
|
|
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
|
|
|
|
#define NULSTR_FOREACH_PAIR(i, j, l) \
|
|
for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
|
|
|
|
int ioprio_class_to_string_alloc(int i, char **s);
|
|
int ioprio_class_from_string(const char *s);
|
|
|
|
const char *sigchld_code_to_string(int i) _const_;
|
|
int sigchld_code_from_string(const char *s) _pure_;
|
|
|
|
int sched_policy_to_string_alloc(int i, char **s);
|
|
int sched_policy_from_string(const char *s);
|
|
|
|
extern int saved_argc;
|
|
extern char **saved_argv;
|
|
|
|
bool kexec_loaded(void);
|
|
|
|
int prot_from_flags(int flags) _const_;
|
|
|
|
void* memdup(const void *p, size_t l) _alloc_(2);
|
|
|
|
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);
|
|
|
|
bool http_url_is_valid(const char *url) _pure_;
|
|
bool documentation_url_is_valid(const char *url) _pure_;
|
|
|
|
bool http_etag_is_valid(const char *etag);
|
|
|
|
bool in_initrd(void);
|
|
|
|
static inline void freep(void *p) {
|
|
free(*(void**) p);
|
|
}
|
|
|
|
#define _cleanup_free_ _cleanup_(freep)
|
|
#define _cleanup_globfree_ _cleanup_(globfree)
|
|
|
|
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
|
|
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
|
return NULL;
|
|
|
|
return malloc(a * b);
|
|
}
|
|
|
|
_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
|
|
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
|
return NULL;
|
|
|
|
return realloc(p, a * b);
|
|
}
|
|
|
|
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
|
|
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
|
|
return NULL;
|
|
|
|
return memdup(p, a * b);
|
|
}
|
|
|
|
/**
|
|
* Check if a string contains any glob patterns.
|
|
*/
|
|
_pure_ static inline bool string_is_glob(const char *p) {
|
|
return !!strpbrk(p, GLOB_CHARS);
|
|
}
|
|
|
|
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
|
int (*compar) (const void *, const void *, void *),
|
|
void *arg);
|
|
|
|
int on_ac_power(void);
|
|
|
|
static inline void *mempset(void *s, int c, size_t n) {
|
|
memset(s, c, n);
|
|
return (uint8_t*)s + n;
|
|
}
|
|
|
|
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
|
|
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
|
|
#define GREEDY_REALLOC(array, allocated, need) \
|
|
greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
|
|
|
|
#define GREEDY_REALLOC0(array, allocated, need) \
|
|
greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
|
|
|
|
static inline void _reset_errno_(int *saved_errno) {
|
|
errno = *saved_errno;
|
|
}
|
|
|
|
#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
|
|
|
|
static inline int negative_errno(void) {
|
|
/* This helper should be used to shut up gcc if you know 'errno' is
|
|
* negative. Instead of "return -errno;", use "return negative_errno();"
|
|
* It will suppress bogus gcc warnings in case it assumes 'errno' might
|
|
* be 0 and thus the caller's error-handling might not be triggered. */
|
|
assert_return(errno > 0, -EINVAL);
|
|
return -errno;
|
|
}
|
|
|
|
static inline unsigned u64log2(uint64_t n) {
|
|
#if __SIZEOF_LONG_LONG__ == 8
|
|
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
|
|
#else
|
|
#error "Wut?"
|
|
#endif
|
|
}
|
|
|
|
static inline unsigned u32ctz(uint32_t n) {
|
|
#if __SIZEOF_INT__ == 4
|
|
return __builtin_ctz(n);
|
|
#else
|
|
#error "Wut?"
|
|
#endif
|
|
}
|
|
|
|
static inline unsigned log2i(int x) {
|
|
assert(x > 0);
|
|
|
|
return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
|
|
}
|
|
|
|
static inline unsigned log2u(unsigned x) {
|
|
assert(x > 0);
|
|
|
|
return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
|
|
}
|
|
|
|
static inline unsigned log2u_round_up(unsigned x) {
|
|
assert(x > 0);
|
|
|
|
if (x == 1)
|
|
return 0;
|
|
|
|
return log2u(x - 1) + 1;
|
|
}
|
|
|
|
#define DECIMAL_STR_WIDTH(x) \
|
|
({ \
|
|
typeof(x) _x_ = (x); \
|
|
unsigned ans = 1; \
|
|
while (_x_ /= 10) \
|
|
ans++; \
|
|
ans; \
|
|
})
|
|
|
|
#define alloca0(n) \
|
|
({ \
|
|
char *_new_; \
|
|
size_t _len_ = n; \
|
|
_new_ = alloca(_len_); \
|
|
(void *) memset(_new_, 0, _len_); \
|
|
})
|
|
|
|
/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
|
|
#define alloca_align(size, align) \
|
|
({ \
|
|
void *_ptr_; \
|
|
size_t _mask_ = (align) - 1; \
|
|
_ptr_ = alloca((size) + _mask_); \
|
|
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
|
|
})
|
|
|
|
#define alloca0_align(size, align) \
|
|
({ \
|
|
void *_new_; \
|
|
size_t _size_ = (size); \
|
|
_new_ = alloca_align(_size_, (align)); \
|
|
(void*)memset(_new_, 0, _size_); \
|
|
})
|
|
|
|
bool id128_is_valid(const char *s) _pure_;
|
|
|
|
/**
|
|
* Normal qsort requires base to be nonnull. Here were require
|
|
* that only if nmemb > 0.
|
|
*/
|
|
static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
|
|
if (nmemb <= 1)
|
|
return;
|
|
|
|
assert(base);
|
|
qsort(base, nmemb, size, compar);
|
|
}
|
|
|
|
int container_get_leader(const char *machine, pid_t *pid);
|
|
|
|
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
|
|
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
|
|
|
|
#ifndef PERSONALITY_INVALID
|
|
/* personality(7) documents that 0xffffffffUL is used for querying the
|
|
* current personality, hence let's use that here as error
|
|
* indicator. */
|
|
#define PERSONALITY_INVALID 0xffffffffLU
|
|
#endif
|
|
|
|
unsigned long personality_from_string(const char *p);
|
|
const char *personality_to_string(unsigned long);
|
|
|
|
uint64_t physical_memory(void);
|
|
|
|
union file_handle_union {
|
|
struct file_handle handle;
|
|
char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
|
|
};
|
|
#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
|
|
|
|
int update_reboot_param_file(const char *param);
|
|
|
|
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
|
|
|
|
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
|
|
for ((e) = &buffer.ev; \
|
|
(uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
|
|
(e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
|
|
|
|
union inotify_event_buffer {
|
|
struct inotify_event ev;
|
|
uint8_t raw[INOTIFY_EVENT_MAX];
|
|
};
|
|
|
|
int version(void);
|
|
|
|
bool fdname_is_valid(const char *s);
|
|
|
|
bool oom_score_adjust_is_valid(int oa);
|