tech-pkg archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Wrappers don't transform @file syntax



I stumbled upon a problem where wrappers don't transform @file syntax
accepted by tools like gcc, ld, and ar. Missing dependencies went
unnoticed because GHC used it to link libraries and executables:

> [*] cc '@/tmp/ghc23632_0/ghc_1.rsp'
> <.> /usr/pkgsrc/devel/hs-either/work/.gcc/bin/gcc -m64
'@/tmp/ghc3079_0/ghc_20.rsp' -D_FORTIFY_SOURCE=2 ...

The attached patch expands @file, possibly recursively, before applying
transformations. I originally planned to turn arguments back to @file
after transformations by writing them to a temporary file, but since it
invokes execvp(3) I couldn't come up with a way to delete it afterwards.

joerg@, could you review it please?
? files/test/Atffile
Index: files/bin/base-wrapper.c
===================================================================
RCS file: /cvsroot/pkgsrc/pkgtools/cwrappers/files/bin/base-wrapper.c,v
retrieving revision 1.6
diff -u -r1.6 base-wrapper.c
--- files/bin/base-wrapper.c	27 Oct 2017 20:59:59 -0000	1.6
+++ files/bin/base-wrapper.c	10 Jan 2020 12:17:18 -0000
@@ -136,6 +136,7 @@
 	operation_mode_cc(&args);
 #endif
 	arglist_apply_config(&args);
+	arglist_expand_atfile(&args);
 #if defined(WRAPPER_LD)
 	normalise_ld(&args);
 #else
Index: files/bin/common.c
===================================================================
RCS file: /cvsroot/pkgsrc/pkgtools/cwrappers/files/bin/common.c,v
retrieving revision 1.10
diff -u -r1.10 common.c
--- files/bin/common.c	25 Mar 2018 20:45:25 -0000	1.10
+++ files/bin/common.c	10 Jan 2020 12:17:18 -0000
@@ -173,6 +173,34 @@
 	}
 }
 
+static void
+arglist_insert_list(struct arglist *args, struct arglist *inserts, struct argument *before)
+{
+	struct argument *insert;
+
+	TAILQ_FOREACH(insert, inserts, link) {
+		struct argument *arg;
+
+		arg = argument_copy(insert->val);
+		if (before != NULL)
+			TAILQ_INSERT_BEFORE(before, arg, link);
+		else
+			TAILQ_INSERT_TAIL(args, arg, link);
+	}
+}
+
+static void
+arglist_clear(struct arglist *args)
+{
+	struct argument *arg;
+
+	while ((arg = TAILQ_FIRST(args)) != NULL) {
+		TAILQ_REMOVE(args, arg, link);
+		free(arg->val);
+		free(arg);
+	}
+}
+
 void
 arglist_apply_config(struct arglist *args)
 {
@@ -194,6 +222,118 @@
 }
 
 void
+arglist_from_atfile(struct arglist *args, const char *file)
+{
+	FILE *fp;
+	char *line;
+	size_t len;
+	ssize_t llen;
+
+	TAILQ_INIT(args);
+
+	fp= fopen(file, "r");
+	if (fp == NULL) {
+		/* If the file cannot be read, it has to be treated
+		 * literally. */
+		struct argument *arg;
+		arg = argument_new(concat("@", file));
+		TAILQ_INSERT_TAIL(args, arg, link);
+		return;
+	}
+
+	line = NULL;
+	len = 0;
+	while ((llen = getline(&line, &len, fp)) > 0) {
+		char *buf;
+		size_t blen, pos;
+
+		/* Allocate a buffer for an argument. It can be at most llen
+		 * bytes long. */
+		buf = xmalloc(llen + 1);
+
+		for (pos = 0; pos < llen; ) {
+			char in_quote;
+
+			/* Find the next possible argument. */
+			blen = 0;
+			pos += strspn(line + pos, " \t\n");
+			in_quote = '\0';
+
+			if (pos >= llen)
+				break;
+
+			while (pos < llen) {
+				if (strchr(" \t\n", line[pos]) != NULL) {
+					if (in_quote != '\0') {
+						buf[blen++] = line[pos++];
+					}
+					else {
+						break;
+					}
+				}
+				else if (line[pos] == '\\') {
+					if (pos+1 < llen) {
+						buf[blen++] = line[pos+1];
+						pos += 2;
+					}
+					else {
+						errx(255, "Incomplete escape sequence: %s", line);
+					}
+				}
+				else if (strchr("\'\"", line[pos]) != NULL) {
+					if (in_quote == line[pos]) {
+						/* We just exited a quoted string. */
+						in_quote = '\0';
+					}
+					else {
+						/* Entering into a quoted string. */
+						in_quote = line[pos];
+					}
+					pos++;
+				}
+				else {
+					buf[blen++] = line[pos++];
+				}
+			}
+
+			buf[blen] = '\0';
+			if (blen > 1 && buf[0] == '@') {
+				/* @file arguments may itself contain @file. Expand it
+				 * recursively. */
+				struct arglist file_args;
+				arglist_from_atfile(&file_args, buf + 1);
+				arglist_append_list(args, &file_args);
+				arglist_clear(&file_args);
+			}
+			else {
+				struct argument *arg;
+				arg = argument_copy(buf);
+				TAILQ_INSERT_TAIL(args, arg, link);
+			}
+		}
+		free(buf);
+	}
+	free(line);
+}
+
+void
+arglist_expand_atfile(struct arglist *args)
+{
+	struct argument *arg, *arg2;
+
+	TAILQ_FOREACH_SAFE(arg, args, link, arg2) {
+		if (arg->val[0] == '@') {
+			struct arglist file_args;
+
+			arglist_from_atfile(&file_args, arg->val + 1);
+			arglist_insert_list(args, &file_args, arg2);
+			arglist_clear(&file_args);
+			argument_unlink(args, &arg);
+		}
+	}
+}
+
+void
 argument_unlink(struct arglist *args, struct argument **argp)
 {
 	struct argument *arg;
Index: files/bin/common.h
===================================================================
RCS file: /cvsroot/pkgsrc/pkgtools/cwrappers/files/bin/common.h,v
retrieving revision 1.8
diff -u -r1.8 common.h
--- files/bin/common.h	7 Nov 2017 16:49:22 -0000	1.8
+++ files/bin/common.h	10 Jan 2020 12:17:18 -0000
@@ -69,7 +69,9 @@
 char	*concat(const char *, const char *);
 char	*concat2(const char *, const char *, size_t);
 void	arglist_from_argc(struct arglist *, int, char **);
+void	arglist_from_atfile(struct arglist *, const char *);
 void	arglist_apply_config(struct arglist *);
+void	arglist_expand_atfile(struct arglist *);
 int	command_exec(struct arglist *, int, char **);
 size_t	wrapper_hash(const char *);
 size_t	wrapper_hash2(const char *, size_t);


Home | Main Index | Thread Index | Old Index