1171195Sscf/*- 2181150Sscf * Copyright (c) 2007-2008 Sean C. Farley <scf@FreeBSD.org> 3171195Sscf * All rights reserved. 4171195Sscf * 5171195Sscf * Redistribution and use in source and binary forms, with or without 6171195Sscf * modification, are permitted provided that the following conditions 7171195Sscf * are met: 8171195Sscf * 1. Redistributions of source code must retain the above copyright 9171195Sscf * notice, this list of conditions and the following disclaimer, 10171195Sscf * without modification, immediately at the beginning of the file. 11171195Sscf * 2. Redistributions in binary form must reproduce the above copyright 12171195Sscf * notice, this list of conditions and the following disclaimer in the 13171195Sscf * documentation and/or other materials provided with the distribution. 14171195Sscf * 15171195Sscf * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16171195Sscf * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17171195Sscf * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18171195Sscf * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19171195Sscf * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20171195Sscf * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21171195Sscf * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22171195Sscf * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23171195Sscf * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24171195Sscf * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25171195Sscf */ 26171195Sscf#include <errno.h> 27171195Sscf#include <libgen.h> 28171195Sscf#include <stdbool.h> 29171195Sscf#include <stdio.h> 30171195Sscf#include <stdlib.h> 31171195Sscf#include <string.h> 32171195Sscf#include <unistd.h> 33171195Sscf 34171195Sscf 35171195Sscf#include <sys/cdefs.h> 36171195Sscf__FBSDID("$FreeBSD: releng/10.3/tools/regression/environ/envctl.c 199983 2009-12-01 05:04:31Z green $"); 37171195Sscf 38171195Sscf 39171195Sscfextern char **environ; 40171195Sscf 41171195Sscf 42176676Sscf/* 43176676Sscf * Print entire environ array. 44176676Sscf */ 45171195Sscfstatic void 46171195Sscfdump_environ(void) 47171195Sscf{ 48171195Sscf char **environPtr; 49171195Sscf 50176676Sscf for (environPtr = environ; *environPtr != NULL; environPtr++) 51171195Sscf printf("%s\n", *environPtr); 52171195Sscf 53171195Sscf return; 54171195Sscf} 55171195Sscf 56171195Sscf 57176676Sscf/* 58176676Sscf * Print usage. 59176676Sscf */ 60171195Sscfstatic void 61171195Sscfusage(const char *program) 62171195Sscf{ 63199983Sgreen fprintf(stderr, "Usage: %s [-DGUchrt] [-c 1|2|3|4] [-bgu name] " 64181150Sscf "[-p name=value]\n" 65181150Sscf "\t[(-S|-s name) value overwrite]\n\n" 66171195Sscf "Options:\n" 67171195Sscf " -D\t\t\t\tDump environ\n" 68171195Sscf " -G name\t\t\tgetenv(NULL)\n" 69171195Sscf " -S value overwrite\t\tsetenv(NULL, value, overwrite)\n" 70171195Sscf " -U\t\t\t\tunsetenv(NULL)\n" 71199983Sgreen " -b name\t\t\tblank the 'name=$name' entry, corrupting it\n" 72181150Sscf " -c 1|2|3|4\t\t\tClear environ variable using method:\n" 73181150Sscf "\t\t\t\t1 - set environ to NULL pointer\n" 74181150Sscf "\t\t\t\t2 - set environ[0] to NULL pointer\n" 75181150Sscf "\t\t\t\t3 - set environ to calloc()'d NULL-terminated array\n" 76181150Sscf "\t\t\t\t4 - set environ to static NULL-terminated array\n" 77171195Sscf " -g name\t\t\tgetenv(name)\n" 78171195Sscf " -h\t\t\t\tHelp\n" 79171195Sscf " -p name=value\t\t\tputenv(name=value)\n" 80171525Sscf " -r\t\t\t\treplace environ with { \"FOO=bar\", NULL }\n" 81171195Sscf " -s name value overwrite\tsetenv(name, value, overwrite)\n" 82171195Sscf " -t\t\t\t\tOutput is suitable for testing (no newlines)\n" 83171195Sscf " -u name\t\t\tunsetenv(name)\n", 84171195Sscf basename(program)); 85171195Sscf 86171195Sscf return; 87171195Sscf} 88171195Sscf 89171195Sscf 90176676Sscf/* 91176676Sscf * Print the return value of a call along with errno upon error else zero. 92176676Sscf * Also, use the eol string based upon whether running in test mode or not. 93176676Sscf */ 94176676Sscfstatic void 95176676Sscfprint_rtrn_errno(int rtrnVal, const char *eol) 96176676Sscf{ 97176676Sscf printf("%d %d%s", rtrnVal, rtrnVal != 0 ? errno : 0, eol); 98176676Sscf 99176676Sscf return; 100176676Sscf} 101176676Sscf 102199983Sgreenstatic void 103199983Sgreenblank_env(const char *var) 104199983Sgreen{ 105199983Sgreen char **newenviron; 106199983Sgreen int n, varlen; 107176676Sscf 108199983Sgreen if (environ == NULL) 109199983Sgreen return; 110199983Sgreen 111199983Sgreen for (n = 0; environ[n] != NULL; n++) 112199983Sgreen ; 113199983Sgreen newenviron = malloc(sizeof(char *) * (n + 1)); 114199983Sgreen varlen = strlen(var); 115199983Sgreen for (; n >= 0; n--) { 116199983Sgreen newenviron[n] = environ[n]; 117199983Sgreen if (newenviron[n] != NULL && 118199983Sgreen strncmp(newenviron[n], var, varlen) == 0 && 119199983Sgreen newenviron[n][varlen] == '=') 120199983Sgreen newenviron[n] += strlen(newenviron[n]); 121199983Sgreen } 122199983Sgreen environ = newenviron; 123199983Sgreen} 124199983Sgreen 125171195Sscfint 126171195Sscfmain(int argc, char **argv) 127171195Sscf{ 128171195Sscf char arg; 129171195Sscf const char *eol = "\n"; 130171195Sscf const char *value; 131181150Sscf static char *emptyEnv[] = { NULL }; 132181150Sscf static char *staticEnv[] = { "FOO=bar", NULL }; 133171195Sscf 134171195Sscf if (argc == 1) { 135171195Sscf usage(argv[0]); 136171195Sscf exit(EXIT_FAILURE); 137171195Sscf } 138171195Sscf 139176676Sscf /* The entire program is basically executed from this loop. */ 140199983Sgreen while ((arg = getopt(argc, argv, "DGS:Ub:c:g:hp:rs:tu:")) != -1) { 141171195Sscf switch (arg) { 142199983Sgreen case 'b': 143199983Sgreen blank_env(optarg); 144199983Sgreen break; 145199983Sgreen 146181150Sscf case 'c': 147181150Sscf switch (atoi(optarg)) { 148181150Sscf case 1: 149181150Sscf environ = NULL; 150181150Sscf break; 151171525Sscf 152181150Sscf case 2: 153181150Sscf environ[0] = NULL; 154181150Sscf break; 155181150Sscf 156181150Sscf case 3: 157181150Sscf environ = calloc(1, sizeof(*environ)); 158181150Sscf break; 159181150Sscf 160181150Sscf case 4: 161181150Sscf environ = emptyEnv; 162181150Sscf break; 163181150Sscf } 164181149Sscf break; 165171525Sscf 166181149Sscf case 'D': 167181149Sscf dump_environ(); 168181149Sscf break; 169171195Sscf 170181149Sscf case 'G': 171181149Sscf case 'g': 172181149Sscf value = getenv(arg == 'g' ? optarg : NULL); 173181149Sscf printf("%s%s", value == NULL ? "*NULL*" : value, eol); 174181149Sscf break; 175171195Sscf 176181149Sscf case 'p': 177181149Sscf print_rtrn_errno(putenv(optarg), eol); 178181149Sscf break; 179171195Sscf 180181149Sscf case 'r': 181181149Sscf environ = staticEnv; 182181149Sscf break; 183171525Sscf 184181149Sscf case 'S': 185181149Sscf print_rtrn_errno(setenv(NULL, optarg, 186181149Sscf atoi(argv[optind])), eol); 187181149Sscf optind += 1; 188181149Sscf break; 189171195Sscf 190181149Sscf case 's': 191181149Sscf print_rtrn_errno(setenv(optarg, argv[optind], 192181149Sscf atoi(argv[optind + 1])), eol); 193181149Sscf optind += 2; 194181149Sscf break; 195171195Sscf 196181149Sscf case 't': 197181149Sscf eol = " "; 198181149Sscf break; 199171195Sscf 200181149Sscf case 'U': 201181149Sscf case 'u': 202181149Sscf print_rtrn_errno(unsetenv(arg == 'u' ? optarg : NULL), 203181149Sscf eol); 204181149Sscf break; 205171195Sscf 206181149Sscf case 'h': 207181149Sscf default: 208181149Sscf usage(argv[0]); 209181149Sscf exit(EXIT_FAILURE); 210171195Sscf } 211171195Sscf } 212171195Sscf 213176676Sscf /* Output a closing newline in test mode. */ 214171195Sscf if (eol[0] == ' ') 215171195Sscf printf("\n"); 216171195Sscf 217171195Sscf return (EXIT_SUCCESS); 218171195Sscf} 219