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