• 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 
36 /* Set from parse_opts.c: */
37 char *child_args;		/* Arguments to child when -C is used */
38 
39 static char *start_cwd;		/* Stores the starting directory for self_exec */
40 
asprintf(char ** app,const char * fmt,...)41 int asprintf(char **app, const char *fmt, ...)
42 {
43 	va_list ptr;
44 	int rv;
45 	char *p;
46 
47 	/*
48 	 * First iteration - find out size of buffer required and allocate it.
49 	 */
50 	va_start(ptr, fmt);
51 	rv = vsnprintf(NULL, 0, fmt, ptr);
52 	va_end(ptr);
53 
54 	p = malloc(++rv);	/* allocate the buffer */
55 	*app = p;
56 	if (!p) {
57 		return -1;
58 	}
59 
60 	/*
61 	 * Second iteration - actually produce output.
62 	 */
63 	va_start(ptr, fmt);
64 	rv = vsnprintf(p, rv, fmt, ptr);
65 	va_end(ptr);
66 
67 	return rv;
68 }
69 
maybe_run_child(void (* child)(),const char * fmt,...)70 void maybe_run_child(void (*child) (), const char *fmt, ...)
71 {
72 	va_list ap;
73 	char *child_dir;
74 	char *p, *tok;
75 	int *iptr, i, j;
76 	char *s;
77 	char **sptr;
78 	char *endptr;
79 
80 	/* Store the current directory for later use. */
81 	start_cwd = getcwd(NULL, 0);
82 
83 	if (child_args) {
84 		char *args = strdup(child_args);
85 
86 		child_dir = strtok(args, ",");
87 		if (strlen(child_dir) == 0) {
88 			tst_brkm(TBROK, NULL,
89 				 "Could not get directory from -C option");
90 			return;
91 		}
92 
93 		va_start(ap, fmt);
94 
95 		for (p = fmt; *p; p++) {
96 			tok = strtok(NULL, ",");
97 			if (!tok || strlen(tok) == 0) {
98 				tst_brkm(TBROK, NULL,
99 					 "Invalid argument to -C option");
100 				return;
101 			}
102 
103 			switch (*p) {
104 			case 'd':
105 				iptr = va_arg(ap, int *);
106 				i = strtol(tok, &endptr, 10);
107 				if (*endptr != '\0') {
108 					tst_brkm(TBROK, NULL,
109 						 "Invalid argument to -C option");
110 					return;
111 				}
112 				*iptr = i;
113 				break;
114 			case 'n':
115 				j = va_arg(ap, int);
116 				i = strtol(tok, &endptr, 10);
117 				if (*endptr != '\0') {
118 					tst_brkm(TBROK, NULL,
119 						 "Invalid argument to -C option");
120 					return;
121 				}
122 				if (j != i) {
123 					va_end(ap);
124 					free(args);
125 					return;
126 				}
127 				break;
128 			case 's':
129 				s = va_arg(ap, char *);
130 				if (!strncpy(s, tok, strlen(tok) + 1)) {
131 					tst_brkm(TBROK, NULL,
132 						 "Could not strncpy for -C option");
133 					return;
134 				}
135 				break;
136 			case 'S':
137 				sptr = va_arg(ap, char **);
138 				*sptr = strdup(tok);
139 				if (!*sptr) {
140 					tst_brkm(TBROK, NULL,
141 						 "Could not strdup for -C option");
142 					return;
143 				}
144 				break;
145 			default:
146 				tst_brkm(TBROK, NULL,
147 					 "Format string option %c not implemented",
148 					 *p);
149 				return;
150 			}
151 		}
152 
153 		va_end(ap);
154 		free(args);
155 		if (chdir(child_dir) < 0) {
156 			tst_brkm(TBROK, NULL,
157 				 "Could not change to %s for child", child_dir);
158 			return;
159 		}
160 
161 		(*child) ();
162 		tst_resm(TWARN, "Child function returned unexpectedly");
163 		/* Exit here? or exit silently? */
164 	}
165 }
166 
self_exec(const char * argv0,const char * fmt,...)167 int self_exec(const char *argv0, const char *fmt, ...)
168 {
169 	va_list ap;
170 	char *p;
171 	char *tmp_cwd;
172 	char *arg;
173 	int ival;
174 	char *str;
175 
176 	if ((tmp_cwd = getcwd(NULL, 0)) == NULL) {
177 		tst_resm(TBROK, "Could not getcwd()");
178 		return -1;
179 	}
180 
181 	arg = strdup(tmp_cwd);
182 	if (arg == NULL) {
183 		tst_resm(TBROK, "Could not produce self_exec string");
184 		return -1;
185 	}
186 
187 	va_start(ap, fmt);
188 
189 	for (p = fmt; *p; p++) {
190 		switch (*p) {
191 		case 'd':
192 		case 'n':
193 			ival = va_arg(ap, int);
194 			if (asprintf(&arg, "%s,%d", arg, ival) < 0) {
195 				tst_resm(TBROK,
196 					 "Could not produce self_exec string");
197 				return -1;
198 			}
199 			break;
200 		case 's':
201 		case 'S':
202 			str = va_arg(ap, char *);
203 			if (asprintf(&arg, "%s,%s", arg, str) < 0) {
204 				tst_resm(TBROK,
205 					 "Could not produce self_exec string");
206 				return -1;
207 			}
208 			break;
209 		default:
210 			tst_resm(TBROK,
211 				 "Format string option %c not implemented", *p);
212 			return -1;
213 			break;
214 		}
215 	}
216 
217 	va_end(ap);
218 
219 	if (chdir(start_cwd) < 0) {
220 		tst_resm(TBROK, "Could not change to %s for self_exec",
221 			 start_cwd);
222 		return -1;
223 	}
224 
225 	return execlp(argv0, argv0, "-C", arg, (char *)NULL);
226 }
227 
228 #endif /* UCLINUX */
229