Browse Source

install/*: add dracut-install tool

master
Harald Hoyer 13 years ago
parent
commit
026b81e980
  1. 17
      Makefile
  2. 2
      dracut.spec
  3. 17
      install/Makefile
  4. 736
      install/dracut-install.c
  5. 731
      install/hashmap.c
  6. 91
      install/hashmap.h
  7. 12
      install/hashmap.lo
  8. BIN
      install/hashmap.o
  9. 294
      install/log.c
  10. 115
      install/log.h
  11. 192
      install/macro.h
  12. 187
      install/util.c
  13. 527
      install/util.h

17
Makefile

@ -13,7 +13,10 @@ manpages = dracut.8 dracut.cmdline.7 dracut.conf.5 dracut-catimages.8 @@ -13,7 +13,10 @@ manpages = dracut.8 dracut.cmdline.7 dracut.conf.5 dracut-catimages.8

.PHONY: install clean archive rpm testimage test all check AUTHORS doc

all: syncheck dracut-version.sh
all: syncheck dracut-version.sh install/dracut-install

install/dracut-install:
$(MAKE) -C install dracut-install

doc: $(manpages) dracut.html

@ -71,6 +74,7 @@ install: doc dracut-version.sh @@ -71,6 +74,7 @@ install: doc dracut-version.sh
ln -s ../dracut-shutdown.service \
$(DESTDIR)$(systemdsystemunitdir)/shutdown.target.wants/dracut-shutdown.service; \
fi
$(MAKE) -C install install

dracut-version.sh:
@echo "DRACUT_VERSION=$(VERSION)-$(GITVERSION)" > dracut-version.sh
@ -83,6 +87,7 @@ clean: @@ -83,6 +87,7 @@ clean:
$(RM) dracut-*.rpm dracut-*.tar.bz2
$(RM) $(manpages) dracut.html
$(MAKE) -C test clean
$(MAKE) -C install clean

archive: dracut-$(VERSION)-$(GITVERSION).tar.bz2

@ -104,7 +109,7 @@ rpm: dracut-$(VERSION).tar.bz2 @@ -104,7 +109,7 @@ rpm: dracut-$(VERSION).tar.bz2
(cd "$$rpmbuild"; rpmbuild --define "_topdir $$PWD" --define "_sourcedir $$PWD" \
--define "_specdir $$PWD" --define "_srcrpmdir $$PWD" \
--define "_rpmdir $$PWD" -ba dracut.spec; ) && \
( mv "$$rpmbuild"/noarch/*.rpm .; mv "$$rpmbuild"/*.src.rpm .;rm -fr "$$rpmbuild"; ls *.rpm )
( mv "$$rpmbuild"/$$(arch)/*.rpm .; mv "$$rpmbuild"/*.src.rpm .;rm -fr "$$rpmbuild"; ls *.rpm )

syncheck:
@ret=0;for i in dracut-initramfs-restore.sh dracut-logger.sh \
@ -123,17 +128,17 @@ check: all syncheck @@ -123,17 +128,17 @@ check: all syncheck

testimage: all
./dracut.sh -l -a debug -f test-$(shell uname -r).img $(shell uname -r)
@echo wrote test-$(shell uname -r).img
@echo wrote test-$(shell uname -r).img

testimages: all
./dracut.sh -l -a debug --kernel-only -f test-kernel-$(shell uname -r).img $(shell uname -r)
@echo wrote test-$(shell uname -r).img
@echo wrote test-$(shell uname -r).img
./dracut.sh -l -a debug --no-kernel -f test-dracut.img $(shell uname -r)
@echo wrote test-dracut.img
@echo wrote test-dracut.img

hostimage: all
./dracut.sh -H -l -a debug -f test-$(shell uname -r).img $(shell uname -r)
@echo wrote test-$(shell uname -r).img
@echo wrote test-$(shell uname -r).img

AUTHORS:
git shortlog --numbered --summary -e |while read a rest; do echo $$rest;done > AUTHORS

2
dracut.spec

@ -25,7 +25,6 @@ URL: https://dracut.wiki.kernel.org/ @@ -25,7 +25,6 @@ URL: https://dracut.wiki.kernel.org/
# http://git.kernel.org/?p=boot/dracut/dracut.git;a=snapshot;h=%{version};sf=tgz
Source0: http://www.kernel.org/pub/linux/utils/boot/dracut/dracut-%{version}.tar.bz2

BuildArch: noarch
BuildRequires: dash bash git

%if 0%{?fedora} || 0%{?rhel}
@ -236,6 +235,7 @@ rm -rf $RPM_BUILD_ROOT @@ -236,6 +235,7 @@ rm -rf $RPM_BUILD_ROOT
%if 0%{?fedora} > 12 || 0%{?rhel} >= 6 || 0%{?suse_version} > 9999
%{_bindir}/mkinitrd
%{_bindir}/lsinitrd
%{_bindir}/dracut-install
%endif
%dir %{dracutlibdir}
%dir %{dracutlibdir}/modules.d

17
install/Makefile

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
prefix ?= /usr
bindir ?= ${prefix}/bin
strip ?= -s

all: dracut-install

dracut-install: dracut-install.c hashmap.c log.c util.c
gcc -std=gnu99 -O2 -g -Wall -o dracut-install dracut-install.c hashmap.c log.c util.c

install: dracut-install
install $(strip) -m 0755 dracut-install $(DESTDIR)$(bindir)/dracut-install

clean:
rm -f dracut-install *~

indent:
indent -i8 -nut -br -linux -l120 dracut-install.c

736
install/dracut-install.c

@ -0,0 +1,736 @@ @@ -0,0 +1,736 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

/* dracut-install.c -- install files and executables

Copyright (C) 2012 Harald Hoyer
Copyright (C) 2012 Red Hat, Inc. All rights reserved.

This program is free software: you can redistribute it and/or modify
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.

This program 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 this program; If not, see <http://www.gnu.org/licenses/>.
*/

#define PROGRAM_VERSION_STRING "1"

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <libgen.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "log.h"
#include "hashmap.h"
#include "util.h"

static bool arg_hmac = false;
static bool arg_createdir = false;
static int arg_loglevel = -1;
static bool arg_optional = false;
static bool arg_all = false;
static bool arg_resolvelazy = false;
static bool arg_resolvedeps = false;
static char *destrootdir = NULL;

static Hashmap *items = NULL;
static Hashmap *items_failed = NULL;

static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps);

static size_t dir_len(char const *file)
{
size_t length;
/* Strip the basename and any redundant slashes before it. */
for (length = strlen(file); 0 < length; length--)
if (file[length] == '/')
break;
return length;
}

static char *convert_abs_rel(const char *from, const char *target)
{
/* we use the 4*MAXPATHLEN, which should not overrun */
char relative_from[MAXPATHLEN * 4];
char *realtarget = NULL;
char *p, *q;
const char *realfrom = from;
int level = 0, fromlevel = 0, targetlevel = 0;
int l, i, rl;
int dirlen;

p = strdup(target);
dirlen = dir_len(p);
p[dirlen] = '\0';
q = realpath(p, NULL);

if (q == NULL) {
free(p);
log_warning("convert_abs_rel(): target '%s' directory has no realpath.", target);
return strdup(from);
}

asprintf(&realtarget, "%s/%s", q, &p[dirlen + 1]);
free(p);
free(q);

/* now calculate the relative path from <from> to <target> and
store it in <relative_from>
*/
relative_from[0] = 0;
rl = 0;

/* count the pathname elements of realtarget */
for (targetlevel = 0, i = 0; realtarget[i]; i++)
if (realtarget[i] == '/')
targetlevel++;

/* count the pathname elements of realfrom */
for (fromlevel = 0, i = 0; realfrom[i]; i++)
if (realfrom[i] == '/')
fromlevel++;

/* count the pathname elements, which are common for both paths */
for (level = 0, i = 0; realtarget[i] && (realtarget[i] == realfrom[i]); i++)
if (realtarget[i] == '/')
level++;

free(realtarget);

/* add "../" to the relative_from path, until the common pathname is
reached */
for (i = level; i < targetlevel; i++) {
if (i != level)
relative_from[rl++] = '/';
relative_from[rl++] = '.';
relative_from[rl++] = '.';
}

/* set l to the next uncommon pathname element in realfrom */
for (l = 1, i = 1; i < level; i++)
for (l++; realfrom[l] && realfrom[l] != '/'; l++) ;
/* skip next '/' */
l++;

/* append the uncommon rest of realfrom to the relative_from path */
for (i = level; i <= fromlevel; i++) {
if (rl)
relative_from[rl++] = '/';
while (realfrom[l] && realfrom[l] != '/')
relative_from[rl++] = realfrom[l++];
l++;
}

relative_from[rl] = 0;
return strdup(relative_from);
}

static int ln_r(const char *src, const char *dst)
{
int ret;
const char *points_to = convert_abs_rel(src, dst);
log_info("ln -s '%s' '%s'", points_to, dst);
ret = symlink(points_to, dst);

if (ret != 0) {
log_error("ERROR: ln -s '%s' '%s': %m", points_to, dst);
free((char *)points_to);
return 1;
}

free((char *)points_to);

return 0;
}

static int cp(const char *src, const char *dst)
{
int pid;
int status;

pid = fork();
if (pid == 0) {
execlp("cp", "cp", "--reflink=auto", "--sparse=auto", "--preserve=mode", "-fL", src, dst, NULL);
_exit(EXIT_FAILURE);
}

while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1;
break;
}
}

return status;
}

static int resolve_deps(const char *src)
{
int ret = 0;

char *buf = malloc(LINE_MAX);
size_t linesize = LINE_MAX;
FILE *fptr;
char *cmd;

if (strstr(src, ".so") == 0) {
int fd;
fd = open(src, O_RDONLY | O_CLOEXEC);
read(fd, buf, LINE_MAX);
buf[LINE_MAX - 1] = '\0';
close(fd);
if (buf[0] == '#' && buf[1] == '!') {
/* we have a shebang */
char *p, *q;
for (p = &buf[2]; *p && isspace(*p); p++) ;
for (q = p; *q && (!isspace(*q)); q++) ;
*q = '\0';
log_debug("Script install: '%s'", p);
ret = dracut_install(p, p, false, true);
if (ret != 0)
log_error("ERROR: failed to install '%s'", p);
return ret;
}
}

/* run ldd */
asprintf(&cmd, "ldd %s", src);
fptr = popen(cmd, "r");

while (!feof(fptr)) {
char *p, *q;

if (getline(&buf, &linesize, fptr) <= 0)
continue;

log_debug("ldd: '%s'", buf);

if (strstr(buf, "not a dynamic executable"))
break;

p = strstr(buf, "/");
if (p) {
int r;
for (q = p; *q && *q != ' ' && *q != '\n'; q++) ;
*q = '\0';
r = dracut_install(p, p, false, false);
if (r != 0)
log_error("ERROR: failed to install '%s' for '%s'", p, src);
else
log_debug("Lib install: '%s'", p);
ret += r;

/* also install lib.so for lib.so.* files */
q = strstr(p, ".so.");
if (q) {
q += 3;
*q = '\0';

/* ignore errors for base lib symlink */
if (dracut_install(p, p, false, false) == 0)
log_debug("Lib install: '%s'", p);
}
}
}
pclose(fptr);

return ret;
}

/* Install ".<filename>.hmac" file for FIPS self-checks */
static int hmac_install(const char *src, const char *dst)
{
char *srcpath = strdup(src);
char *dstpath = strdup(dst);
char *srchmacname = NULL;
char *dsthmacname = NULL;
size_t dlen = dir_len(src);

if (endswith(src, ".hmac"))
return 0;

srcpath[dlen] = '\0';
dstpath[dir_len(dst)] = '\0';
asprintf(&srchmacname, "%s/.%s.hmac", srcpath, &src[dlen + 1]);
asprintf(&dsthmacname, "%s/.%s.hmac", dstpath, &src[dlen + 1]);
log_debug("hmac cp '%s' '%s')", srchmacname, dsthmacname);
dracut_install(srchmacname, dsthmacname, false, false);
free(dsthmacname);
free(srchmacname);
free(srcpath);
free(dstpath);
return 0;
}

static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps)
{
struct stat sb, db;
char *dname = NULL;
char *fulldstpath = NULL;
char *fulldstdir = NULL;
int ret;
bool src_exists = true;
char *i, *existing;

log_debug("dracut_install('%s', '%s')", src, dst);

existing = hashmap_get(items_failed, src);
if (existing) {
if (strcmp(existing, src) == 0) {
log_debug("hash hit items_failed for '%s'", src);
return 1;
}
}

existing = hashmap_get(items, dst);
if (existing) {
if (strcmp(existing, dst) == 0) {
log_debug("hash hit items for '%s'", dst);
return 0;
}
}

if (lstat(src, &sb) < 0) {
src_exists = false;
if (!isdir) {
i = strdup(src);
hashmap_put(items_failed, i, i);
/* src does not exist */
return 1;
}
}

i = strdup(dst);
hashmap_put(items, i, i);

asprintf(&fulldstpath, "%s%s", destrootdir, dst);

ret = stat(fulldstpath, &sb);

if (ret != 0 && (errno != ENOENT)) {
log_error("ERROR: stat '%s': %m", fulldstpath);
return 1;
}

if (ret == 0) {
log_debug("'%s' already exists", fulldstpath);
free(fulldstpath);
/* dst does already exist */
return 0;
}

/* check destination directory */
fulldstdir = strdup(fulldstpath);
fulldstdir[dir_len(fulldstdir)] = '\0';

ret = stat(fulldstdir, &db);

if (ret < 0) {
if (errno != ENOENT) {
log_error("ERROR: stat '%s': %m", fulldstdir);
return 1;
}
/* create destination directory */
log_debug("dest dir '%s' does not exist", fulldstdir);
dname = strdup(dst);
dname[dir_len(dname)] = '\0';
ret = dracut_install(dname, dname, true, false);

free(dname);

if (ret != 0) {
log_error("ERROR: failed to create directory '%s'", fulldstdir);
free(fulldstdir);
return 1;
}
}

free(fulldstdir);

if (isdir && !src_exists) {
log_info("mkdir '%s'", fulldstpath);
return mkdir(fulldstpath, 0755);
}

/* ready to install src */

if (S_ISDIR(sb.st_mode)) {
log_info("mkdir '%s'", fulldstpath);
return mkdir(fulldstpath, sb.st_mode | S_IWUSR);
}

if (S_ISLNK(sb.st_mode)) {
char *abspath;
char *absdestpath = NULL;

abspath = realpath(src, NULL);

if (abspath == NULL)
return 1;

if (dracut_install(abspath, abspath, false, resolvedeps)) {
log_debug("'%s' install error", abspath);
return 1;
}

if (lstat(abspath, &sb) != 0) {
log_debug("lstat '%s': %m", abspath);
return 1;
}

if (lstat(fulldstpath, &sb) != 0) {

asprintf(&absdestpath, "%s%s", destrootdir, abspath);

ln_r(absdestpath, fulldstpath);

free(absdestpath);
}

free(abspath);
if (arg_hmac) {
/* copy .hmac files also */
hmac_install(src, dst);
}

return 0;
}

if (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
if (resolvedeps)
ret += resolve_deps(src);
if (arg_hmac) {
/* copy .hmac files also */
hmac_install(src, dst);
}
}

log_info("cp '%s' '%s'", src, fulldstpath);
ret += cp(src, fulldstpath);
return ret;
}

static void item_free(char *i)
{
assert(i);
free(i);
}

static void usage(int status)
{
/* */
printf("\
Usage: %s -D DESTROOTDIR [OPTION]... -a SOURCE...\n\
or: %s -D DESTROOTDIR [OPTION]... SOURCE DEST\n\
\n\
Install SOURCE to DEST in DESTROOTDIR with all needed dependencies.\n\
\n\
-D --destrootdir Install all files to DESTROOTDIR as the root\n\
-a --all Install all SOURCE arguments to DESTROOTDIR\n\
-o --optional If SOURCE does not exist, do not fail\n\
-d --dir SOURCE is a directory\n\
-l --ldd Also install shebang executables and libraries\n\
-R --resolvelazy Only install shebang executables and libraries for all SOURCE files\n\
-f --fips Also install all '.SOURCE.hmac' files\n\
-v --verbose Show more output\n\
--debug Show debug output\n\
--version Show package version\n\
-h --help Show this help\n\
\n\
Example:\n\
# %s -D /var/tmp/test-root --ldd -a sh tr\n\
# tree /var/tmp/test-root\n\
/var/tmp/test-root\n\
|-- lib64 -> usr/lib64\n\
`-- usr\n\
|-- bin\n\
| |-- bash\n\
| |-- sh -> bash\n\
| `-- tr\n\
`-- lib64\n\
|-- ld-2.15.90.so\n\
|-- ld-linux-x86-64.so.2 -> ld-2.15.90.so\n\
|-- libc-2.15.90.so\n\
|-- libc.so\n\
|-- libc.so.6 -> libc-2.15.90.so\n\
|-- libdl-2.15.90.so\n\
|-- libdl.so -> libdl-2.15.90.so\n\
|-- libdl.so.2 -> libdl-2.15.90.so\n\
|-- libtinfo.so.5 -> libtinfo.so.5.9\n\
`-- libtinfo.so.5.9\n\
", program_invocation_short_name, program_invocation_short_name, program_invocation_short_name);
exit(status);
}

static int parse_argv(int argc, char *argv[])
{
int c;

enum {
ARG_VERSION = 0x100,
ARG_DEBUG
};

static const struct option const options[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, ARG_VERSION},
{"dir", no_argument, NULL, 'd'},
{"debug", no_argument, NULL, ARG_DEBUG},
{"verbose", no_argument, NULL, 'v'},
{"ldd", no_argument, NULL, 'l'},
{"resolvelazy", no_argument, NULL, 'R'},
{"optional", no_argument, NULL, 'o'},
{"all", no_argument, NULL, 'a'},
{"fips", no_argument, NULL, 'H'},
{"destrootdir", required_argument, NULL, 'D'},
{NULL, 0, NULL, 0}
};

while ((c = getopt_long(argc, argv, "adhloD:DHILR", options, NULL)) != -1) {
switch (c) {
case ARG_VERSION:
puts(PROGRAM_VERSION_STRING);
return 0;
case 'd':
arg_createdir = true;
break;
case ARG_DEBUG:
arg_loglevel = LOG_DEBUG;
break;
case 'v':
arg_loglevel = LOG_INFO;
break;
case 'o':
arg_optional = true;
break;
case 'l':
arg_resolvedeps = true;
break;
case 'R':
arg_resolvelazy = true;
break;
case 'a':
arg_all = true;
break;
case 'D':
destrootdir = strdup(optarg);
break;
case 'H':
arg_hmac = true;
break;
case 'h':
usage(EXIT_SUCCESS);
break;
default:
usage(EXIT_FAILURE);
}
}

if (!optind || optind == argc) {
usage(EXIT_FAILURE);
}

return 1;
}

static int resolve_lazy(int argc, char **argv)
{
int i;
int destrootdirlen = strlen(destrootdir);
int ret = 0;
char *item;
for (i = 0; i < argc; i++) {
const char *src = argv[i];
char *p = argv[i];
char *existing;

log_debug("resolve_deps('%s')", src);

if (strstr(src, destrootdir)) {
p = &argv[i][destrootdirlen];
}

existing = hashmap_get(items, p);
if (existing) {
if (strcmp(existing, p) == 0)
continue;
}

item = strdup(p);
hashmap_put(items, item, item);

ret += resolve_deps(src);
}
return ret;
}

static int install_all(int argc, char **argv)
{
int r = 0;
int i;
for (i = 0; i < argc; i++) {
int ret;
log_debug("Handle '%s'", argv[i]);

if (strchr(argv[i], '/') == NULL) {
char *path;
char *p, *q;
bool end = false;
path = getenv("PATH");
if (path == NULL) {
log_error("PATH is not set");
exit(EXIT_FAILURE);
}
path = strdup(path);
p = path;
log_debug("PATH=%s", path);
do {
char *newsrc = NULL;
char *dest;
struct stat sb;

for (q = p; *q && *q != ':'; q++) ;

if (*q == '\0')
end = true;
else
*q = '\0';

asprintf(&newsrc, "%s/%s", p, argv[i]);
p = q + 1;

if (stat(newsrc, &sb) != 0) {
free(newsrc);
ret = -1;
continue;
}

dest = strdup(newsrc);

log_debug("dracut_install '%s'", newsrc);
ret = dracut_install(newsrc, dest, arg_createdir, arg_resolvedeps);
if (ret == 0) {
end = true;
log_debug("dracut_install '%s' OK", newsrc);
}
free(newsrc);
free(dest);
} while (!end);
free(path);
} else {
char *dest = strdup(argv[i]);
ret = dracut_install(argv[i], dest, arg_createdir, arg_resolvedeps);
free(dest);
}

if ((ret != 0) && (!arg_optional)) {
log_error("ERROR: installing '%s'", argv[i]);
r = EXIT_FAILURE;
}
}
return r;
}

int main(int argc, char **argv)
{
int r;
char *i;

r = parse_argv(argc, argv);
if (r <= 0)
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;

log_set_target(LOG_TARGET_CONSOLE);
log_parse_environment();

if (arg_loglevel >= 0)
log_set_max_level(arg_loglevel);

log_open();

umask(0022);

if (destrootdir == NULL) {
destrootdir = getenv("DESTROOTDIR");
if (destrootdir == NULL) {
log_error("Environment DESTROOTDIR or argument -D is not set!");
usage(EXIT_FAILURE);
}
destrootdir = strdup(destrootdir);
}

items = hashmap_new(string_hash_func, string_compare_func);
items_failed = hashmap_new(string_hash_func, string_compare_func);

if (!items || !items_failed) {
log_error("Out of memory");
r = EXIT_FAILURE;
goto finish;
}

r = EXIT_SUCCESS;

if (((optind + 1) < argc) && (strcmp(argv[optind + 1], destrootdir) == 0)) {
/* ugly hack for compat mode "inst src $destrootdir" */
if ((optind + 2) == argc) {
argc--;
} else {
/* ugly hack for compat mode "inst src $destrootdir dst" */
if ((optind + 3) == argc) {
argc--;
argv[optind + 1] = argv[optind + 2];
}
}
}

if (arg_resolvelazy) {
r = resolve_lazy(argc - optind, &argv[optind]);
} else if (arg_all || (argc - optind > 2) || ((argc - optind) == 1)) {
r = install_all(argc - optind, &argv[optind]);
} else {
/* simple "inst src dst" */
r = dracut_install(argv[optind], argv[optind + 1], arg_createdir, arg_resolvedeps);
if ((r != 0) && (!arg_optional)) {
log_error("ERROR: installing '%s' to '%s'", argv[optind], argv[optind + 1]);
r = EXIT_FAILURE;
}
}

if (arg_optional)
r = EXIT_SUCCESS;

finish:

while ((i = hashmap_steal_first(items)))
item_free(i);

while ((i = hashmap_steal_first(items_failed)))
item_free(i);

hashmap_free(items);
hashmap_free(items_failed);

free(destrootdir);

return r;
}

731
install/hashmap.c

@ -0,0 +1,731 @@ @@ -0,0 +1,731 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

/***
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 <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "util.h"
#include "hashmap.h"
#include "macro.h"

#define NBUCKETS 127

struct hashmap_entry {
const void *key;
void *value;
struct hashmap_entry *bucket_next, *bucket_previous;
struct hashmap_entry *iterate_next, *iterate_previous;
};

struct Hashmap {
hash_func_t hash_func;
compare_func_t compare_func;

struct hashmap_entry *iterate_list_head, *iterate_list_tail;
unsigned n_entries;

bool from_pool;
};

#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap))))

struct pool {
struct pool *next;
unsigned n_tiles;
unsigned n_used;
};

static struct pool *first_hashmap_pool = NULL;
static void *first_hashmap_tile = NULL;

static struct pool *first_entry_pool = NULL;
static void *first_entry_tile = NULL;

static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size) {
unsigned i;

if (*first_tile) {
void *r;

r = *first_tile;
*first_tile = * (void**) (*first_tile);
return r;
}

if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) {
unsigned n;
size_t size;
struct pool *p;

n = *first_pool ? (*first_pool)->n_tiles : 0;
n = MAX(512U, n * 2);
size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size);
n = (size - ALIGN(sizeof(struct pool))) / tile_size;

p = malloc(size);
if (!p)
return NULL;

p->next = *first_pool;
p->n_tiles = n;
p->n_used = 0;

*first_pool = p;
}

i = (*first_pool)->n_used++;

return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size;
}

static void deallocate_tile(void **first_tile, void *p) {
* (void**) p = *first_tile;
*first_tile = p;
}

#ifndef __OPTIMIZE__

static void drop_pool(struct pool *p) {
while (p) {
struct pool *n;
n = p->next;
free(p);
p = n;
}
}

__attribute__((destructor)) static void cleanup_pool(void) {
/* Be nice to valgrind */

drop_pool(first_hashmap_pool);
drop_pool(first_entry_pool);
}

#endif

unsigned string_hash_func(const void *p) {
unsigned hash = 5381;
const signed char *c;

/* DJB's hash function */

for (c = p; *c; c++)
hash = (hash << 5) + hash + (unsigned) *c;

return hash;
}

int string_compare_func(const void *a, const void *b) {
return strcmp(a, b);
}

unsigned trivial_hash_func(const void *p) {
return PTR_TO_UINT(p);
}

int trivial_compare_func(const void *a, const void *b) {
return a < b ? -1 : (a > b ? 1 : 0);
}

Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) {
bool b;
Hashmap *h;
size_t size;

b = is_main_thread();

size = ALIGN(sizeof(Hashmap)) + NBUCKETS * sizeof(struct hashmap_entry*);

if (b) {
h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size);
if (!h)
return NULL;

memset(h, 0, size);
} else {
h = malloc0(size);

if (!h)
return NULL;
}

h->hash_func = hash_func ? hash_func : trivial_hash_func;
h->compare_func = compare_func ? compare_func : trivial_compare_func;

h->n_entries = 0;
h->iterate_list_head = h->iterate_list_tail = NULL;

h->from_pool = b;

return h;
}

int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) {
assert(h);

if (*h)
return 0;

if (!(*h = hashmap_new(hash_func, compare_func)))
return -ENOMEM;

return 0;
}

static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
assert(h);
assert(e);

/* Insert into hash table */
e->bucket_next = BY_HASH(h)[hash];
e->bucket_previous = NULL;
if (BY_HASH(h)[hash])
BY_HASH(h)[hash]->bucket_previous = e;
BY_HASH(h)[hash] = e;

/* Insert into iteration list */
e->iterate_previous = h->iterate_list_tail;
e->iterate_next = NULL;
if (h->iterate_list_tail) {
assert(h->iterate_list_head);
h->iterate_list_tail->iterate_next = e;
} else {
assert(!h->iterate_list_head);
h->iterate_list_head = e;
}
h->iterate_list_tail = e;

h->n_entries++;
assert(h->n_entries >= 1);
}

static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
assert(h);
assert(e);

/* Remove from iteration list */
if (e->iterate_next)
e->iterate_next->iterate_previous = e->iterate_previous;
else
h->iterate_list_tail = e->iterate_previous;

if (e->iterate_previous)
e->iterate_previous->iterate_next = e->iterate_next;
else
h->iterate_list_head = e->iterate_next;

/* Remove from hash table bucket list */
if (e->bucket_next)
e->bucket_next->bucket_previous = e->bucket_previous;

if (e->bucket_previous)
e->bucket_previous->bucket_next = e->bucket_next;
else
BY_HASH(h)[hash] = e->bucket_next;

assert(h->n_entries >= 1);
h->n_entries--;
}

static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
unsigned hash;

assert(h);
assert(e);

hash = h->hash_func(e->key) % NBUCKETS;

unlink_entry(h, e, hash);

if (h->from_pool)
deallocate_tile(&first_entry_tile, e);
else
free(e);
}

void hashmap_free(Hashmap*h) {

if (!h)
return;

hashmap_clear(h);

if (h->from_pool)
deallocate_tile(&first_hashmap_tile, h);
else
free(h);
}

void hashmap_free_free(Hashmap *h) {
void *p;

while ((p = hashmap_steal_first(h)))
free(p);

hashmap_free(h);
}

void hashmap_clear(Hashmap *h) {
if (!h)
return;

while (h->iterate_list_head)
remove_entry(h, h->iterate_list_head);
}

static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
struct hashmap_entry *e;
assert(h);
assert(hash < NBUCKETS);

for (e = BY_HASH(h)[hash]; e; e = e->bucket_next)
if (h->compare_func(e->key, key) == 0)
return e;

return NULL;
}

int hashmap_put(Hashmap *h, const void *key, void *value) {
struct hashmap_entry *e;
unsigned hash;

assert(h);

hash = h->hash_func(key) % NBUCKETS;

if ((e = hash_scan(h, hash, key))) {

if (e->value == value)
return 0;

return -EEXIST;
}

if (h->from_pool)
e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry));
else
e = new(struct hashmap_entry, 1);

if (!e)
return -ENOMEM;

e->key = key;
e->value = value;

link_entry(h, e, hash);

return 1;
}

int hashmap_replace(Hashmap *h, const void *key, void *value) {
struct hashmap_entry *e;
unsigned hash;

assert(h);

hash = h->hash_func(key) % NBUCKETS;

if ((e = hash_scan(h, hash, key))) {
e->key = key;
e->value = value;
return 0;
}

return hashmap_put(h, key, value);
}

void* hashmap_get(Hashmap *h, const void *key) {
unsigned hash;
struct hashmap_entry *e;

if (!h)
return NULL;

hash = h->hash_func(key) % NBUCKETS;

if (!(e = hash_scan(h, hash, key)))
return NULL;

return e->value;
}

void* hashmap_remove(Hashmap *h, const void *key) {
struct hashmap_entry *e;
unsigned hash;
void *data;

if (!h)
return NULL;

hash = h->hash_func(key) % NBUCKETS;

if (!(e = hash_scan(h, hash, key)))
return NULL;

data = e->value;
remove_entry(h, e);

return data;
}

int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
struct hashmap_entry *e;
unsigned old_hash, new_hash;

if (!h)
return -ENOENT;

old_hash = h->hash_func(old_key) % NBUCKETS;
if (!(e = hash_scan(h, old_hash, old_key)))
return -ENOENT;

new_hash = h->hash_func(new_key) % NBUCKETS;
if (hash_scan(h, new_hash, new_key))
return -EEXIST;

unlink_entry(h, e, old_hash);

e->key = new_key;
e->value = value;

link_entry(h, e, new_hash);

return 0;
}

int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
struct hashmap_entry *e, *k;
unsigned old_hash, new_hash;

if (!h)
return -ENOENT;

old_hash = h->hash_func(old_key) % NBUCKETS;
if (!(e = hash_scan(h, old_hash, old_key)))
return -ENOENT;

new_hash = h->hash_func(new_key) % NBUCKETS;

if ((k = hash_scan(h, new_hash, new_key)))
if (e != k)
remove_entry(h, k);

unlink_entry(h, e, old_hash);

e->key = new_key;
e->value = value;

link_entry(h, e, new_hash);

return 0;
}

void* hashmap_remove_value(Hashmap *h, const void *key, void *value) {
struct hashmap_entry *e;
unsigned hash;

if (!h)
return NULL;

hash = h->hash_func(key) % NBUCKETS;

if (!(e = hash_scan(h, hash, key)))
return NULL;

if (e->value != value)
return NULL;

remove_entry(h, e);

return value;
}

void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
struct hashmap_entry *e;

assert(i);

if (!h)
goto at_end;

if (*i == ITERATOR_LAST)
goto at_end;

if (*i == ITERATOR_FIRST && !h->iterate_list_head)
goto at_end;

e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i;

if (e->iterate_next)
*i = (Iterator) e->iterate_next;
else
*i = ITERATOR_LAST;

if (key)
*key = e->key;

return e->value;

at_end:
*i = ITERATOR_LAST;

if (key)
*key = NULL;

return NULL;
}

void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) {
struct hashmap_entry *e;

assert(i);

if (!h)
goto at_beginning;

if (*i == ITERATOR_FIRST)
goto at_beginning;

if (*i == ITERATOR_LAST && !h->iterate_list_tail)
goto at_beginning;

e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i;

if (e->iterate_previous)
*i = (Iterator) e->iterate_previous;
else
*i = ITERATOR_FIRST;

if (key)
*key = e->key;

return e->value;

at_beginning:
*i = ITERATOR_FIRST;

if (key)
*key = NULL;

return NULL;
}

void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) {
unsigned hash;
struct hashmap_entry *e;

if (!h)
return NULL;

hash = h->hash_func(key) % NBUCKETS;

if (!(e = hash_scan(h, hash, key)))
return NULL;

*i = (Iterator) e;

return e->value;
}

void* hashmap_first(Hashmap *h) {

if (!h)
return NULL;

if (!h->iterate_list_head)
return NULL;

return h->iterate_list_head->value;
}

void* hashmap_first_key(Hashmap *h) {

if (!h)
return NULL;

if (!h->iterate_list_head)
return NULL;

return (void*) h->iterate_list_head->key;
}

void* hashmap_last(Hashmap *h) {

if (!h)
return NULL;

if (!h->iterate_list_tail)
return NULL;

return h->iterate_list_tail->value;
}

void* hashmap_steal_first(Hashmap *h) {
void *data;

if (!h)
return NULL;

if (!h->iterate_list_head)
return NULL;

data = h->iterate_list_head->value;
remove_entry(h, h->iterate_list_head);

return data;
}

void* hashmap_steal_first_key(Hashmap *h) {
void *key;

if (!h)
return NULL;

if (!h->iterate_list_head)
return NULL;

key = (void*) h->iterate_list_head->key;
remove_entry(h, h->iterate_list_head);

return key;
}

unsigned hashmap_size(Hashmap *h) {

if (!h)
return 0;

return h->n_entries;
}

bool hashmap_isempty(Hashmap *h) {

if (!h)
return true;

return h->n_entries == 0;
}

int hashmap_merge(Hashmap *h, Hashmap *other) {
struct hashmap_entry *e;

assert(h);

if (!other)
return 0;

for (e = other->iterate_list_head; e; e = e->iterate_next) {
int r;

if ((r = hashmap_put(h, e->key, e->value)) < 0)
if (r != -EEXIST)
return r;
}

return 0;
}

void hashmap_move(Hashmap *h, Hashmap *other) {
struct hashmap_entry *e, *n;

assert(h);

/* The same as hashmap_merge(), but every new item from other
* is moved to h. This function is guaranteed to succeed. */

if (!other)
return;

for (e = other->iterate_list_head; e; e = n) {
unsigned h_hash, other_hash;

n = e->iterate_next;

h_hash = h->hash_func(e->key) % NBUCKETS;

if (hash_scan(h, h_hash, e->key))
continue;

other_hash = other->hash_func(e->key) % NBUCKETS;

unlink_entry(other, e, other_hash);
link_entry(h, e, h_hash);
}
}

int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
unsigned h_hash, other_hash;
struct hashmap_entry *e;

if (!other)
return 0;

assert(h);

h_hash = h->hash_func(key) % NBUCKETS;
if (hash_scan(h, h_hash, key))
return -EEXIST;

other_hash = other->hash_func(key) % NBUCKETS;
if (!(e = hash_scan(other, other_hash, key)))
return -ENOENT;

unlink_entry(other, e, other_hash);
link_entry(h, e, h_hash);

return 0;
}

Hashmap *hashmap_copy(Hashmap *h) {
Hashmap *copy;

assert(h);

if (!(copy = hashmap_new(h->hash_func, h->compare_func)))
return NULL;

if (hashmap_merge(copy, h) < 0) {
hashmap_free(copy);
return NULL;
}

return copy;
}

char **hashmap_get_strv(Hashmap *h) {
char **sv;
Iterator it;
char *item;
int n;

sv = new(char*, h->n_entries+1);
if (!sv)
return NULL;

n = 0;
HASHMAP_FOREACH(item, h, it)
sv[n++] = item;
sv[n] = NULL;

return sv;
}

91
install/hashmap.h

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

#ifndef foohashmaphfoo
#define foohashmaphfoo

/***
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 <stdbool.h>

/* Pretty straightforward hash table implementation. As a minor
* optimization a NULL hashmap object will be treated as empty hashmap
* for all read operations. That way it is not necessary to
* instantiate an object for each Hashmap use. */

typedef struct Hashmap Hashmap;
typedef struct _IteratorStruct _IteratorStruct;
typedef _IteratorStruct* Iterator;

#define ITERATOR_FIRST ((Iterator) 0)
#define ITERATOR_LAST ((Iterator) -1)

typedef unsigned (*hash_func_t)(const void *p);
typedef int (*compare_func_t)(const void *a, const void *b);

unsigned string_hash_func(const void *p);
int string_compare_func(const void *a, const void *b);

unsigned trivial_hash_func(const void *p);
int trivial_compare_func(const void *a, const void *b);

Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
void hashmap_free(Hashmap *h);
void hashmap_free_free(Hashmap *h);
Hashmap *hashmap_copy(Hashmap *h);
int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);

int hashmap_put(Hashmap *h, const void *key, void *value);
int hashmap_replace(Hashmap *h, const void *key, void *value);
void* hashmap_get(Hashmap *h, const void *key);
void* hashmap_remove(Hashmap *h, const void *key);
void* hashmap_remove_value(Hashmap *h, const void *key, void *value);
int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);

int hashmap_merge(Hashmap *h, Hashmap *other);
void hashmap_move(Hashmap *h, Hashmap *other);
int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key);

unsigned hashmap_size(Hashmap *h);
bool hashmap_isempty(Hashmap *h);

void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key);
void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key);
void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i);

void hashmap_clear(Hashmap *h);
void *hashmap_steal_first(Hashmap *h);
void *hashmap_steal_first_key(Hashmap *h);
void* hashmap_first(Hashmap *h);
void* hashmap_first_key(Hashmap *h);
void* hashmap_last(Hashmap *h);

char **hashmap_get_strv(Hashmap *h);

#define HASHMAP_FOREACH(e, h, i) \
for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL))

#define HASHMAP_FOREACH_KEY(e, k, h, i) \
for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k)))

#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \
for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL))

#endif

12
install/hashmap.lo

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
# src/shared/hashmap.lo - a libtool object file
# Generated by libtool (GNU libtool) 2.4.2
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# Name of the PIC object.
pic_object='.libs/hashmap.o'

# Name of the non-PIC object
non_pic_object='hashmap.o'

BIN
install/hashmap.o

Binary file not shown.

294
install/log.c

@ -0,0 +1,294 @@ @@ -0,0 +1,294 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

/***
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 <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>

#include "log.h"
#include "util.h"
#include "macro.h"

#define SNDBUF_SIZE (8*1024*1024)

static LogTarget log_target = LOG_TARGET_CONSOLE;
static int log_max_level = LOG_WARNING;
static int log_facility = LOG_DAEMON;

static int console_fd = STDERR_FILENO;

static bool show_location = false;

/* Akin to glibc's __abort_msg; which is private and we hence cannot
* use here. */
static char *log_abort_msg = NULL;

void log_close_console(void) {

if (console_fd < 0)
return;

if (getpid() == 1) {
if (console_fd >= 3)
close_nointr_nofail(console_fd);

console_fd = -1;
}
}

static int log_open_console(void) {

if (console_fd >= 0)
return 0;

if (getpid() == 1) {

console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (console_fd < 0) {
log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
return console_fd;
}

log_debug("Successfully opened /dev/console for logging.");
} else
console_fd = STDERR_FILENO;

return 0;
}


int log_open(void) {
return log_open_console();
}


void log_close(void) {
log_close_console();
}


void log_set_max_level(int level) {
assert((level & LOG_PRIMASK) == level);

log_max_level = level;
}

void log_set_facility(int facility) {
log_facility = facility;
}

static int write_to_console(
int level,
const char*file,
int line,
const char *func,
const char *buffer) {

char location[64];
struct iovec iovec[5];
unsigned n = 0;

if (console_fd < 0)
return 0;

zero(iovec);

IOVEC_SET_STRING(iovec[n++], "dracut-install: ");

if (show_location) {
snprintf(location, sizeof(location), "(%s:%u) ", file, line);
IOVEC_SET_STRING(iovec[n++], location);
}

IOVEC_SET_STRING(iovec[n++], buffer);
IOVEC_SET_STRING(iovec[n++], "\n");

if (writev(console_fd, iovec, n) < 0)
return -errno;

return 1;
}

static int log_dispatch(
int level,
const char*file,
int line,
const char *func,
char *buffer) {

int r = 0;

if (log_target == LOG_TARGET_NULL)
return 0;

/* Patch in LOG_DAEMON facility if necessary */
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);

do {
char *e;
int k = 0;

buffer += strspn(buffer, NEWLINE);

if (buffer[0] == 0)
break;

if ((e = strpbrk(buffer, NEWLINE)))
*(e++) = 0;

k = write_to_console(level, file, line, func, buffer);
if (k < 0)
return k;
buffer = e;
} while (buffer);

return r;
}

int log_metav(
int level,
const char*file,
int line,
const char *func,
const char *format,
va_list ap) {

char buffer[LINE_MAX];
int saved_errno, r;

if (_likely_(LOG_PRI(level) > log_max_level))
return 0;

saved_errno = errno;
vsnprintf(buffer, sizeof(buffer), format, ap);
char_array_0(buffer);

r = log_dispatch(level, file, line, func, buffer);
errno = saved_errno;

return r;
}

int log_meta(
int level,
const char*file,
int line,
const char *func,
const char *format, ...) {

int r;
va_list ap;

va_start(ap, format);
r = log_metav(level, file, line, func, format, ap);
va_end(ap);

return r;
}

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
_noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
static char buffer[LINE_MAX];

snprintf(buffer, sizeof(buffer), format, text, file, line, func);

char_array_0(buffer);
log_abort_msg = buffer;

log_dispatch(LOG_CRIT, file, line, func, buffer);
abort();
}
#pragma GCC diagnostic pop

_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
}

_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
}

void log_set_target(LogTarget target) {
assert(target >= 0);
assert(target < _LOG_TARGET_MAX);

log_target = target;
}

int log_set_target_from_string(const char *e) {
LogTarget t;

t = log_target_from_string(e);
if (t < 0)
return -EINVAL;

log_set_target(t);
return 0;
}

int log_set_max_level_from_string(const char *e) {
int t;

t = log_level_from_string(e);
if (t < 0)
return t;

log_set_max_level(t);
return 0;
}

void log_parse_environment(void) {
const char *e;

if ((e = getenv("DRACUT_LOG_TARGET")))
if (log_set_target_from_string(e) < 0)
log_warning("Failed to parse log target %s. Ignoring.", e);

if ((e = getenv("DRACUT_LOG_LEVEL")))
if (log_set_max_level_from_string(e) < 0)
log_warning("Failed to parse log level %s. Ignoring.", e);

}

LogTarget log_get_target(void) {
return log_target;
}

int log_get_max_level(void) {
return log_max_level;
}


static const char *const log_target_table[] = {
[LOG_TARGET_CONSOLE] = "console",
[LOG_TARGET_AUTO] = "auto",
[LOG_TARGET_SAFE] = "safe",
[LOG_TARGET_NULL] = "null"
};

DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);

115
install/log.h

@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

#ifndef foologhfoo
#define foologhfoo

/***
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 <syslog.h>
#include <stdbool.h>
#include <stdarg.h>

#include "macro.h"

typedef enum LogTarget{
LOG_TARGET_CONSOLE,
LOG_TARGET_KMSG,
LOG_TARGET_JOURNAL,
LOG_TARGET_JOURNAL_OR_KMSG,
LOG_TARGET_SYSLOG,
LOG_TARGET_SYSLOG_OR_KMSG,
LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */
LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */
LOG_TARGET_NULL,
_LOG_TARGET_MAX,
_LOG_TARGET_INVALID = -1
} LogTarget;

void log_set_target(LogTarget target);
void log_set_max_level(int level);
void log_set_facility(int facility);

int log_set_target_from_string(const char *e);
int log_set_max_level_from_string(const char *e);

void log_show_color(bool b);
void log_show_location(bool b);

int log_show_color_from_string(const char *e);
int log_show_location_from_string(const char *e);

LogTarget log_get_target(void);
int log_get_max_level(void);

int log_open(void);
void log_close(void);
void log_forget_fds(void);

void log_close_syslog(void);
void log_close_journal(void);
void log_close_kmsg(void);
void log_close_console(void);

void log_parse_environment(void);

int log_meta(
int level,
const char*file,
int line,
const char *func,
const char *format, ...) _printf_attr_(5,6);

int log_metav(
int level,
const char*file,
int line,
const char *func,
const char *format,
va_list ap);

_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func);
_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func);

/* This modifies the buffer passed! */
int log_dump_internal(
int level,
const char*file,
int line,
const char *func,
char *buffer);

#define log_full(level, ...) log_meta(level, __FILE__, __LINE__, __func__, __VA_ARGS__)

#define log_debug(...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_info(...) log_meta(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_notice(...) log_meta(LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_error(...) log_meta(LOG_ERR, __FILE__, __LINE__, __func__, __VA_ARGS__)

/* This modifies the buffer passed! */
#define log_dump(level, buffer) log_dump_internal(level, __FILE__, __LINE__, __func__, buffer)

const char *log_target_to_string(LogTarget target);
LogTarget log_target_from_string(const char *s);

const char *log_level_to_string(int i);
int log_level_from_string(const char *s);

#endif

192
install/macro.h

@ -0,0 +1,192 @@ @@ -0,0 +1,192 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

#ifndef foomacrohfoo
#define foomacrohfoo

/***
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 <assert.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <inttypes.h>

#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
#define _sentinel_ __attribute__ ((sentinel))
#define _noreturn_ __attribute__((noreturn))
#define _unused_ __attribute__ ((unused))
#define _destructor_ __attribute__ ((destructor))
#define _pure_ __attribute__ ((pure))
#define _const_ __attribute__ ((const))
#define _deprecated_ __attribute__ ((deprecated))
#define _packed_ __attribute__ ((packed))
#define _malloc_ __attribute__ ((malloc))
#define _weak_ __attribute__ ((weak))
#define _likely_(x) (__builtin_expect(!!(x),1))
#define _unlikely_(x) (__builtin_expect(!!(x),0))
#define _public_ __attribute__ ((visibility("default")))
#define _hidden_ __attribute__ ((visibility("hidden")))
#define _weakref_(x) __attribute__((weakref(#x)))
#define _introspect_(x) __attribute__((section("introspect." x)))

#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)

/* Rounds up */
#define ALIGN(l) ALIGN_TO((l), sizeof(void*))
static inline size_t ALIGN_TO(size_t l, size_t ali) {
return ((l + ali - 1) & ~(ali - 1));
}

#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))

/*
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

#ifndef MAX
#define MAX(a,b) \
__extension__ ({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a > _b ? _a : _b; \
})
#endif

#define MAX3(a,b,c) \
MAX(MAX(a,b),c)

#ifndef MIN
#define MIN(a,b) \
__extension__ ({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a < _b ? _a : _b; \
})
#endif

#define MIN3(a,b,c) \
MIN(MIN(a,b),c)

#define CLAMP(x, low, high) \
__extension__ ({ \
typeof(x) _x = (x); \
typeof(low) _low = (low); \
typeof(high) _high = (high); \
((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
})

#define assert_se(expr) \
do { \
if (_unlikely_(!(expr))) \
log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
} while (false) \

/* We override the glibc assert() here. */
#undef assert
#ifdef NDEBUG
#define assert(expr) do {} while(false)
#else
#define assert(expr) assert_se(expr)
#endif

#define assert_not_reached(t) \
do { \
log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
} while (false)

#define assert_cc(expr) \
do { \
switch (0) { \
case 0: \
case !!(expr): \
; \
} \
} while (false)

#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
#define UINT_TO_PTR(u) ((void*) ((uintptr_t) (u)))

#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
#define UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u)))

#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p)))
#define ULONG_TO_PTR(u) ((void*) ((uintptr_t) (u)))

#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define INT_TO_PTR(u) ((void*) ((intptr_t) (u)))

#define TO_INT32(p) ((int32_t) ((intptr_t) (p)))
#define INT32_TO_PTR(u) ((void*) ((intptr_t) (u)))

#define PTR_TO_LONG(p) ((long) ((intptr_t) (p)))
#define LONG_TO_PTR(u) ((void*) ((intptr_t) (u)))

#define memzero(x,l) (memset((x), 0, (l)))
#define zero(x) (memzero(&(x), sizeof(x)))

#define char_array_0(x) x[sizeof(x)-1] = 0;

#define IOVEC_SET_STRING(i, s) \
do { \
struct iovec *_i = &(i); \
char *_s = (char *)(s); \
_i->iov_base = _s; \
_i->iov_len = strlen(_s); \
} while(false)

static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
size_t r = 0;

for (j = 0; j < n; j++)
r += i[j].iov_len;

return r;
}

static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
unsigned j;

for (j = 0; j < n; j++) {
size_t sub;

if (_unlikely_(k <= 0))
break;

sub = MIN(i[j].iov_len, k);
i[j].iov_len -= sub;
i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
k -= sub;
}

return k;
}

#include "log.h"

#endif

187
install/util.c

@ -0,0 +1,187 @@ @@ -0,0 +1,187 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

/***
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 <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/syscall.h>

#include "util.h"

static inline pid_t gettid(void) {
return (pid_t) syscall(SYS_gettid);
}

size_t page_size(void) {
static __thread size_t pgsz = 0;
long r;

if (_likely_(pgsz > 0))
return pgsz;

assert_se((r = sysconf(_SC_PAGESIZE)) > 0);

pgsz = (size_t) r;

return pgsz;
}

bool endswith(const char *s, const char *postfix) {
size_t sl, pl;

assert(s);
assert(postfix);

sl = strlen(s);
pl = strlen(postfix);

if (pl == 0)
return true;

if (sl < pl)
return false;

return memcmp(s + sl - pl, postfix, pl) == 0;
}
int close_nointr(int fd) {
assert(fd >= 0);

for (;;) {
int r;

r = close(fd);
if (r >= 0)
return r;

if (errno != EINTR)
return -errno;
}
}

void close_nointr_nofail(int fd) {
int saved_errno = errno;

/* like close_nointr() but cannot fail, and guarantees errno
* is unchanged */

assert_se(close_nointr(fd) == 0);

errno = saved_errno;
}

int open_terminal(const char *name, int mode) {
int fd, r;
unsigned c = 0;

/*
* If a TTY is in the process of being closed opening it might
* cause EIO. This is horribly awful, but unlikely to be
* changed in the kernel. Hence we work around this problem by
* retrying a couple of times.
*
* https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
*/

for (;;) {
if ((fd = open(name, mode)) >= 0)
break;

if (errno != EIO)
return -errno;

if (c >= 20)
return -errno;

usleep(50 * USEC_PER_MSEC);
c++;
}

if (fd < 0)
return -errno;

if ((r = isatty(fd)) < 0) {
close_nointr_nofail(fd);
return -errno;
}

if (!r) {
close_nointr_nofail(fd);
return -ENOTTY;
}

return fd;
}

bool streq_ptr(const char *a, const char *b) {

/* Like streq(), but tries to make sense of NULL pointers */

if (a && b)
return streq(a, b);

if (!a && !b)
return true;

return false;
}
bool is_main_thread(void) {
static __thread int cached = 0;

if (_unlikely_(cached == 0))
cached = getpid() == gettid() ? 1 : -1;

return cached > 0;
}

int safe_atou(const char *s, unsigned *ret_u) {
char *x = NULL;
unsigned long l;

assert(s);
assert(ret_u);

errno = 0;
l = strtoul(s, &x, 0);

if (!x || *x || errno)
return errno ? -errno : -EINVAL;

if ((unsigned long) (unsigned) l != l)
return -ERANGE;

*ret_u = (unsigned) l;
return 0;
}

static const char *const log_level_table[] = {
[LOG_EMERG] = "emerg",
[LOG_ALERT] = "alert",
[LOG_CRIT] = "crit",
[LOG_ERR] = "err",
[LOG_WARNING] = "warning",
[LOG_NOTICE] = "notice",
[LOG_INFO] = "info",
[LOG_DEBUG] = "debug"
};

DEFINE_STRING_TABLE_LOOKUP(log_level, int);

527
install/util.h

@ -0,0 +1,527 @@ @@ -0,0 +1,527 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/

#ifndef fooutilhfoo
#define fooutilhfoo

/***
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 <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sched.h>
#include <limits.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/resource.h>

#include "macro.h"

typedef uint64_t usec_t;
typedef uint64_t nsec_t;

typedef struct dual_timestamp {
usec_t realtime;
usec_t monotonic;
} dual_timestamp;

#define MSEC_PER_SEC 1000ULL
#define USEC_PER_SEC 1000000ULL
#define USEC_PER_MSEC 1000ULL
#define NSEC_PER_SEC 1000000000ULL
#define NSEC_PER_MSEC 1000000ULL
#define NSEC_PER_USEC 1000ULL

#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC)
#define NSEC_PER_MINUTE (60ULL*NSEC_PER_SEC)
#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE)
#define NSEC_PER_HOUR (60ULL*NSEC_PER_MINUTE)
#define USEC_PER_DAY (24ULL*USEC_PER_HOUR)
#define NSEC_PER_DAY (24ULL*NSEC_PER_HOUR)
#define USEC_PER_WEEK (7ULL*USEC_PER_DAY)
#define NSEC_PER_WEEK (7ULL*NSEC_PER_DAY)
#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC)
#define NSEC_PER_MONTH (2629800ULL*NSEC_PER_SEC)
#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC)
#define NSEC_PER_YEAR (31557600ULL*NSEC_PER_SEC)

/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
#define NEWLINE "\n\r"
#define QUOTES "\"\'"
#define COMMENTS "#;\n"

#define FORMAT_TIMESTAMP_MAX 64
#define FORMAT_TIMESTAMP_PRETTY_MAX 256
#define FORMAT_TIMESPAN_MAX 64
#define FORMAT_BYTES_MAX 8

#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
#define ANSI_HIGHLIGHT_OFF "\x1B[0m"

usec_t now(clockid_t clock);

dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);

#define dual_timestamp_is_set(ts) ((ts)->realtime > 0)

usec_t timespec_load(const struct timespec *ts);
struct timespec *timespec_store(struct timespec *ts, usec_t u);

usec_t timeval_load(const struct timeval *tv);
struct timeval *timeval_store(struct timeval *tv, usec_t u);

size_t page_size(void);
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())

#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)

bool streq_ptr(const char *a, const char *b);

#define new(t, n) ((t*) malloc(sizeof(t)*(n)))

#define new0(t, n) ((t*) calloc((n), sizeof(t)))

#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))

#define newdup(t, p, n) ((t*) memdup(p, sizeof(t)*(n)))

#define malloc0(n) (calloc((n), 1))

static inline const char* yes_no(bool b) {
return b ? "yes" : "no";
}

static inline const char* strempty(const char *s) {
return s ? s : "";
}

static inline const char* strnull(const char *s) {
return s ? s : "(null)";
}

static inline const char *strna(const char *s) {
return s ? s : "n/a";
}

static inline bool isempty(const char *p) {
return !p || !p[0];
}

bool endswith(const char *s, const char *postfix);
bool startswith(const char *s, const char *prefix);
bool startswith_no_case(const char *s, const char *prefix);

bool first_word(const char *s, const char *word);

int close_nointr(int fd);
void close_nointr_nofail(int fd);
void close_many(const int fds[], unsigned n_fd);

int parse_boolean(const char *v);
int parse_usec(const char *t, usec_t *usec);
int parse_nsec(const char *t, nsec_t *nsec);
int parse_bytes(const char *t, off_t *bytes);
int parse_pid(const char *s, pid_t* ret_pid);
int parse_uid(const char *s, uid_t* ret_uid);
#define parse_gid(s, ret_uid) parse_uid(s, ret_uid)

int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);

int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);

#if __WORDSIZE == 32
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));
return safe_atou(s, (unsigned*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(int));
return safe_atoi(s, (int*) ret_u);
}
#else
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(long long int));
return safe_atolli(s, (long long int*) ret_u);
}
#endif

static inline int safe_atou32(const char *s, uint32_t *ret_u) {
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
return safe_atou(s, (unsigned*) ret_u);
}

static inline int safe_atoi32(const char *s, int32_t *ret_i) {
assert_cc(sizeof(int32_t) == sizeof(int));
return safe_atoi(s, (int*) ret_i);
}

static inline int safe_atou64(const char *s, uint64_t *ret_u) {
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
}

static inline int safe_atoi64(const char *s, int64_t *ret_i) {
assert_cc(sizeof(int64_t) == sizeof(long long int));
return safe_atolli(s, (long long int*) ret_i);
}

char *split(const char *c, size_t *l, const char *separator, char **state);
char *split_quoted(const char *c, size_t *l, char **state);

#define FOREACH_WORD(word, length, s, state) \
for ((state) = NULL, (word) = split((s), &(length), WHITESPACE, &(state)); (word); (word) = split((s), &(length), WHITESPACE, &(state)))

#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state)))

#define FOREACH_WORD_QUOTED(word, length, s, state) \
for ((state) = NULL, (word) = split_quoted((s), &(length), &(state)); (word); (word) = split_quoted((s), &(length), &(state)))

pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
int get_starttime_of_pid(pid_t pid, unsigned long long *st);

int write_one_line_file(const char *fn, const char *line);
int write_one_line_file_atomic(const char *fn, const char *line);
int read_one_line_file(const char *fn, char **line);
int read_full_file(const char *fn, char **contents, size_t *size);

int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
int load_env_file(const char *fname, char ***l);
int write_env_file(const char *fname, char **l);

char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);

char *replace_env(const char *format, char **env);
char **replace_env_argv(char **argv, char **env);

int readlink_malloc(const char *p, char **r);
int readlink_and_make_absolute(const char *p, char **r);
int readlink_and_canonicalize(const char *p, char **r);

int reset_all_signal_handlers(void);

char *strstrip(char *s);
char *delete_chars(char *s, const char *bad);
char *truncate_nl(char *s);

char *file_in_same_dir(const char *path, const char *filename);

int rmdir_parents(const char *path, const char *stop);

int get_process_comm(pid_t pid, char **name);
int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
int get_process_exe(pid_t pid, char **name);
int get_process_uid(pid_t pid, uid_t *uid);

char hexchar(int x);
int unhexchar(char c);
char octchar(int x);
int unoctchar(char c);
char decchar(int x);
int undecchar(char c);

char *cescape(const char *s);
char *cunescape(const char *s);
char *cunescape_length(const char *s, size_t length);

char *xescape(const char *s, const char *bad);

char *bus_path_escape(const char *s);
char *bus_path_unescape(const char *s);

char *ascii_strlower(char *path);

bool dirent_is_file(const struct dirent *de);
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix);

bool ignore_file(const char *filename);

bool chars_intersect(const char *a, const char *b);

char *format_timestamp(char *buf, size_t l, usec_t t);
char *format_timestamp_pretty(char *buf, size_t l, usec_t t);
char *format_timespan(char *buf, size_t l, usec_t t);

int make_stdio(int fd);
int make_null_stdio(void);

unsigned long long random_ull(void);

#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
scope const char *name##_to_string(type i) { \
if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
return NULL; \
return name##_table[i]; \
} \
scope type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
assert(s); \
for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
if (name##_table[i] && \
streq(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && \
u < ELEMENTSOF(name##_table)) \
return (type) u; \
return (type) -1; \
} \
struct __useless_struct_to_allow_trailing_semicolon__

#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static)

int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);

int close_all_fds(const int except[], unsigned n_except);

bool fstype_is_network(const char *fstype);

int chvt(int vt);

int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
int ask(char *ret, const char *replies, const char *text, ...);

int reset_terminal_fd(int fd, bool switch_to_text);
int reset_terminal(const char *name);

int open_terminal(const char *name, int mode);
int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm);
int release_terminal(void);

int flush_fd(int fd);

int ignore_signals(int sig, ...);
int default_signals(int sig, ...);
int sigaction_many(const struct sigaction *sa, ...);

int close_pipe(int p[]);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);

ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);

bool is_device_path(const char *path);

int dir_is_empty(const char *path);

void rename_process(const char name[8]);

void sigset_add_many(sigset_t *ss, ...);

char* gethostname_malloc(void);
bool hostname_is_set(void);
char* getlogname_malloc(void);

int getttyname_malloc(int fd, char **r);
int getttyname_harder(int fd, char **r);

int get_ctty_devnr(pid_t pid, dev_t *d);
int get_ctty(pid_t, dev_t *_devnr, char **r);

int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);

int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);

int pipe_eof(int fd);

cpu_set_t* cpu_set_malloc(unsigned *ncpus);

void status_vprintf(const char *status, bool ellipse, const char *format, va_list ap);
void status_printf(const char *status, bool ellipse, const char *format, ...);
void status_welcome(void);

int fd_columns(int fd);
unsigned columns(void);

int fd_lines(int fd);
unsigned lines(void);

int running_in_chroot(void);

char *ellipsize(const char *s, size_t length, unsigned percent);
char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent);

int touch(const char *path);

char *unquote(const char *s, const char *quotes);
char *normalize_env_assignment(const char *s);

int wait_for_terminate(pid_t pid, siginfo_t *status);
int wait_for_terminate_and_warn(const char *name, pid_t pid);

_noreturn_ void freeze(void);

bool null_or_empty(struct stat *st);
int null_or_empty_path(const char *fn);

DIR *xopendirat(int dirfd, const char *name, int flags);

void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
void dual_timestamp_deserialize(const char *value, dual_timestamp *t);

char *fstab_node_to_udev_node(const char *p);

bool tty_is_vc(const char *tty);
bool tty_is_vc_resolve(const char *tty);
bool tty_is_console(const char *tty);
int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);

void execute_directory(const char *directory, DIR *_d, char *argv[]);

int kill_and_sigcont(pid_t pid, int sig);

bool nulstr_contains(const char*nulstr, const char *needle);

bool plymouth_running(void);

void parse_syslog_priority(char **p, int *priority);
void skip_syslog_pid(char **buf);
void skip_syslog_date(char **buf);

bool hostname_is_valid(const char *s);
char* hostname_cleanup(char *s);

char* strshorten(char *s, size_t l);

int terminal_vhangup_fd(int fd);
int terminal_vhangup(const char *name);

int vt_disallocate(const char *name);

int copy_file(const char *from, const char *to);
int symlink_or_copy(const char *from, const char *to);
int symlink_or_copy_atomic(const char *from, const char *to);

int fchmod_umask(int fd, mode_t mode);

bool display_is_local(const char *display);
int socket_from_display(const char *display, char **path);

int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home);
int get_group_creds(const char **groupname, gid_t *gid);

int in_group(const char *name);

int glob_exists(const char *path);

int dirent_ensure_type(DIR *d, struct dirent *de);

int in_search_path(const char *path, char **search);
int get_files_in_directory(const char *path, char ***list);

char *join(const char *x, ...) _sentinel_;

bool is_main_thread(void);

bool in_charset(const char *s, const char* charset);

int block_get_whole_disk(dev_t d, dev_t *ret);

int file_is_priv_sticky(const char *p);

int strdup_or_null(const char *a, char **b);

#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))

const char *ioprio_class_to_string(int i);
int ioprio_class_from_string(const char *s);

const char *sigchld_code_to_string(int i);
int sigchld_code_from_string(const char *s);

const char *log_facility_unshifted_to_string(int i);
int log_facility_unshifted_from_string(const char *s);

const char *log_level_to_string(int i);
int log_level_from_string(const char *s);

const char *sched_policy_to_string(int i);
int sched_policy_from_string(const char *s);

const char *rlimit_to_string(int i);
int rlimit_from_string(const char *s);

const char *ip_tos_to_string(int i);
int ip_tos_from_string(const char *s);

const char *signal_to_string(int i);
int signal_from_string(const char *s);

int signal_from_string_try_harder(const char *s);

extern int saved_argc;
extern char **saved_argv;

bool kexec_loaded(void);

int prot_from_flags(int flags);

char *format_bytes(char *buf, size_t l, off_t t);

int fd_wait_for_event(int fd, int event, usec_t timeout);

void* memdup(const void *p, size_t l);

int is_kernel_thread(pid_t pid);

int fd_inc_sndbuf(int fd, size_t n);
int fd_inc_rcvbuf(int fd, size_t n);

int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);

int setrlimit_closest(int resource, const struct rlimit *rlim);

int getenv_for_pid(pid_t pid, const char *field, char **_value);

int can_sleep(const char *type);

bool is_valid_documentation_url(const char *url);

bool in_initrd(void);

void warn_melody(void);

#endif
Loading…
Cancel
Save