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: */ 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 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 167int 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