blob: 06441d3c3551c6f31f00f8b7a7ad0040af5ae4d7 [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
Mike Frysinger28606c12010-08-17 17:22:45 -040025#define _GNU_SOURCE /* for asprintf */
26
27#include "config.h"
28
vapierb56735e2006-08-21 07:05:41 +000029#ifdef UCLINUX
30
vapierb56735e2006-08-21 07:05:41 +000031#include <stdarg.h>
32#include <string.h>
33#include <stdio.h>
34#include "test.h"
35
36/* Set from parse_opts.c: */
37char *child_args; /* Arguments to child when -C is used */
38
39static char *start_cwd; /* Stores the starting directory for self_exec */
40
41int 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
70void
71maybe_run_child(void (*child)(), 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_resm(TBROK, NULL, "Could not get directory from -C option");
90 tst_exit();
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_resm(TBROK, "Invalid argument to -C option");
99 tst_exit();
100 }
101
102 switch (*p) {
103 case 'd':
104 iptr = va_arg(ap, int *);
105 i = strtol(tok, &endptr, 10);
106 if (*endptr != '\0') {
107 tst_resm(TBROK, "Invalid argument to -C option");
108 tst_exit();
109 }
110 *iptr = i;
111 break;
112 case 'n':
113 j = va_arg(ap, int);
114 i = strtol(tok, &endptr, 10);
115 if (*endptr != '\0') {
116 tst_resm(TBROK, "Invalid argument to -C option");
117 tst_exit();
118 }
vapier45a8ba02009-07-20 10:59:32 +0000119 if (j != i) {
vapierb56735e2006-08-21 07:05:41 +0000120 va_end(ap);
121 return;
122 }
123 break;
124 case 's':
125 s = va_arg(ap, char *);
126 if (!strncpy(s, tok, strlen(tok)+1)) {
127 tst_resm(TBROK, "Could not strncpy for -C option");
128 tst_exit();
129 }
130 break;
131 case 'S':
132 sptr = va_arg(ap, char **);
133 *sptr = strdup(tok);
134 if (!*sptr) {
135 tst_resm(TBROK, "Could not strdup for -C option");
136 tst_exit();
137 }
138 break;
139 default:
140 tst_resm(TBROK, "Format string option %c not implemented", *p);
141 tst_exit();
142 break;
143 }
144 }
145
146 va_end(ap);
147
148 if (chdir(child_dir) < 0) {
149 tst_resm(TBROK, "Could not change to %s for child", child_dir);
150 tst_exit();
151 }
152
153 (*child)();
154 tst_resm(TWARN, "Child function returned unexpectedly");
155 /* Exit here? or exit silently? */
156 }
157}
158
159int
160self_exec(char *argv0, char *fmt, ...)
161{
162 va_list ap;
163 char *p;
164 char *tmp_cwd;
165 char *arg;
166 int ival;
167 char *str;
168
169 if ((tmp_cwd = getcwd(NULL, 0)) == NULL) {
170 tst_resm(TBROK, "Could not getcwd()");
171 return -1;
172 }
173
174 arg = strdup( tmp_cwd );
175
176 if (( arg = strdup( tmp_cwd )) == NULL) {
177 tst_resm(TBROK, "Could not produce self_exec string");
178 return -1;
179 }
180
181 va_start(ap, fmt);
182
183 for (p = fmt; *p; p++) {
184 switch (*p) {
185 case 'd':
186 case 'n':
187 ival = va_arg(ap, int);
188 if (asprintf(&arg, "%s,%d", arg, ival) < 0) {
189 tst_resm(TBROK, "Could not produce self_exec string");
190 return -1;
191 }
192 break;
193 case 's':
194 case 'S':
195 str = va_arg(ap, char *);
196 if (asprintf(&arg, "%s,%s", arg, str) < 0) {
197 tst_resm(TBROK, "Could not produce self_exec string");
198 return -1;
199 }
200 break;
201 default:
202 tst_resm(TBROK, "Format string option %c not implemented", *p);
203 return -1;
204 break;
205 }
206 }
207
208 va_end(ap);
209
210 if (chdir(start_cwd) < 0) {
211 tst_resm(TBROK, "Could not change to %s for self_exec", start_cwd);
212 return -1;
213 }
214
215 return execlp(argv0, argv0, "-C", arg, (char *) NULL);
216}
217
218#endif /* UCLINUX */