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