• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 
27 #define WRITE_STRING(fd, string) if (write(fd, string, sizeof(string)-1)) {}
28 
main(int argc,char * argv[])29 int main(int argc, char *argv[])
30 {
31 	int i, pos = 0;
32 	char *args[argc];
33 	char *stdin_path = NULL, *stdout_path = NULL, *stderr_path = NULL;
34 	int stderr_fd = 0;
35 
36 	if (argc <= 1) {
37 		fprintf(stderr, "%s: Takes at least one agrument!\n", argv[0]);
38 		return 1;
39 	}
40 
41 	for (i = 1; i < argc; i++) {
42 
43 		if (argv[i][0] == '>') {
44 			if (argv[i][1]) {
45 				stdout_path = argv[i]+1;
46 			} else {
47 				if (++i >= argc) {
48 					fprintf(stderr,
49 					        "%s: Missing filename after >\n",
50 					        argv[0]);
51 					return 1;
52 				}
53 				stdout_path = argv[i];
54 			}
55 			continue;
56 		}
57 
58 		if (argv[i][0] == '<') {
59 			if (argv[i][1]) {
60 				stdin_path = argv[i]+1;
61 			} else {
62 				if (++i >= argc) {
63 					fprintf(stderr,
64 					        "%s: Missing filename after <\n",
65 					        argv[0]);
66 					return 1;
67 				}
68 				stdin_path = argv[i];
69 			}
70 			continue;
71 		}
72 
73 		if (argv[i][0] == '2' && argv[i][1] == '>') {
74 			if (argv[i][2]) {
75 				stderr_path = argv[i]+2;
76 			} else {
77 				if (++i >= argc) {
78 					fprintf(stderr,
79 					        "%s: Missing filename after 2>\n",
80 					        argv[0]);
81 					return 1;
82 				}
83 				stderr_path = argv[i];
84 			}
85 			continue;
86 		}
87 
88 		args[pos++] = argv[i];
89 	}
90 
91 	args[pos] = NULL;
92 
93 	if (stdin_path) {
94 		if (close(0)) {
95 			fprintf(stderr, "%s: Failed to close stdin: %s\n",
96 				argv[0], strerror(errno));
97 			return 1;
98 		}
99 		if (open(stdin_path, O_RDONLY) < 0) {
100 			fprintf(stderr,
101 			        "%s: Failed to open '%s' for reading: %s\n",
102 				argv[0], stdin_path, strerror(errno));
103 			return 1;
104 		}
105 	}
106 
107 	if (stdout_path) {
108 		if (close(1)) {
109 			fprintf(stderr, "%s: Failed to close stdout: %s\n",
110 				argv[0], strerror(errno));
111 			return 1;
112 		}
113 		if (open(stdout_path, O_CREAT|O_WRONLY|O_TRUNC, 0777) < 0) {
114 			fprintf(stderr,
115 			        "%s: Failed to open '%s' for writing: %s\n",
116 				argv[0], stdin_path, strerror(errno));
117 			return 1;
118 		}
119 	}
120 
121 	if (stderr_path) {
122 		int fd = open(stderr_path, O_CREAT|O_WRONLY|O_TRUNC, 0777);
123 		int stderr_fd = dup(2);
124 
125 		if (stderr_fd < 0) {
126 			fprintf(stderr, "%s: Failed to dup() stderr: %s\n",
127 				argv[0], strerror(errno));
128 			return 1;
129 		}
130 
131 		if (fd < 0) {
132 			fprintf(stderr,
133 			        "%s: Failed to open '%s' for writing: %s\n",
134 				argv[0], stdin_path, strerror(errno));
135 			return 1;
136 		}
137 
138 		if (dup2(fd, 2) < 0) {
139 			fprintf(stderr, "%s: Failed to dup2 stderr: %s\n",
140 				argv[0], strerror(errno));
141 			WRITE_STRING(stderr_fd, "Failed to dup2 stderr\n");
142 			return 1;
143 		}
144 	}
145 
146 	execvp(argv[1], args);
147 
148 	/* Fall back to shell if command wasn't found */
149 	FILE *sin = popen("/bin/sh", "w");
150 
151 	if (!sin) {
152 		if (stderr_fd) {
153 			WRITE_STRING(stderr_fd, "Failed to popen /bin/sh\n");
154 		} else {
155 			fprintf(stderr, "%s: Failed to popen /bin/sh: %s\n",
156 				argv[0], strerror(errno));
157 		}
158 		return 1;
159 	}
160 
161 	//TODO: Should we escape args?
162 	for (i = 0; args[i]; i++)
163 		fprintf(sin, "%s ", args[i]);
164 
165 	return !!pclose(sin);
166 }
167