Blob Blame History Raw
From f5bf4407d7801d5add15b786a7425b6135dfb7e2 Mon Sep 17 00:00:00 2001
From: Jan Zeleny <jzeleny@redhat.com>
Date: Thu, 21 Nov 2013 12:18:46 +0100
Subject: [PATCH] Implement "--" as a command separator

Whatever comes after the first "--" will be considered a command. If there
are multiple arguments after the first "--", they will all be concatenated by
spaces and treated as a single command afterwards.
---
 scl.1 |  9 ++++++-
 scl.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 76 insertions(+), 21 deletions(-)

diff --git a/scl.1 b/scl.1
index aa797739b1faafe8760e9fc7c5ddaa6ef5da5f4f..f552653f82e97e6503e81f5f75d63b8ca0429bfa 100644
--- a/scl.1
+++ b/scl.1
@@ -5,6 +5,8 @@ scl \- Setup and run software from Software Collection environment
 .PP
 \fBscl\fP \fI<action>\fR \fI<collection1>\fR [\fI<collection2> ...\fR] \fI<command>\fR
 .PP
+\fBscl\fP \fI<action>\fR \fI<collection1>\fR [\fI<collection2> ...\fR] -- \fI<command>\fR
+.PP
 \fBscl\fP {\fB-l|--list\fP} [\fI<collection1> <collection2> ...\fR]
 .SH "DESCRIPTION"
 .PP
@@ -27,6 +29,10 @@ collections which are enabled by the left-right order as present on \fBscl\fP co
 Collection environment enabled. Control is returned back to the caller with the original
 environment as soon as the command finishes. It \fI<command>\fR is '-' (dash) then it is
 read from the standard input.
+.PP
+Note that if you use \fI<command>\fR consisting of multiple arguments, you either need to
+use quotes or the \fB--\fP command separator. Everything that follows the
+separator will be considered a command or its argument.
 .SH "OPTIONS"
 .PP
 .IP "\fB-l, --list\fP"
@@ -52,4 +58,5 @@ scl -l example
 list all packages within example collection
 .SH "AUTHOR"
 .PP
-\fBscl\fP was written by Jindrich Novy <jnovy@redhat.com>.
+\fBscl\fP was written by Jindrich Novy <jnovy@redhat.com> and Jan Zeleny
+<jzeleny@redhat.com>
diff --git a/scl.c b/scl.c
index 81fdf5d94a9e011d697cd422cd581d21364d7eca..cf3ff5bfa7fce0b95705b0aa09946524d06801c5 100644
--- a/scl.c
+++ b/scl.c
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 
 #define SCL_CONF_DIR "/etc/scl/conf/"
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
 
 static void check_asprintf( char **strp, const char *fmt, ... ) {
 	va_list args;
@@ -245,8 +246,10 @@ int main(int argc, char **argv) {
 	struct stat st;
 	char *path, *enablepath;
 	char tmp[] = "/var/tmp/sclXXXXXX";
-	char *cmd = NULL, *bash_cmd, *echo, *enabled;
-	int i, tfd, ffd, stdin_read = 0;
+	char *bash_cmd, *echo, *enabled;
+	int i, tfd, ffd;
+	int separator_pos = 0;
+	char *command = NULL;
 
 	if (argc == 2 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h"))) {
 		print_usage(argv[0]);
@@ -263,25 +266,58 @@ int main(int argc, char **argv) {
 		exit(EXIT_SUCCESS);
 	}
 
-	if (!strcmp(argv[argc-1], "-")) {	/* reading command from stdin */
-		size_t r;
+	for (i = 0; i < argc; i++) {
+		if (strcmp(argv[i], "--") == 0) {
+			break;
+		}
+	}
+	separator_pos = i;
 
+	if (separator_pos == argc) {
+		/* Separator not found */
 		if (argc < 4) {
-			fprintf(stderr, "Need at least 3 arguments.\nRun %s without arguments to get help.\n", argv[0]);
+			fprintf(stderr, "Need at least 3 arguments.\nRun %s --help to get help.\n", argv[0]);
 			exit(EXIT_FAILURE);
 		}
 
-		cmd = malloc(BUFSIZ);
+		command = strdup(argv[argc-1]);
+		if (command == NULL) {
+			fprintf(stderr, "Can't duplicate string.\n");
+		}
+	} else if (separator_pos == argc-1) {
+		command = "-";
+	} else if (separator_pos <= 2) {
+		fprintf(stderr, "Need at least 2 arguments before command is specified.\nRun %s --help to get help.\n", argv[0]);
+		exit(EXIT_FAILURE);
+	} else {
+		command = NULL;
+	}
 
-		if (!cmd) {
+	if ((command == NULL && !strcmp(argv[separator_pos+1], "-")) ||
+	    (command != NULL && !strcmp(command, "-"))) {	/* reading command from stdin */
+		size_t r;
+
+
+		command = malloc(BUFSIZ+1);
+		if (!command) {
 			fprintf(stderr, "Can't allocate memory.\n");
 			exit(EXIT_FAILURE);
 		}
 
-		for (r=0; (r += fread(cmd+r, 1, BUFSIZ, stdin));) {
-			if (feof(stdin)) break;
-			cmd = realloc(cmd, r+BUFSIZ);
-			if (!cmd) {
+		for (r=0; (r += fread(command+r, 1, BUFSIZ, stdin));) {
+			if (feof(stdin)) {
+				if (r % BUFSIZ == 0) {
+					command = realloc(command, r+1);
+					if (!command) {
+						fprintf(stderr, "Can't reallocate memory.\n");
+						exit(EXIT_FAILURE);
+					}
+				}
+				command[r] = '\0';
+				break;
+			}
+			command = realloc(command, r+BUFSIZ+1);
+			if (!command) {
 				fprintf(stderr, "Can't reallocate memory.\n");
 				exit(EXIT_FAILURE);
 			}
@@ -290,15 +326,27 @@ int main(int argc, char **argv) {
 			fprintf(stderr, "Error reading command from stdin.\n");
 			exit(EXIT_FAILURE);
 		}
-		stdin_read = 1;
-	}
+	} else if (command == NULL) {
+		int len = 0;
+		for (i = separator_pos+1; i < argc; i++) {
+			len += strlen(argv[i])+3; /* +1 for additional space, +2 for additional quotes */
+		}
 
-	if (!stdin_read) {
-		if (argc < 4) {
-			print_usage(argv[0]);
+		command = malloc((len+1)*sizeof(char));
+		if (command == NULL) {
+			fprintf(stderr, "Can't allocate memory.\n");
 			exit(EXIT_FAILURE);
 		}
-		cmd = strdup(argv[argc-1]);
+
+		len = 0;
+		for (i = separator_pos+1; i < argc; i++) {
+			command[len++] = '"';
+			strcpy(command+len, argv[i]);
+			len += strlen(argv[i]);
+			command[len++] = '"';
+			command[len++] = ' ';
+		}
+		command[len] = '\0';
 	}
 
 	tfd = mkstemp(tmp);
@@ -307,7 +355,7 @@ int main(int argc, char **argv) {
 	write_script(tfd, enabled);
 	free(enabled);
 
-	for (i=2; i<argc-1; i++) {
+	for (i=2; i<MIN(separator_pos, argc-1); i++) {
 		FILE *f;
 		size_t r;
 		char scl_dir[BUFSIZ];
@@ -367,9 +415,9 @@ int main(int argc, char **argv) {
 		free(path);
 	}
 
-	write_script(tfd, cmd);
+	write_script(tfd, command);
 	write_script(tfd, "\n");
-	free(cmd);
+	free(command);
 	close(tfd);
 
 	check_asprintf(&bash_cmd, "/bin/bash %s", tmp);
-- 
1.8.3.1