blob: c287ce913d1b76350ce2f40bebd2c797928d8fa3 [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
Wanlong Gao354ebb42012-12-07 10:10:04 +080025#define _GNU_SOURCE /* for asprintf */
Mike Frysinger28606c12010-08-17 17:22:45 -040026
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: */
Wanlong Gao354ebb42012-12-07 10:10:04 +080037char *child_args; /* Arguments to child when -C is used */
vapierb56735e2006-08-21 07:05:41 +000038
Wanlong Gao354ebb42012-12-07 10:10:04 +080039static char *start_cwd; /* Stores the starting directory for self_exec */
vapierb56735e2006-08-21 07:05:41 +000040
41int asprintf(char **app, const char *fmt, ...)
42{
Wanlong Gao354ebb42012-12-07 10:10:04 +080043 va_list ptr;
44 int rv;
45 char *p;
vapierb56735e2006-08-21 07:05:41 +000046
Wanlong Gao354ebb42012-12-07 10:10:04 +080047 /*
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);
vapierb56735e2006-08-21 07:05:41 +000053
Wanlong Gao354ebb42012-12-07 10:10:04 +080054 p = malloc(++rv); /* allocate the buffer */
55 *app = p;
56 if (!p) {
57 return -1;
58 }
vapierb56735e2006-08-21 07:05:41 +000059
Wanlong Gao354ebb42012-12-07 10:10:04 +080060 /*
61 * Second iteration - actually produce output.
62 */
63 va_start(ptr, fmt);
64 rv = vsnprintf(p, rv, fmt, ptr);
65 va_end(ptr);
vapierb56735e2006-08-21 07:05:41 +000066
Wanlong Gao354ebb42012-12-07 10:10:04 +080067 return rv;
vapierb56735e2006-08-21 07:05:41 +000068}
69
Mike Frysinger55d8ae52014-02-13 04:11:45 -050070void maybe_run_child(void (*child) (), const char *fmt, ...)
vapierb56735e2006-08-21 07:05:41 +000071{
Wanlong Gao354ebb42012-12-07 10:10:04 +080072 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;
vapierb56735e2006-08-21 07:05:41 +000079
Wanlong Gao354ebb42012-12-07 10:10:04 +080080 /* Store the current directory for later use. */
81 start_cwd = getcwd(NULL, 0);
vapierb56735e2006-08-21 07:05:41 +000082
Wanlong Gao354ebb42012-12-07 10:10:04 +080083 if (child_args) {
84 char *args = strdup(child_args);
vapierb56735e2006-08-21 07:05:41 +000085
Wanlong Gao354ebb42012-12-07 10:10:04 +080086 child_dir = strtok(args, ",");
87 if (strlen(child_dir) == 0) {
88 tst_brkm(TBROK, NULL,
89 "Could not get directory from -C option");
Cyril Hrubisd101cab2017-02-14 11:48:46 +010090 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +080091 }
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");
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100100 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800101 }
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");
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100110 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800111 }
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");
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100120 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800121 }
122 if (j != i) {
123 va_end(ap);
Manjeet Pawarc4140402015-05-28 04:41:36 +0000124 free(args);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800125 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");
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100133 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800134 }
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");
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100142 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800143 }
144 break;
145 default:
146 tst_brkm(TBROK, NULL,
147 "Format string option %c not implemented",
148 *p);
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100149 return;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800150 }
151 }
152
153 va_end(ap);
Manjeet Pawarc4140402015-05-28 04:41:36 +0000154 free(args);
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100155 if (chdir(child_dir) < 0) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800156 tst_brkm(TBROK, NULL,
157 "Could not change to %s for child", child_dir);
Cyril Hrubisd101cab2017-02-14 11:48:46 +0100158 return;
159 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800160
161 (*child) ();
162 tst_resm(TWARN, "Child function returned unexpectedly");
163 /* Exit here? or exit silently? */
164 }
165}
166
Mike Frysinger55d8ae52014-02-13 04:11:45 -0500167int self_exec(const char *argv0, const char *fmt, ...)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800168{
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);
Manjeet Pawarc4140402015-05-28 04:41:36 +0000182 if (arg == NULL) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800183 tst_resm(TBROK, "Could not produce self_exec string");
184 return -1;
vapierb56735e2006-08-21 07:05:41 +0000185 }
186
187 va_start(ap, fmt);
188
189 for (p = fmt; *p; p++) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800190 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;
vapierb56735e2006-08-21 07:05:41 +0000214 }
vapierb56735e2006-08-21 07:05:41 +0000215 }
216
217 va_end(ap);
218
Wanlong Gao354ebb42012-12-07 10:10:04 +0800219 if (chdir(start_cwd) < 0) {
220 tst_resm(TBROK, "Could not change to %s for self_exec",
221 start_cwd);
vapierb56735e2006-08-21 07:05:41 +0000222 return -1;
vapierb56735e2006-08-21 07:05:41 +0000223 }
vapierb56735e2006-08-21 07:05:41 +0000224
Wanlong Gao354ebb42012-12-07 10:10:04 +0800225 return execlp(argv0, argv0, "-C", arg, (char *)NULL);
vapierb56735e2006-08-21 07:05:41 +0000226}
227
Markos Chandras8d2d8ba2012-01-03 10:40:50 +0000228#endif /* UCLINUX */