blob: 4b554cfa6c6fbd0b591fe666a55c78a7fb3caa22 [file] [log] [blame]
vapierb56735e2006-08-21 07:05:41 +00001/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: t -*- */
vapier45a8ba02009-07-20 10:59:32 +00002/*
vapierb56735e2006-08-21 07:05:41 +00003 * self_exec.c: self_exec magic required to run child functions on uClinux
vapier45a8ba02009-07-20 10:59:32 +00004 *
vapierb56735e2006-08-21 07:05:41 +00005 * Copyright (C) 2005 Paul J.Y. Lahaie <pjlahaie-at-steamballoon.com>
vapier45a8ba02009-07-20 10:59:32 +00006 *
vapierb56735e2006-08-21 07:05:41 +00007 * 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.
vapier45a8ba02009-07-20 10:59:32 +000011 *
vapierb56735e2006-08-21 07:05:41 +000012 * 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.
vapier45a8ba02009-07-20 10:59:32 +000016 *
vapierb56735e2006-08-21 07:05:41 +000017 * 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.
vapier45a8ba02009-07-20 10:59:32 +000020 *
vapierb56735e2006-08-21 07:05:41 +000021 * This software was produced by Steamballoon Incorporated
22 * 55 Byward Market Square, 2nd Floor North, Ottawa, ON K1N 9C3, Canada
23 */
24
25#ifdef UCLINUX
26
27#define _GNU_SOURCE /* for asprintf */
28#include <stdarg.h>
29#include <string.h>
30#include <stdio.h>
31#include "test.h"
32
33/* Set from parse_opts.c: */
34char *child_args; /* Arguments to child when -C is used */
35
36static char *start_cwd; /* Stores the starting directory for self_exec */
37
38int asprintf(char **app, const char *fmt, ...)
39{
40 va_list ptr;
41 int rv;
42 char *p;
43
44 /*
45 * First iteration - find out size of buffer required and allocate it.
46 */
47 va_start(ptr, fmt);
48 rv = vsnprintf(NULL, 0, fmt, ptr);
49 va_end(ptr);
50
51 p = malloc(++rv); /* allocate the buffer */
52 *app = p;
53 if (!p) {
54 return -1;
55 }
56
57 /*
58 * Second iteration - actually produce output.
59 */
60 va_start(ptr, fmt);
61 rv = vsnprintf(p, rv, fmt, ptr);
62 va_end(ptr);
63
64 return rv;
65}
66
67void
68maybe_run_child(void (*child)(), char *fmt, ...)
69{
70 va_list ap;
71 char *child_dir;
72 char *p, *tok;
73 int *iptr, i, j;
74 char *s;
75 char **sptr;
76 char *endptr;
77
78 /* Store the current directory for later use. */
79 start_cwd = getcwd(NULL, 0);
80
81 if (child_args) {
82 char *args = strdup(child_args);
83
84 child_dir = strtok(args, ",");
85 if (strlen(child_dir) == 0) {
86 tst_resm(TBROK, NULL, "Could not get directory from -C option");
87 tst_exit();
88 }
89
90 va_start(ap, fmt);
91
92 for (p = fmt; *p; p++) {
93 tok = strtok(NULL, ",");
94 if (!tok || strlen(tok) == 0) {
95 tst_resm(TBROK, "Invalid argument to -C option");
96 tst_exit();
97 }
98
99 switch (*p) {
100 case 'd':
101 iptr = va_arg(ap, int *);
102 i = strtol(tok, &endptr, 10);
103 if (*endptr != '\0') {
104 tst_resm(TBROK, "Invalid argument to -C option");
105 tst_exit();
106 }
107 *iptr = i;
108 break;
109 case 'n':
110 j = va_arg(ap, int);
111 i = strtol(tok, &endptr, 10);
112 if (*endptr != '\0') {
113 tst_resm(TBROK, "Invalid argument to -C option");
114 tst_exit();
115 }
vapier45a8ba02009-07-20 10:59:32 +0000116 if (j != i) {
vapierb56735e2006-08-21 07:05:41 +0000117 va_end(ap);
118 return;
119 }
120 break;
121 case 's':
122 s = va_arg(ap, char *);
123 if (!strncpy(s, tok, strlen(tok)+1)) {
124 tst_resm(TBROK, "Could not strncpy for -C option");
125 tst_exit();
126 }
127 break;
128 case 'S':
129 sptr = va_arg(ap, char **);
130 *sptr = strdup(tok);
131 if (!*sptr) {
132 tst_resm(TBROK, "Could not strdup for -C option");
133 tst_exit();
134 }
135 break;
136 default:
137 tst_resm(TBROK, "Format string option %c not implemented", *p);
138 tst_exit();
139 break;
140 }
141 }
142
143 va_end(ap);
144
145 if (chdir(child_dir) < 0) {
146 tst_resm(TBROK, "Could not change to %s for child", child_dir);
147 tst_exit();
148 }
149
150 (*child)();
151 tst_resm(TWARN, "Child function returned unexpectedly");
152 /* Exit here? or exit silently? */
153 }
154}
155
156int
157self_exec(char *argv0, char *fmt, ...)
158{
159 va_list ap;
160 char *p;
161 char *tmp_cwd;
162 char *arg;
163 int ival;
164 char *str;
165
166 if ((tmp_cwd = getcwd(NULL, 0)) == NULL) {
167 tst_resm(TBROK, "Could not getcwd()");
168 return -1;
169 }
170
171 arg = strdup( tmp_cwd );
172
173 if (( arg = strdup( tmp_cwd )) == NULL) {
174 tst_resm(TBROK, "Could not produce self_exec string");
175 return -1;
176 }
177
178 va_start(ap, fmt);
179
180 for (p = fmt; *p; p++) {
181 switch (*p) {
182 case 'd':
183 case 'n':
184 ival = va_arg(ap, int);
185 if (asprintf(&arg, "%s,%d", arg, ival) < 0) {
186 tst_resm(TBROK, "Could not produce self_exec string");
187 return -1;
188 }
189 break;
190 case 's':
191 case 'S':
192 str = va_arg(ap, char *);
193 if (asprintf(&arg, "%s,%s", arg, str) < 0) {
194 tst_resm(TBROK, "Could not produce self_exec string");
195 return -1;
196 }
197 break;
198 default:
199 tst_resm(TBROK, "Format string option %c not implemented", *p);
200 return -1;
201 break;
202 }
203 }
204
205 va_end(ap);
206
207 if (chdir(start_cwd) < 0) {
208 tst_resm(TBROK, "Could not change to %s for self_exec", start_cwd);
209 return -1;
210 }
211
212 return execlp(argv0, argv0, "-C", arg, (char *) NULL);
213}
214
215#endif /* UCLINUX */