install: install all PATH binaries found

This should fix the issues with symlinks in /bin pointing to /usr/bin on
some distributions.
master
Harald Hoyer 2013-12-19 16:59:46 +01:00
parent 3aa35b727f
commit 2f461da2a0
6 changed files with 1007 additions and 45 deletions

View File

@ -47,6 +47,7 @@ DRACUT_INSTALL_OBJECTS = \
install/dracut-install.o \
install/hashmap.o\
install/log.o \
install/strv.o \
install/util.o

# deps generated with gcc -MM
@ -56,6 +57,7 @@ install/hashmap.o: install/hashmap.c install/util.h install/macro.h install/log.
install/hashmap.h
install/log.o: install/log.c install/log.h install/macro.h install/util.h
install/util.o: install/util.c install/util.h install/macro.h install/log.h
install/strv.o: install/strv.c install/strv.h install/util.h install/macro.h install/log.h

install/dracut-install: $(DRACUT_INSTALL_OBJECTS)


View File

@ -44,6 +44,7 @@
#include "log.h"
#include "hashmap.h"
#include "util.h"
#include "strv.h"

static bool arg_hmac = false;
static bool arg_createdir = false;
@ -784,13 +785,13 @@ static int resolve_lazy(int argc, char **argv)
return ret;
}

static char *find_binary(const char *src)
static char **find_binary(const char *src)
{
_cleanup_free_ char *path = NULL;
char *p, *q;
bool end = false;
char *path = NULL;
_cleanup_strv_free_ char **p = NULL;
char **ret = NULL;
char **q;
char *newsrc = NULL;
int ret;

path = getenv("PATH");

@ -798,34 +799,21 @@ static char *find_binary(const char *src)
log_error("PATH is not set");
exit(EXIT_FAILURE);
}
path = strdup(path);
p = path;

if (path == NULL) {
log_error("Out of memory!");
exit(EXIT_FAILURE);
}

log_debug("PATH=%s", path);

do {
p = strv_split(path, ":");

STRV_FOREACH(q, p) {
struct stat sb;
int r;

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

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

ret = asprintf(&newsrc, "%s/%s", p, src);
if (ret < 0) {
r = asprintf(&newsrc, "%s/%s", *q, src);
if (r < 0) {
log_error("Out of memory!");
exit(EXIT_FAILURE);
}

p = q + 1;

if (stat(newsrc, &sb) != 0) {
log_debug("stat(%s) != 0", newsrc);
free(newsrc);
@ -833,30 +821,37 @@ static char *find_binary(const char *src)
continue;
}

end = true;
strv_push(&ret, newsrc);

} while (!end);
};

if (newsrc)
log_debug("find_binary(%s) == %s", src, newsrc);
if (ret) {
STRV_FOREACH(q, ret) {
log_debug("find_binary(%s) == %s", src, *q);
}
}

return newsrc;
return ret;
}

static int install_one(const char *src, const char *dst)
{
int r = EXIT_SUCCESS;
int ret;
int ret = 0;

if (strchr(src, '/') == NULL) {
char *newsrc = find_binary(src);
if (newsrc) {
log_debug("dracut_install '%s' '%s'", newsrc, dst);
ret = dracut_install(newsrc, dst, arg_createdir, arg_resolvedeps, true);
if (ret == 0) {
log_debug("dracut_install '%s' '%s' OK", newsrc, dst);
char **q = NULL;
char **p = find_binary(src);
if (p) {
STRV_FOREACH(q, p) {
char *newsrc = *q;
log_debug("dracut_install '%s' '%s'", newsrc, dst);
ret = dracut_install(newsrc, dst, arg_createdir, arg_resolvedeps, true);
if (ret == 0) {
log_debug("dracut_install '%s' '%s' OK", newsrc, dst);
}
}
free(newsrc);
strv_free(p);
} else {
ret = -1;
}
@ -877,17 +872,22 @@ static int install_all(int argc, char **argv)
int r = EXIT_SUCCESS;
int i;
for (i = 0; i < argc; i++) {
int ret;
int ret = 0;
log_debug("Handle '%s'", argv[i]);

if (strchr(argv[i], '/') == NULL) {
_cleanup_free_ char *newsrc = find_binary(argv[i]);
if (newsrc) {
log_debug("dracut_install '%s'", newsrc);
ret = dracut_install(newsrc, newsrc, arg_createdir, arg_resolvedeps, true);
if (ret == 0) {
log_debug("dracut_install '%s' OK", newsrc);
char **q = NULL;
char **p = find_binary(argv[i]);
if (p) {
STRV_FOREACH(q, p) {
char *newsrc = *q;
log_debug("dracut_install '%s'", newsrc);
ret = dracut_install(newsrc, newsrc, arg_createdir, arg_resolvedeps, true);
if (ret == 0) {
log_debug("dracut_install '%s' OK", newsrc);
}
}
strv_free(p);
} else {
ret = -1;
}

587
install/strv.c Normal file
View File

@ -0,0 +1,587 @@
/*-*- 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 <stdarg.h>
#include <string.h>
#include <errno.h>

#include "util.h"
#include "strv.h"

char *strv_find(char **l, const char *name) {
char **i;

assert(name);

STRV_FOREACH(i, l)
if (streq(*i, name))
return *i;

return NULL;
}

char *strv_find_prefix(char **l, const char *name) {
char **i;

assert(name);

STRV_FOREACH(i, l)
if (startswith(*i, name))
return *i;

return NULL;
}

void strv_free(char **l) {
char **k;

if (!l)
return;

for (k = l; *k; k++)
free(*k);

free(l);
}

char **strv_copy(char * const *l) {
char **r, **k;

k = r = new(char*, strv_length(l) + 1);
if (!r)
return NULL;

if (l)
for (; *l; k++, l++) {
*k = strdup(*l);
if (!*k) {
strv_free(r);
return NULL;
}
}

*k = NULL;
return r;
}

unsigned strv_length(char * const *l) {
unsigned n = 0;

if (!l)
return 0;

for (; *l; l++)
n++;

return n;
}

char **strv_new_ap(const char *x, va_list ap) {
const char *s;
char **a;
unsigned n = 0, i = 0;
va_list aq;

/* As a special trick we ignore all listed strings that equal
* (const char*) -1. This is supposed to be used with the
* STRV_IFNOTNULL() macro to include possibly NULL strings in
* the string list. */

if (x) {
n = x == (const char*) -1 ? 0 : 1;

va_copy(aq, ap);
while ((s = va_arg(aq, const char*))) {
if (s == (const char*) -1)
continue;

n++;
}

va_end(aq);
}

a = new(char*, n+1);
if (!a)
return NULL;

if (x) {
if (x != (const char*) -1) {
a[i] = strdup(x);
if (!a[i])
goto fail;
i++;
}

while ((s = va_arg(ap, const char*))) {

if (s == (const char*) -1)
continue;

a[i] = strdup(s);
if (!a[i])
goto fail;

i++;
}
}

a[i] = NULL;

return a;

fail:
strv_free(a);
return NULL;
}

char **strv_new(const char *x, ...) {
char **r;
va_list ap;

va_start(ap, x);
r = strv_new_ap(x, ap);
va_end(ap);

return r;
}

char **strv_merge(char **a, char **b) {
char **r, **k;

if (!a)
return strv_copy(b);

if (!b)
return strv_copy(a);

r = new(char*, strv_length(a) + strv_length(b) + 1);
if (!r)
return NULL;

for (k = r; *a; k++, a++) {
*k = strdup(*a);
if (!*k)
goto fail;
}

for (; *b; k++, b++) {
*k = strdup(*b);
if (!*k)
goto fail;
}

*k = NULL;
return r;

fail:
strv_free(r);
return NULL;
}

char **strv_merge_concat(char **a, char **b, const char *suffix) {
char **r, **k;

/* Like strv_merge(), but appends suffix to all strings in b, before adding */

if (!b)
return strv_copy(a);

r = new(char*, strv_length(a) + strv_length(b) + 1);
if (!r)
return NULL;

k = r;
if (a)
for (; *a; k++, a++) {
*k = strdup(*a);
if (!*k)
goto fail;
}

for (; *b; k++, b++) {
*k = strappend(*b, suffix);
if (!*k)
goto fail;
}

*k = NULL;
return r;

fail:
strv_free(r);
return NULL;

}

char **strv_split(const char *s, const char *separator) {
char *state;
char *w;
size_t l;
unsigned n, i;
char **r;

assert(s);

n = 0;
FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
n++;

r = new(char*, n+1);
if (!r)
return NULL;

i = 0;
FOREACH_WORD_SEPARATOR(w, l, s, separator, state) {
r[i] = strndup(w, l);
if (!r[i]) {
strv_free(r);
return NULL;
}

i++;
}

r[i] = NULL;
return r;
}

char **strv_split_quoted(const char *s) {
char *state;
char *w;
size_t l;
unsigned n, i;
char **r;

assert(s);

n = 0;
FOREACH_WORD_QUOTED(w, l, s, state)
n++;

r = new(char*, n+1);
if (!r)
return NULL;

i = 0;
FOREACH_WORD_QUOTED(w, l, s, state) {
r[i] = cunescape_length(w, l);
if (!r[i]) {
strv_free(r);
return NULL;
}
i++;
}

r[i] = NULL;
return r;
}

char **strv_split_newlines(const char *s) {
char **l;
unsigned n;

assert(s);

/* Special version of strv_split() that splits on newlines and
* suppresses an empty string at the end */

l = strv_split(s, NEWLINE);
if (!l)
return NULL;

n = strv_length(l);
if (n <= 0)
return l;

if (isempty(l[n-1])) {
free(l[n-1]);
l[n-1] = NULL;
}

return l;
}

char *strv_join(char **l, const char *separator) {
char *r, *e;
char **s;
size_t n, k;

if (!separator)
separator = " ";

k = strlen(separator);

n = 0;
STRV_FOREACH(s, l) {
if (n != 0)
n += k;
n += strlen(*s);
}

r = new(char, n+1);
if (!r)
return NULL;

e = r;
STRV_FOREACH(s, l) {
if (e != r)
e = stpcpy(e, separator);

e = stpcpy(e, *s);
}

*e = 0;

return r;
}

char **strv_append(char **l, const char *s) {
char **r, **k;

if (!l)
return strv_new(s, NULL);

if (!s)
return strv_copy(l);

r = new(char*, strv_length(l)+2);
if (!r)
return NULL;

for (k = r; *l; k++, l++) {
*k = strdup(*l);
if (!*k)
goto fail;
}

k[0] = strdup(s);
if (!k[0])
goto fail;

k[1] = NULL;
return r;

fail:
strv_free(r);
return NULL;
}

int strv_push(char ***l, char *value) {
char **c;
unsigned n;

if (!value)
return 0;

n = strv_length(*l);
c = realloc(*l, sizeof(char*) * (n + 2));
if (!c)
return -ENOMEM;

c[n] = value;
c[n+1] = NULL;

*l = c;
return 0;
}

int strv_extend(char ***l, const char *value) {
char *v;
int r;

if (!value)
return 0;

v = strdup(value);
if (!v)
return -ENOMEM;

r = strv_push(l, v);
if (r < 0)
free(v);

return r;
}

char **strv_uniq(char **l) {
char **i;

/* Drops duplicate entries. The first identical string will be
* kept, the others dropped */

STRV_FOREACH(i, l)
strv_remove(i+1, *i);

return l;
}

char **strv_remove(char **l, const char *s) {
char **f, **t;

if (!l)
return NULL;

assert(s);

/* Drops every occurrence of s in the string list, edits
* in-place. */

for (f = t = l; *f; f++) {

if (streq(*f, s)) {
free(*f);
continue;
}

*(t++) = *f;
}

*t = NULL;
return l;
}

char **strv_remove_prefix(char **l, const char *s) {
char **f, **t;

if (!l)
return NULL;

assert(s);

/* Drops every occurrence of a string prefixed with s in the
* string list, edits in-place. */

for (f = t = l; *f; f++) {

if (startswith(*f, s)) {
free(*f);
continue;
}

*(t++) = *f;
}

*t = NULL;
return l;
}

char **strv_parse_nulstr(const char *s, size_t l) {
const char *p;
unsigned c = 0, i = 0;
char **v;

assert(s || l <= 0);

if (l <= 0)
return new0(char*, 1);

for (p = s; p < s + l; p++)
if (*p == 0)
c++;

if (s[l-1] != 0)
c++;

v = new0(char*, c+1);
if (!v)
return NULL;

p = s;
while (p < s + l) {
const char *e;

e = memchr(p, 0, s + l - p);

v[i] = strndup(p, e ? e - p : s + l - p);
if (!v[i]) {
strv_free(v);
return NULL;
}

i++;

if (!e)
break;

p = e + 1;
}

assert(i == c);

return v;
}

char **strv_split_nulstr(const char *s) {
const char *i;
char **r = NULL;

NULSTR_FOREACH(i, s)
if (strv_extend(&r, i) < 0) {
strv_free(r);
return NULL;
}

if (!r)
return strv_new(NULL, NULL);

return r;
}

bool strv_overlap(char **a, char **b) {
char **i, **j;

STRV_FOREACH(i, a) {
STRV_FOREACH(j, b) {
if (streq(*i, *j))
return true;
}
}

return false;
}

static int str_compare(const void *_a, const void *_b) {
const char **a = (const char**) _a, **b = (const char**) _b;

return strcmp(*a, *b);
}

char **strv_sort(char **l) {

if (strv_isempty(l))
return l;

qsort(l, strv_length(l), sizeof(char*), str_compare);
return l;
}

void strv_print(char **l) {
char **s;

if (!l)
return;

STRV_FOREACH(s, l)
puts(*s);
}

118
install/strv.h Normal file
View File

@ -0,0 +1,118 @@
/*-*- 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 <stdarg.h>
#include <stdbool.h>

#include "util.h"

char *strv_find(char **l, const char *name) _pure_;
char *strv_find_prefix(char **l, const char *name) _pure_;

void strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)

char **strv_copy(char * const *l);
unsigned strv_length(char * const *l) _pure_;

char **strv_merge(char **a, char **b);
char **strv_merge_concat(char **a, char **b, const char *suffix);
char **strv_append(char **l, const char *s);
int strv_extend(char ***l, const char *value);
int strv_push(char ***l, char *value);

char **strv_remove(char **l, const char *s);
char **strv_remove_prefix(char **l, const char *s);
char **strv_uniq(char **l);

#define strv_contains(l, s) (!!strv_find((l), (s)))

char **strv_new(const char *x, ...) _sentinel_;
char **strv_new_ap(const char *x, va_list ap);

static inline const char* STRV_IFNOTNULL(const char *x) {
return x ? x : (const char *) -1;
}

static inline bool strv_isempty(char * const *l) {
return !l || !*l;
}

char **strv_split(const char *s, const char *separator);
char **strv_split_quoted(const char *s);
char **strv_split_newlines(const char *s);

char *strv_join(char **l, const char *separator);

char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);

bool strv_overlap(char **a, char **b) _pure_;

#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)

#define STRV_FOREACH_BACKWARDS(s, l) \
STRV_FOREACH(s, l) \
; \
for ((s)--; (l) && ((s) >= (l)); (s)--)

#define STRV_FOREACH_PAIR(x, y, l) \
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))

char **strv_sort(char **l);
void strv_print(char **l);

#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))

#define STRV_MAKE_EMPTY ((char*[1]) { NULL })

#define strv_from_stdarg_alloca(first) \
({ \
char **_l; \
\
if (!first) \
_l = (char**) &first; \
else { \
unsigned _n; \
va_list _ap; \
\
_n = 1; \
va_start(_ap, first); \
while (va_arg(_ap, char*)) \
_n++; \
va_end(_ap); \
\
_l = newa(char*, _n+1); \
_l[_n = 0] = (char*) first; \
va_start(_ap, first); \
for (;;) { \
_l[++_n] = va_arg(_ap, char*); \
if (!_l[_n]) \
break; \
} \
va_end(_ap); \
} \
_l; \
})

View File

@ -277,3 +277,238 @@ char *strjoin(const char *x, ...) {

return r;
}

char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) {
char *r, *t;
const char *f;
size_t pl;

assert(s);

/* Undoes C style string escaping, and optionally prefixes it. */

pl = prefix ? strlen(prefix) : 0;

r = new(char, pl+length+1);
if (!r)
return r;

if (prefix)
memcpy(r, prefix, pl);

for (f = s, t = r + pl; f < s + length; f++) {

if (*f != '\\') {
*(t++) = *f;
continue;
}

f++;

switch (*f) {

case 'a':
*(t++) = '\a';
break;
case 'b':
*(t++) = '\b';
break;
case 'f':
*(t++) = '\f';
break;
case 'n':
*(t++) = '\n';
break;
case 'r':
*(t++) = '\r';
break;
case 't':
*(t++) = '\t';
break;
case 'v':
*(t++) = '\v';
break;
case '\\':
*(t++) = '\\';
break;
case '"':
*(t++) = '"';
break;
case '\'':
*(t++) = '\'';
break;

case 's':
/* This is an extension of the XDG syntax files */
*(t++) = ' ';
break;

case 'x': {
/* hexadecimal encoding */
int a, b;

a = unhexchar(f[1]);
b = unhexchar(f[2]);

if (a < 0 || b < 0) {
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
*(t++) = 'x';
} else {
*(t++) = (char) ((a << 4) | b);
f += 2;
}

break;
}

case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
/* octal encoding */
int a, b, c;

a = unoctchar(f[0]);
b = unoctchar(f[1]);
c = unoctchar(f[2]);

if (a < 0 || b < 0 || c < 0) {
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
*(t++) = f[0];
} else {
*(t++) = (char) ((a << 6) | (b << 3) | c);
f += 2;
}

break;
}

case 0:
/* premature end of string.*/
*(t++) = '\\';
goto finish;

default:
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
*(t++) = *f;
break;
}
}

finish:
*t = 0;
return r;
}

char *cunescape_length(const char *s, size_t length) {
return cunescape_length_with_prefix(s, length, NULL);
}


/* Split a string into words, but consider strings enclosed in '' and
* "" as words even if they include spaces. */
char *split_quoted(const char *c, size_t *l, char **state) {
const char *current, *e;
bool escaped = false;

assert(c);
assert(l);
assert(state);

current = *state ? *state : c;

current += strspn(current, WHITESPACE);

if (*current == 0)
return NULL;

else if (*current == '\'') {
current ++;

for (e = current; *e; e++) {
if (escaped)
escaped = false;
else if (*e == '\\')
escaped = true;
else if (*e == '\'')
break;
}

*l = e-current;
*state = (char*) (*e == 0 ? e : e+1);

} else if (*current == '\"') {
current ++;

for (e = current; *e; e++) {
if (escaped)
escaped = false;
else if (*e == '\\')
escaped = true;
else if (*e == '\"')
break;
}

*l = e-current;
*state = (char*) (*e == 0 ? e : e+1);

} else {
for (e = current; *e; e++) {
if (escaped)
escaped = false;
else if (*e == '\\')
escaped = true;
else if (strchr(WHITESPACE, *e))
break;
}
*l = e-current;
*state = (char*) e;
}

return (char*) current;
}

/* Split a string into words. */
char *split(const char *c, size_t *l, const char *separator, char **state) {
char *current;

current = *state ? *state : (char*) c;

if (!*current || *c == 0)
return NULL;

current += strspn(current, separator);
*l = strcspn(current, separator);
*state = current+*l;

return (char*) current;
}

int unhexchar(char c) {

if (c >= '0' && c <= '9')
return c - '0';

if (c >= 'a' && c <= 'f')
return c - 'a' + 10;

if (c >= 'A' && c <= 'F')
return c - 'A' + 10;

return -1;
}

int unoctchar(char c) {

if (c >= '0' && c <= '7')
return c - '0';

return -1;
}

View File

@ -134,8 +134,16 @@ static inline bool isempty(const char *p) {
return !p || !p[0];
}


static inline const char *startswith(const char *s, const char *prefix) {
if (strncmp(s, prefix, strlen(prefix)) == 0)
return s + strlen(prefix);
return NULL;
}

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);
@ -562,4 +570,16 @@ void warn_melody(void);

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

#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
func(*p); \
} \
struct __useless_struct_to_allow_trailing_semicolon__

char *split_quoted(const char *c, size_t *l, char **state);
char *cunescape_length(const char *s, size_t length);
int unhexchar(char c) _const_;
int unoctchar(char c) _const_;

#endif