xbps-checkvers: rewrite shell substitution without buffer guessing
This commit is contained in:
parent
6b3b4bc3cd
commit
204b9b630a
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2019 Juan Romero Pardines
|
* Copyright (c) 2014-2019 Juan Romero Pardines
|
||||||
* Copyright (c) 2012-2014 Dave Elusive <davehome@redthumb.info.tm>
|
* Copyright (c) 2012-2014 Dave Elusive <davehome@redthumb.info.tm>
|
||||||
|
* Copyright (c) 2019 Duncan Overbruck <mail@duncano.de>
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -58,6 +59,17 @@ do { \
|
|||||||
#define _dprintf(...)
|
#define _dprintf(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SBUFSZ 128
|
||||||
|
#define ALIGN(n, a) (((n) + (a) - 1) & ~((a) - 1))
|
||||||
|
#define MAX(a, b) ((a) < (b) ? (b) : (a))
|
||||||
|
#define NEXTSZ(o, r) ALIGN(MAX((o) * 2, (o) + (r)), SBUFSZ)
|
||||||
|
|
||||||
|
struct sbuf {
|
||||||
|
char *mem;
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct str_ptr_t {
|
typedef struct str_ptr_t {
|
||||||
char *s;
|
char *s;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -90,6 +102,77 @@ typedef struct _rcv_t {
|
|||||||
typedef int (*rcv_check_func)(rcv_t *);
|
typedef int (*rcv_check_func)(rcv_t *);
|
||||||
typedef int (*rcv_proc_func)(rcv_t *, const char *, rcv_check_func);
|
typedef int (*rcv_proc_func)(rcv_t *, const char *, rcv_check_func);
|
||||||
|
|
||||||
|
static void
|
||||||
|
sbuf_extend(struct sbuf *sb, int newsz)
|
||||||
|
{
|
||||||
|
sb->size = newsz;
|
||||||
|
sb->mem = realloc(sb->mem, newsz);
|
||||||
|
if (sb->mem == NULL) {
|
||||||
|
fprintf(stderr, "realloc: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sbuf *
|
||||||
|
sbuf_make(void)
|
||||||
|
{
|
||||||
|
struct sbuf *sb = calloc(1, sizeof(*sb));
|
||||||
|
if (sb == NULL) {
|
||||||
|
fprintf(stderr, "calloc: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
sbuf_buf(struct sbuf *sb)
|
||||||
|
{
|
||||||
|
if (!sb->mem)
|
||||||
|
sbuf_extend(sb, 1);
|
||||||
|
sb->mem[sb->len] = '\0';
|
||||||
|
return sb->mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
sbuf_done(struct sbuf *sb, char **dest)
|
||||||
|
{
|
||||||
|
size_t len = sb->len;
|
||||||
|
*dest = sbuf_buf(sb);
|
||||||
|
free(sb);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sbuf_chr(struct sbuf *sb, int c)
|
||||||
|
{
|
||||||
|
if (sb->len + 2 >= sb->size)
|
||||||
|
sbuf_extend(sb, NEXTSZ(sb->size, 1));
|
||||||
|
sb->mem[sb->len++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sbuf_mem(struct sbuf *sb, const char *src, size_t len)
|
||||||
|
{
|
||||||
|
if (sb->len + len + 1 >= sb->size)
|
||||||
|
sbuf_extend(sb, NEXTSZ(sb->size, len + 1));
|
||||||
|
memcpy(sb->mem + sb->len, src, len);
|
||||||
|
sb->len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sbuf_str(struct sbuf *sb, const char *src)
|
||||||
|
{
|
||||||
|
sbuf_mem(sb, src, strlen(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
sbuf_strn(struct sbuf *sb, const char *src, size_t n)
|
||||||
|
{
|
||||||
|
sbuf_mem(sb, src, n);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static map_item_t
|
static map_item_t
|
||||||
map_new_item(void)
|
map_new_item(void)
|
||||||
{
|
{
|
||||||
@ -291,108 +374,92 @@ rcv_load_file(rcv_t *rcv, const char *fname)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static size_t
|
||||||
rcv_refs(rcv_t *rcv, const char *s, size_t len)
|
rcv_sh_substitute(rcv_t *rcv, const char *str, size_t len, char **outp)
|
||||||
{
|
{
|
||||||
map_item_t item;
|
const char *p;
|
||||||
size_t i = 0, j = 0, k = 0, count = len*3;
|
char *cmd;
|
||||||
char *ref = calloc(count, sizeof(char));
|
struct sbuf *out = sbuf_make();
|
||||||
char *buf = calloc(count, sizeof(char));
|
|
||||||
|
|
||||||
assert(rcv);
|
for (p = str; *p && p < str+len; p++) {
|
||||||
assert(s);
|
switch (*p) {
|
||||||
assert(ref);
|
case '$':
|
||||||
assert(buf);
|
if (p+1 < str+len) {
|
||||||
|
const char *ref;
|
||||||
while (i < len) {
|
size_t reflen;
|
||||||
if (s[i] == '$' && s[i+1] != '(') {
|
map_item_t item;
|
||||||
j = 0;
|
p++;
|
||||||
i++;
|
if (*p == '(') {
|
||||||
if (s[i] == '{') {
|
FILE *fp;
|
||||||
i++;
|
char c;
|
||||||
}
|
for (ref = ++p; *p && p < str+len && *p != ')'; p++)
|
||||||
while (isalpha(s[i]) || s[i] == '_') {
|
;
|
||||||
ref[j++] = s[i++];
|
if (*p != ')')
|
||||||
}
|
goto err1;
|
||||||
if (s[i] == '}') {
|
cmd = strndup(ref, p-ref);
|
||||||
i++;
|
if ((fp = popen(cmd, "r")) == NULL)
|
||||||
}
|
goto err2;
|
||||||
ref[j++] = '\0';
|
while ((c = fgetc(fp)) != EOF && c != '\n')
|
||||||
item = map_find(rcv->env, ref);
|
sbuf_chr(out, c);
|
||||||
if ((strncmp(ref, item.k.s, strlen(ref)) == 0)) {
|
if (pclose(fp) != 0)
|
||||||
buf = strcat(buf, item.v.s);
|
goto err2;
|
||||||
k += item.v.len;
|
free(cmd);
|
||||||
} else {
|
cmd = NULL;
|
||||||
buf = strcat(buf, "NULL");
|
continue;
|
||||||
k += 4;
|
} else if (*p == '{') {
|
||||||
}
|
for (ref = ++p; *p && p < str+len && (isalnum(*p) || *p == '_'); p++)
|
||||||
} else {
|
;
|
||||||
if (s[i] != '\n')
|
reflen = p-ref;
|
||||||
buf[k++] = s[i++];
|
switch (*p) {
|
||||||
}
|
case '/': /* fallthrough */
|
||||||
}
|
case '%': /* fallthrough */
|
||||||
buf[k] = '\0';
|
case '#': /* fallthrough */
|
||||||
free(ref);
|
case ':':
|
||||||
return buf;
|
for (; *p && p < str+len && *p != '}'; p++)
|
||||||
}
|
;
|
||||||
|
if (*p != '}')
|
||||||
static char *
|
goto err1;
|
||||||
rcv_cmd(rcv_t *rcv, const char *s, size_t len)
|
break;
|
||||||
{
|
case '}':
|
||||||
int c, rv = 0;
|
break;
|
||||||
FILE *stream;
|
default:
|
||||||
size_t i = 0, j = 0, k = 0, count = len*3;
|
goto err1;
|
||||||
char *cmd = calloc(count, sizeof(char));
|
}
|
||||||
char *buf = calloc(count, sizeof(char));
|
} else {
|
||||||
|
for (ref = p; *p && p < str+len && (isalnum(*p) || *p == '_'); p++)
|
||||||
assert(cmd);
|
;
|
||||||
assert(buf);
|
reflen = p-ref;
|
||||||
|
|
||||||
(void)rcv;
|
|
||||||
|
|
||||||
while (i < len) {
|
|
||||||
if (s[i] == '$' && s[i+1] != '{') {
|
|
||||||
j = 0;
|
|
||||||
i++;
|
|
||||||
if (s[i] == '(') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (s[i] != ')') {
|
|
||||||
cmd[j++] = s[i++];
|
|
||||||
}
|
|
||||||
if (s[i] == ')') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
cmd[j++] = '\0';
|
|
||||||
if ((stream = popen(cmd, "r")) == NULL)
|
|
||||||
goto error;
|
|
||||||
while ((c = fgetc(stream)) != EOF && c != '\n') {
|
|
||||||
buf[k++] = (char)c;
|
|
||||||
}
|
|
||||||
rv = pclose(stream);
|
|
||||||
error:
|
|
||||||
if (rv > 0 || errno > 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Shell cmd failed: '%s' for "
|
|
||||||
"template '%s'",
|
|
||||||
cmd, rcv->fname);
|
|
||||||
if (errno > 0) {
|
|
||||||
fprintf(stderr, ": %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
}
|
}
|
||||||
putchar('\n');
|
item = map_find_n(rcv->env, ref, reflen);
|
||||||
exit(1);
|
if ((strncmp(ref, item.k.s, reflen) == 0)) {
|
||||||
|
sbuf_str(out, item.v.s);
|
||||||
|
} else {
|
||||||
|
sbuf_str(out, "NULL");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
/* fallthrough */
|
||||||
} else {
|
default:
|
||||||
if (s[i] != '\n')
|
sbuf_chr(out, *p);
|
||||||
buf[k++] = s[i++];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf[k] = '\0';
|
return sbuf_done(out, outp);
|
||||||
free(cmd);
|
|
||||||
free(__UNCONST(s));
|
err1:
|
||||||
return buf;
|
fprintf(stderr, "syntax error: in file '%s'\n", rcv->fname);
|
||||||
|
exit(1);
|
||||||
|
err2:
|
||||||
|
fprintf(stderr,
|
||||||
|
"Shell cmd failed: '%s' for "
|
||||||
|
"template '%s'",
|
||||||
|
cmd, rcv->fname);
|
||||||
|
if (errno > 0) {
|
||||||
|
fprintf(stderr, ": %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
} else {
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -460,11 +527,8 @@ rcv_get_pkgver(rcv_t *rcv)
|
|||||||
if (strchr(v, '$')) {
|
if (strchr(v, '$')) {
|
||||||
assert(item);
|
assert(item);
|
||||||
assert(item->v.s);
|
assert(item->v.s);
|
||||||
item->v.s = rcv_refs(rcv, item->v.s, item->v.len);
|
item->v.len = rcv_sh_substitute(rcv, item->v.s, item->v.len, &item->v.s);
|
||||||
item->v.len = strlen(item->v.s);
|
|
||||||
item->v.vmalloc = 1;
|
item->v.vmalloc = 1;
|
||||||
item->v.s = rcv_cmd(rcv, item->v.s, item->v.len);
|
|
||||||
item->v.len = strlen(item->v.s);
|
|
||||||
} else {
|
} else {
|
||||||
item->v.vmalloc = 0;
|
item->v.vmalloc = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user