env.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. env.c
  5. Abstract:
  6. This module implements support for the env utility.
  7. Author:
  8. Evan Green 26-Aug-2013
  9. Environment:
  10. POSIX
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/lib/types.h>
  16. #include <assert.h>
  17. #include <errno.h>
  18. #include <getopt.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include "swlib.h"
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. #define ENV_VERSION_MAJOR 1
  27. #define ENV_VERSION_MINOR 0
  28. #define ENV_USAGE \
  29. "usage: env [-i] [-] [-u name] [name=value]... [utility [argument...]]\n" \
  30. "The env utility executes the given utility after setting the given \n" \
  31. "environment variables. If no utility is supplied, the resulting \n" \
  32. "environment shall be written to standard output.\n" \
  33. "Options are:\n" \
  34. " -i, --ignore-environment -- Invoke the utility with exactly the \n" \
  35. " environment specified; the inherited environment shall be \n" \
  36. " ignored completely. A lone - is equivalent to the -i option.\n" \
  37. " -u, --unset <name> -- Unset the given environment variable.\n" \
  38. " --help -- Display this help text and exit.\n" \
  39. " --version -- Display the application version and exit.\n"
  40. #define ENV_OPTIONS_STRING "+iu:"
  41. //
  42. // Set this option to disable inheriting of the current environment.
  43. //
  44. #define ENV_OPTION_NO_INHERIT 0x00000001
  45. //
  46. // ------------------------------------------------------ Data Type Definitions
  47. //
  48. //
  49. // ----------------------------------------------- Internal Function Prototypes
  50. //
  51. //
  52. // -------------------------------------------------------------------- Globals
  53. //
  54. extern char **environ;
  55. struct option EnvLongOptions[] = {
  56. {"ignore-environment", no_argument, NULL, 'i'},
  57. {"unset", required_argument, NULL, 'u'},
  58. {"help", no_argument, NULL, 'h'},
  59. {"version", no_argument, NULL, 'V'},
  60. {NULL, 0, NULL, 0}
  61. };
  62. //
  63. // ------------------------------------------------------------------ Functions
  64. //
  65. INT
  66. EnvMain (
  67. INT ArgumentCount,
  68. CHAR **Arguments
  69. )
  70. /*++
  71. Routine Description:
  72. This routine is the main entry point for the env utility.
  73. Arguments:
  74. ArgumentCount - Supplies the number of command line arguments the program
  75. was invoked with.
  76. Arguments - Supplies a tokenized array of command line arguments.
  77. Return Value:
  78. Returns an integer exit code. 0 for success, nonzero otherwise.
  79. --*/
  80. {
  81. PSTR Argument;
  82. ULONG ArgumentIndex;
  83. ULONG EnvironmentIndex;
  84. INT Option;
  85. ULONG Options;
  86. int Status;
  87. Options = 0;
  88. //
  89. // Process the control arguments.
  90. //
  91. while (TRUE) {
  92. Option = getopt_long(ArgumentCount,
  93. Arguments,
  94. ENV_OPTIONS_STRING,
  95. EnvLongOptions,
  96. NULL);
  97. if (Option == -1) {
  98. //
  99. // Check for a lonely dash, which is the same as -i.
  100. //
  101. ArgumentIndex = optind;
  102. if (ArgumentIndex < ArgumentCount) {
  103. Argument = Arguments[ArgumentIndex];
  104. if (strcmp(Argument, "-") == 0) {
  105. Options |= ENV_OPTION_NO_INHERIT;
  106. optind += 1;
  107. }
  108. }
  109. break;
  110. }
  111. if ((Option == '?') || (Option == ':')) {
  112. Status = 1;
  113. goto MainEnd;
  114. }
  115. switch (Option) {
  116. case 'i':
  117. Options |= ENV_OPTION_NO_INHERIT;
  118. break;
  119. case 'V':
  120. SwPrintVersion(ENV_VERSION_MAJOR, ENV_VERSION_MINOR);
  121. return 1;
  122. case 'h':
  123. printf(ENV_USAGE);
  124. return 1;
  125. case 'u':
  126. Argument = optarg;
  127. assert(Argument != NULL);
  128. //
  129. // Calling putenv without an equals unsets the variable.
  130. //
  131. putenv(Argument);
  132. break;
  133. default:
  134. assert(FALSE);
  135. Status = 1;
  136. goto MainEnd;
  137. }
  138. }
  139. ArgumentIndex = optind;
  140. if (ArgumentIndex > ArgumentCount) {
  141. ArgumentIndex = ArgumentCount;
  142. }
  143. //
  144. // Clear the environment if requested.
  145. //
  146. if ((Options & ENV_OPTION_NO_INHERIT) != 0) {
  147. environ = NULL;
  148. }
  149. //
  150. // Loop setting environment variables as long as there are arguments with
  151. // an equals sign.
  152. //
  153. while (ArgumentIndex < ArgumentCount) {
  154. Argument = Arguments[ArgumentIndex];
  155. if (strchr(Argument, '=') == NULL) {
  156. break;
  157. }
  158. Status = putenv(Argument);
  159. if (Status != 0) {
  160. SwPrintError(errno, Argument, "Failed to set variable");
  161. goto MainEnd;
  162. }
  163. ArgumentIndex += 1;
  164. }
  165. //
  166. // If there are more arguments, then execute that utility with those
  167. // arguments.
  168. //
  169. if (ArgumentIndex < ArgumentCount) {
  170. Status = SwExec(Arguments[ArgumentIndex],
  171. Arguments + ArgumentIndex,
  172. ArgumentCount - ArgumentIndex);
  173. SwPrintError(errno, Arguments[ArgumentIndex], "Failed to exec");
  174. goto MainEnd;
  175. }
  176. //
  177. // There are no arguments, so print the current environment.
  178. //
  179. if (environ == NULL) {
  180. Status = 0;
  181. goto MainEnd;
  182. }
  183. EnvironmentIndex = 0;
  184. while (environ[EnvironmentIndex] != NULL) {
  185. printf("%s\n", environ[EnvironmentIndex]);
  186. EnvironmentIndex += 1;
  187. }
  188. Status = 0;
  189. MainEnd:
  190. return Status;
  191. }
  192. //
  193. // --------------------------------------------------------- Internal Functions
  194. //