grub-editenv.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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. long loc;
  109. size_t size;
  110. grub_envblk_t envblk;
  111. fp = grub_util_fopen (name, "rb");
  112. if (! fp)
  113. {
  114. /* Create the file implicitly. */
  115. grub_util_create_envblk_file (name);
  116. fp = grub_util_fopen (name, "rb");
  117. if (! fp)
  118. grub_util_error (_("cannot open `%s': %s"), name,
  119. strerror (errno));
  120. }
  121. if (fseek (fp, 0, SEEK_END) < 0)
  122. grub_util_error (_("cannot seek `%s': %s"), name,
  123. strerror (errno));
  124. loc = ftell (fp);
  125. if (loc < 0)
  126. grub_util_error (_("cannot get file location `%s': %s"), name,
  127. strerror (errno));
  128. size = (size_t) loc;
  129. if (fseek (fp, 0, SEEK_SET) < 0)
  130. grub_util_error (_("cannot seek `%s': %s"), name,
  131. strerror (errno));
  132. buf = xmalloc (size);
  133. if (fread (buf, 1, size, fp) != size)
  134. grub_util_error (_("cannot read `%s': %s"), name,
  135. strerror (errno));
  136. fclose (fp);
  137. envblk = grub_envblk_open (buf, size);
  138. if (! envblk)
  139. grub_util_error ("%s", _("invalid environment block"));
  140. return envblk;
  141. }
  142. static int
  143. print_var (const char *varname, const char *value,
  144. void *hook_data __attribute__ ((unused)))
  145. {
  146. printf ("%s=%s\n", varname, value);
  147. return 0;
  148. }
  149. static void
  150. list_variables (const char *name)
  151. {
  152. grub_envblk_t envblk;
  153. envblk = open_envblk_file (name);
  154. grub_envblk_iterate (envblk, NULL, print_var);
  155. grub_envblk_close (envblk);
  156. }
  157. static void
  158. write_envblk (const char *name, grub_envblk_t envblk)
  159. {
  160. FILE *fp;
  161. fp = grub_util_fopen (name, "wb");
  162. if (! fp)
  163. grub_util_error (_("cannot open `%s': %s"), name,
  164. strerror (errno));
  165. if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp)
  166. != grub_envblk_size (envblk))
  167. grub_util_error (_("cannot write to `%s': %s"), name,
  168. strerror (errno));
  169. if (grub_util_file_sync (fp) < 0)
  170. grub_util_error (_("cannot sync `%s': %s"), name, strerror (errno));
  171. fclose (fp);
  172. }
  173. static void
  174. set_variables (const char *name, int argc, char *argv[])
  175. {
  176. grub_envblk_t envblk;
  177. envblk = open_envblk_file (name);
  178. while (argc)
  179. {
  180. char *p;
  181. p = strchr (argv[0], '=');
  182. if (! p)
  183. grub_util_error (_("invalid parameter %s"), argv[0]);
  184. *(p++) = 0;
  185. if (! grub_envblk_set (envblk, argv[0], p))
  186. grub_util_error ("%s", _("environment block too small"));
  187. argc--;
  188. argv++;
  189. }
  190. write_envblk (name, envblk);
  191. grub_envblk_close (envblk);
  192. }
  193. static void
  194. unset_variables (const char *name, int argc, char *argv[])
  195. {
  196. grub_envblk_t envblk;
  197. envblk = open_envblk_file (name);
  198. while (argc)
  199. {
  200. grub_envblk_delete (envblk, argv[0]);
  201. argc--;
  202. argv++;
  203. }
  204. write_envblk (name, envblk);
  205. grub_envblk_close (envblk);
  206. }
  207. int
  208. main (int argc, char *argv[])
  209. {
  210. const char *filename;
  211. char *command;
  212. int curindex, arg_count;
  213. grub_util_host_init (&argc, &argv);
  214. /* Parse our arguments */
  215. if (argp_parse (&argp, argc, argv, 0, &curindex, 0) != 0)
  216. {
  217. fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
  218. exit(1);
  219. }
  220. arg_count = argc - curindex;
  221. if (arg_count == 1)
  222. {
  223. filename = DEFAULT_ENVBLK_PATH;
  224. command = argv[curindex++];
  225. }
  226. else
  227. {
  228. filename = argv[curindex++];
  229. if (strcmp (filename, "-") == 0)
  230. filename = DEFAULT_ENVBLK_PATH;
  231. command = argv[curindex++];
  232. }
  233. if (strcmp (command, "create") == 0)
  234. grub_util_create_envblk_file (filename);
  235. else if (strcmp (command, "list") == 0)
  236. list_variables (filename);
  237. else if (strcmp (command, "set") == 0)
  238. set_variables (filename, argc - curindex, argv + curindex);
  239. else if (strcmp (command, "unset") == 0)
  240. unset_variables (filename, argc - curindex, argv + curindex);
  241. else
  242. {
  243. char *program = xstrdup(program_name);
  244. fprintf (stderr, _("Unknown command `%s'.\n"), command);
  245. argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program);
  246. free(program);
  247. exit(1);
  248. }
  249. return 0;
  250. }