• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: t -*- */
2 /*
3  * self_exec.c: self_exec magic required to run child functions on uClinux
4  *
5  * Copyright (C) 2005 Paul J.Y. Lahaie <pjlahaie-at-steamballoon.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * This software was produced by Steamballoon Incorporated
22  * 55 Byward Market Square, 2nd Floor North, Ottawa, ON K1N 9C3, Canada
23  */
24 
25 #define _GNU_SOURCE		/* for asprintf */
26 
27 #include "config.h"
28 
29 #ifdef UCLINUX
30 
31 #include <stdarg.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include "test.h"
35 #include "safe_macros.h"
36 
37 /* Set from parse_opts.c: */
38 char *child_args;		/* Arguments to child when -C is used */
39 
40 static char *start_cwd;		/* Stores the starting directory for self_exec */
41 
asprintf(char ** app,const char * fmt,...)42 int asprintf(char **app, const char *fmt, ...)
43 {
44 	va_list ptr;
45 	int rv;
46 	char *p;
47 
48 	/*
49 	 * First iteration - find out size of buffer required and allocate it.
50 	 */
51 	va_start(ptr, fmt);
52 	rv = vsnprintf(NULL, 0, fmt, ptr);
53 	va_end(ptr);
54 
55 	p = malloc(++rv);	/* allocate the buffer */
56 	*app = p;
57 	if (!p) {
58 		return -1;
59 	}
60 
61 	/*
62 	 * Second iteration - actually produce output.
63 	 */
64 	va_start(ptr, fmt);
65 	rv = vsnprintf(p, rv, fmt, ptr);
66 	va_end(ptr);
67 
68 	return rv;
69 }
70 
maybe_run_child(void (* child)(),const char * fmt,...)71 void maybe_run_child(void (*child) (), const char *fmt, ...)
72 {
73 	va_list ap;
74 	char *child_dir;
75 	char *p, *tok;
76 	int *iptr, i, j;
77 	char *s;
78 	char **sptr;
79 	char *endptr;
80 
81 	/* Store the current directory for later use. */
82 	start_cwd = getcwd(NULL, 0);
83 
84 	if (child_args) {
85 		char *args = strdup(child_args);
86 
87 		child_dir = strtok(args, ",");
88 		if (strlen(child_dir) == 0) {
89 			tst_brkm(TBROK, NULL,
90 				 "Could not get directory from -C option");
91 			return;
92 		}
93 
94 		va_start(ap, fmt);
95 
96 		for (p = fmt; *p; p++) {
97 			tok = strtok(NULL, ",");
98 			if (!tok || strlen(tok) == 0) {
99 				tst_brkm(TBROK, NULL,
100 					 "Invalid argument to -C option");
101 				return;
102 			}
103 
104 			switch (*p) {
105 			case 'd':
106 				iptr = va_arg(ap, int *);
107 				i = strtol(tok, &endptr, 10);
108 				if (*endptr != '\0') {
109 					tst_brkm(TBROK, NULL,
110 						 "Invalid argument to -C option");
111 					return;
112 				}
113 				*iptr = i;
114 				break;
115 			case 'n':
116 				j = va_arg(ap, int);
117 				i = strtol(tok, &endptr, 10);
118 				if (*endptr != '\0') {
119 					tst_brkm(TBROK, NULL,
120 						 "Invalid argument to -C option");
121 					return;
122 				}
123 				if (j != i) {
124 					va_end(ap);
125 					free(args);
126 					return;
127 				}
128 				break;
129 			case 's':
130 				s = va_arg(ap, char *);
131 				if (!strncpy(s, tok, strlen(tok) + 1)) {
132 					tst_brkm(TBROK, NULL,
133 						 "Could not strncpy for -C option");
134 					return;
135 				}
136 				break;
137 			case 'S':
138 				sptr = va_arg(ap, char **);
139 				*sptr = strdup(tok);
140 				if (!*sptr) {
141 					tst_brkm(TBROK, NULL,
142 						 "Could not strdup for -C option");
143 					return;
144 				}
145 				break;
146 			default:
147 				tst_brkm(TBROK, NULL,
148 					 "Format string option %c not implemented",
149 					 *p);
150 				return;
151 			}
152 		}
153 
154 		va_end(ap);
155 		free(args);
156 		SAFE_CHDIR(NULL, child_dir);
157 
158 		(*child) ();
159 		tst_resm(TWARN, "Child function returned unexpectedly");
160 		/* Exit here? or exit silently? */
161 	}
162 }
163 
self_exec(const char * argv0,const char * fmt,...)164 int self_exec(const char *argv0, const char *fmt, ...)
165 {
166 	va_list ap;
167 	char *p;
168 	char *tmp_cwd;
169 	char *arg;
170 	int ival;
171 	char *str;
172 
173 	if ((tmp_cwd = getcwd(NULL, 0)) == NULL) {
174 		tst_resm(TBROK, "Could not getcwd()");
175 		return -1;
176 	}
177 
178 	arg = strdup(tmp_cwd);
179 	if (arg == NULL) {
180 		tst_resm(TBROK, "Could not produce self_exec string");
181 		return -1;
182 	}
183 
184 	va_start(ap, fmt);
185 
186 	for (p = fmt; *p; p++) {
187 		switch (*p) {
188 		case 'd':
189 		case 'n':
190 			ival = va_arg(ap, int);
191 			if (asprintf(&arg, "%s,%d", arg, ival) < 0) {
192 				tst_resm(TBROK,
193 					 "Could not produce self_exec string");
194 				return -1;
195 			}
196 			break;
197 		case 's':
198 		case 'S':
199 			str = va_arg(ap, char *);
200 			if (asprintf(&arg, "%s,%s", arg, str) < 0) {
201 				tst_resm(TBROK,
202 					 "Could not produce self_exec string");
203 				return -1;
204 			}
205 			break;
206 		default:
207 			tst_resm(TBROK,
208 				 "Format string option %c not implemented", *p);
209 			return -1;
210 			break;
211 		}
212 	}
213 
214 	va_end(ap);
215 
216 	if (chdir(start_cwd) < 0) {
217 		tst_resm(TBROK, "Could not change to %s for self_exec",
218 			 start_cwd);
219 		return -1;
220 	}
221 
222 	return execlp(argv0, argv0, "-C", arg, (char *)NULL);
223 }
224 
225 #endif /* UCLINUX */
226