123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- /* envblk.c - Common functions for environment block. */
- /*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2008,2009 Free Software Foundation, Inc.
- *
- * GRUB is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GRUB is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <config.h>
- #include <grub/types.h>
- #include <grub/misc.h>
- #include <grub/mm.h>
- #include <grub/lib/envblk.h>
- grub_envblk_t
- grub_envblk_open (char *buf, grub_size_t size)
- {
- grub_envblk_t envblk;
- if (size < sizeof (GRUB_ENVBLK_SIGNATURE)
- || grub_memcmp (buf, GRUB_ENVBLK_SIGNATURE,
- sizeof (GRUB_ENVBLK_SIGNATURE) - 1))
- {
- grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
- return 0;
- }
- envblk = grub_malloc (sizeof (*envblk));
- if (envblk)
- {
- envblk->buf = buf;
- envblk->size = size;
- }
- return envblk;
- }
- void
- grub_envblk_close (grub_envblk_t envblk)
- {
- grub_free (envblk->buf);
- grub_free (envblk);
- }
- static int
- escaped_value_len (const char *value)
- {
- int n = 0;
- char *p;
- for (p = (char *) value; *p; p++)
- {
- if (*p == '\\' || *p == '\n')
- n += 2;
- else
- n++;
- }
- return n;
- }
- static char *
- find_next_line (char *p, const char *pend)
- {
- while (p < pend)
- {
- if (*p == '\\')
- p += 2;
- else if (*p == '\n')
- break;
- else
- p++;
- }
- return p + 1;
- }
- int
- grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value)
- {
- char *p, *pend;
- char *space;
- int found = 0;
- int nl;
- int vl;
- int i;
- nl = grub_strlen (name);
- vl = escaped_value_len (value);
- p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
- pend = envblk->buf + envblk->size;
- /* First, look at free space. */
- for (space = pend - 1; *space == '#'; space--)
- ;
- if (*space != '\n')
- /* Broken. */
- return 0;
- space++;
- while (p + nl + 1 < space)
- {
- if (grub_memcmp (p, name, nl) == 0 && p[nl] == '=')
- {
- int len;
- /* Found the same name. */
- p += nl + 1;
- /* Check the length of the current value. */
- len = 0;
- while (p + len < pend && p[len] != '\n')
- {
- if (p[len] == '\\')
- len += 2;
- else
- len++;
- }
- if (p + len >= pend)
- /* Broken. */
- return 0;
- if (pend - space < vl - len)
- /* No space. */
- return 0;
- if (vl < len)
- {
- /* Move the following characters backward, and fill the new
- space with harmless characters. */
- grub_memmove (p + vl, p + len, pend - (p + len));
- grub_memset (space - (len - vl), '#', len - vl);
- }
- else
- /* Move the following characters forward. */
- grub_memmove (p + vl, p + len, pend - (p + vl));
- found = 1;
- break;
- }
- p = find_next_line (p, pend);
- }
- if (! found)
- {
- /* Append a new variable. */
- if (pend - space < nl + 1 + vl + 1)
- /* No space. */
- return 0;
- grub_memcpy (space, name, nl);
- p = space + nl;
- *p++ = '=';
- }
- /* Write the value. */
- for (i = 0; value[i]; i++)
- {
- if (value[i] == '\\' || value[i] == '\n')
- *p++ = '\\';
- *p++ = value[i];
- }
- *p = '\n';
- return 1;
- }
- void
- grub_envblk_delete (grub_envblk_t envblk, const char *name)
- {
- char *p, *pend;
- int nl;
- nl = grub_strlen (name);
- p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
- pend = envblk->buf + envblk->size;
- while (p + nl + 1 < pend)
- {
- if (grub_memcmp (p, name, nl) == 0 && p[nl] == '=')
- {
- /* Found. */
- int len = nl + 1;
- while (p + len < pend)
- {
- if (p[len] == '\n')
- break;
- else if (p[len] == '\\')
- len += 2;
- else
- len++;
- }
- if (p + len >= pend)
- /* Broken. */
- return;
- len++;
- grub_memmove (p, p + len, pend - (p + len));
- grub_memset (pend - len, '#', len);
- break;
- }
- p = find_next_line (p, pend);
- }
- }
- void
- grub_envblk_iterate (grub_envblk_t envblk,
- void *hook_data,
- int hook (const char *name, const char *value, void *hook_data))
- {
- char *p, *pend;
- p = envblk->buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1;
- pend = envblk->buf + envblk->size;
- while (p < pend)
- {
- if (*p != '#')
- {
- char *name;
- char *value;
- char *name_start, *name_end, *value_start;
- char *q;
- int ret;
- name_start = p;
- while (p < pend && *p != '=')
- p++;
- if (p == pend)
- /* Broken. */
- return;
- name_end = p;
- p++;
- value_start = p;
- while (p < pend)
- {
- if (*p == '\n')
- break;
- else if (*p == '\\')
- p += 2;
- else
- p++;
- }
- if (p >= pend)
- /* Broken. */
- return;
- name = grub_malloc (p - name_start + 1);
- if (! name)
- /* out of memory. */
- return;
- value = name + (value_start - name_start);
- grub_memcpy (name, name_start, name_end - name_start);
- name[name_end - name_start] = '\0';
- for (p = value_start, q = value; *p != '\n'; ++p)
- {
- if (*p == '\\')
- *q++ = *++p;
- else
- *q++ = *p;
- }
- *q = '\0';
- ret = hook (name, value, hook_data);
- grub_free (name);
- if (ret)
- return;
- }
- p = find_next_line (p, pend);
- }
- }
|