grub-editenv.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /* grub-editenv.c - tool to edit environment block. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <config.h>
  20. #include <grub/types.h>
  21. #include <grub/emu/misc.h>
  22. #include <grub/util/misc.h>
  23. #include <grub/lib/envblk.h>
  24. #include <grub/i18n.h>
  25. #include <grub/emu/hostfile.h>
  26. #include <grub/util/install.h>
  27. #include <stdio.h>
  28. #include <unistd.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #pragma GCC diagnostic ignored "-Wmissing-prototypes"
  32. #pragma GCC diagnostic ignored "-Wmissing-declarations"
  33. #include <argp.h>
  34. #pragma GCC diagnostic error "-Wmissing-prototypes"
  35. #pragma GCC diagnostic error "-Wmissing-declarations"
  36. #include "progname.h"
  37. #define DEFAULT_ENVBLK_PATH DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG
  38. static struct argp_option options[] = {
  39. {0, 0, 0, OPTION_DOC, N_("Commands:"), 1},
  40. {"create", 0, 0, OPTION_DOC|OPTION_NO_USAGE,
  41. N_("Create a blank environment block file."), 0},
  42. {"list", 0, 0, OPTION_DOC|OPTION_NO_USAGE,
  43. N_("List the current variables."), 0},
  44. /* TRANSLATORS: "set" is a keyword. It's a summary of "set" subcommand. */
  45. {N_("set [NAME=VALUE ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE,
  46. N_("Set variables."), 0},
  47. /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */
  48. {N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE,
  49. N_("Delete variables."), 0},
  50. {0, 0, 0, OPTION_DOC, N_("Options:"), -1},
  51. {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
  52. { 0, 0, 0, 0, 0, 0 }
  53. };
  54. /* Print the version information. */
  55. static void
  56. print_version (FILE *stream, struct argp_state *state)
  57. {
  58. fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
  59. }
  60. void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
  61. /* Set the bug report address */
  62. const char *argp_program_bug_address = "<"PACKAGE_BUGREPORT">";
  63. static error_t argp_parser (int key, char *arg, struct argp_state *state)
  64. {
  65. switch (key)
  66. {
  67. case 'v':
  68. verbosity++;
  69. break;
  70. case ARGP_KEY_NO_ARGS:
  71. fprintf (stderr, "%s",
  72. _("You need to specify at least one command.\n"));
  73. argp_usage (state);
  74. break;
  75. default:
  76. return ARGP_ERR_UNKNOWN;
  77. }
  78. return 0;
  79. }
  80. #pragma GCC diagnostic ignored "-Wformat-nonliteral"
  81. static char *
  82. help_filter (int key, const char *text, void *input __attribute__ ((unused)))
  83. {
  84. switch (key)
  85. {
  86. case ARGP_KEY_HELP_POST_DOC:
  87. return xasprintf (text, DEFAULT_ENVBLK_PATH, DEFAULT_ENVBLK_PATH);
  88. default:
  89. return (char *) text;
  90. }
  91. }
  92. #pragma GCC diagnostic error "-Wformat-nonliteral"
  93. struct argp argp = {
  94. options, argp_parser, N_("FILENAME COMMAND"),
  95. "\n"N_("\
  96. Tool to edit environment block.")
  97. "\v"N_("\
  98. If FILENAME is `-', the default value %s is used.\n\n\
  99. There is no `delete' command; if you want to delete the whole environment\n\
  100. block, use `rm %s'."),
  101. NULL, help_filter, NULL
  102. };
  103. static grub_envblk_t
  104. open_envblk_file (const char *name)
  105. {
  106. FILE *fp;
  107. char *buf;
  108. size_t size;
  109. grub_envblk_t envblk;
  110. fp = grub_util_fopen (name, "rb");
  111. if (! fp)
  112. {
  113. /* Create the file implicitly. */
  114. grub_util_create_envblk_file (name);
  115. fp = grub_util_fopen (name, "rb");
  116. if (! fp)
  117. grub_util_error (_("cannot open `%s': %s"), name,
  118. strerror (errno));
  119. }
  120. if (fseek (fp, 0, SEEK_END) < 0)
  121. grub_util_error (_("cannot seek `%s': %s"), name,
  122. strerror (errno));
  123. size = (size_t) ftell (fp);
  124. if (fseek (fp, 0, SEEK_SET) < 0)
  125. grub_util_error (_("cannot seek `%s': %s"), name,
  126. strerror (errno));
  127. buf = xmalloc (size);
  128. if (fread (buf, 1, size, fp) != size)
  129. grub_util_error (_("cannot read `%s': %s"), name,
  130. strerror (errno));
  131. fclose (fp);
  132. envblk = grub_envblk_open (buf, size);
  133. if (! envblk)
  134. grub_util_error ("%s", _("invalid environment block"));
  135. return envblk;
  136. }
  137. static int
  138. print_var (const char *varname, const char *value,
  139. void *hook_data __attribute__ ((unused)))
  140. {
  141. printf ("%s=%s\n", varname, value);
  142. return 0;
  143. }
  144. static void
  145. list_variables (const char *name)
  146. {
  147. grub_envblk_t envblk;
  148. envblk = open_envblk_file (name);
  149. grub_envblk_iterate (envblk, NULL, print_var);
  150. grub_envblk_close (envblk);
  151. }
  152. static void
  153. write_envblk (const char *name, grub_envblk_t envblk)
  154. {
  155. FILE *fp;
  156. fp = grub_util_fopen (name, "wb");
  157. if (! fp)
  158. grub_util_error (_("cannot open `%s': %s"), name,
  159. strerror (errno));
  160. if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp)
  161. != grub_envblk_size (envblk))
  162. grub_util_error (_("cannot write to `%s': %s"), name,
  163. strerror (errno));
  164. grub_util_file_sync (fp);
  165. fclose (fp);
  166. }
  167. static void
  168. set_variables (const char *name, int argc, char *argv[])
  169. {
  170. grub_envblk_t envblk;
  171. envblk = open_envblk_file (name);
  172. while (argc)
  173. {
  174. char *p;
  175. p = strchr (argv[0], '=');
  176. if (! p)
  177. grub_util_error (_("invalid parameter %s"), argv[0]);
  178. *(p++) = 0;
  179. if (! grub_envblk_set (envblk, argv[0], p))
  180. grub_util_error ("%s", _("environment block too small"));
  181. argc--;
  182. argv++;
  183. }
  184. write_envblk (name, envblk);
  185. grub_envblk_close (envblk);
  186. }
  187. static void
  188. unset_variables (const char *name, int argc, char *argv[])
  189. {
  190. grub_envblk_t envblk;
  191. envblk = open_envblk_file (name);
  192. while (argc)
  193. {
  194. grub_envblk_delete (envblk, argv[0]);
  195. argc--;
  196. argv++;
  197. }
  198. write_envblk (name, envblk);
  199. grub_envblk_close (envblk);
  200. }
  201. int
  202. main (int argc, char *argv[])
  203. {
  204. const char *filename;
  205. char *command;
  206. int curindex, arg_count;
  207. grub_util_host_init (&argc, &argv);
  208. /* Parse our arguments */
  209. if (argp_parse (&argp, argc, argv, 0, &curindex, 0) != 0)
  210. {
  211. fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
  212. exit(1);
  213. }
  214. arg_count = argc - curindex;
  215. if (arg_count == 1)
  216. {
  217. filename = DEFAULT_ENVBLK_PATH;
  218. command = argv[curindex++];
  219. }
  220. else
  221. {
  222. filename = argv[curindex++];
  223. if (strcmp (filename, "-") == 0)
  224. filename = DEFAULT_ENVBLK_PATH;
  225. command = argv[curindex++];
  226. }
  227. if (strcmp (command, "create") == 0)
  228. grub_util_create_envblk_file (filename);
  229. else if (strcmp (command, "list") == 0)
  230. list_variables (filename);
  231. else if (strcmp (command, "set") == 0)
  232. set_variables (filename, argc - curindex, argv + curindex);
  233. else if (strcmp (command, "unset") == 0)
  234. unset_variables (filename, argc - curindex, argv + curindex);
  235. else
  236. {
  237. char *program = xstrdup(program_name);
  238. fprintf (stderr, _("Unknown command `%s'.\n"), command);
  239. argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program);
  240. free(program);
  241. exit(1);
  242. }
  243. return 0;
  244. }