/* $NetBSD$ */ /*- * Copyright (c) 2015 Jared D. McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * cc -Wall -Werror -O2 uenv.c -o uenv -lutil -lz */ #include #include #include #include #include #include #include #include #include #include #include // ODROID-C1 #define CONFIG_ENV_SIZE (32 * 1024) // unit: bytes #define CONFIG_ENV_OFFSET (512 * 1024) // unit: bytes struct environment { uint32_t crc; u_char data[CONFIG_ENV_SIZE - 4]; }; static void usage(const char *pn) { fprintf(stderr, "usage: %s [key] [value]\n", pn); exit(EXIT_FAILURE); } static struct environment * open_uenv(int fd, int flags) { struct environment *env; int prot = PROT_READ; if (flags == O_RDWR) prot |= PROT_WRITE; env = mmap(NULL, CONFIG_ENV_SIZE, prot, MAP_FILE|MAP_SHARED, fd, CONFIG_ENV_OFFSET); if (env == MAP_FAILED) err(EXIT_FAILURE, "couldn't mmap device"); return env; } static void close_uenv(struct environment *env) { munmap(env, CONFIG_ENV_SIZE); } static void print_uenv(struct environment *env, const char *key) { const char *p = (const char *)env->data; uint32_t crc; crc = crc32(0, env->data, sizeof(env->data)); if (env->crc != crc) { errx(EXIT_FAILURE, "bad uenv crc (expected %#x got %#x)", crc, env->crc); } while (*p) { if (key == NULL || (strstr(p, key) == p && p[strlen(key)] == '=')) { printf("%s\n", p); } p += strlen(p) + 1; } } static void update_uenv(struct environment *env, const char *key, const char *val) { const char *p = (const char *)env->data; struct environment new_env; char *new_p; bool existing; uint32_t crc; memset(&new_env, 0, sizeof(new_env)); new_p = (char *)new_env.data; existing = false; crc = crc32(0, env->data, sizeof(env->data)); if (env->crc == crc) { while (*p) { if (strstr(p, key) == p && p[strlen(key)] == '=') { strcpy(new_p, key); strcat(new_p, "="); strcat(new_p, val); existing = true; } else { strcat(new_p, p); } new_p += strlen(new_p) + 1; p += strlen(p) + 1; } } if (!existing) { strcpy(new_p, key); strcat(new_p, "="); strcat(new_p, val); new_p += strlen(new_p) + 1; } new_env.crc = crc32(0, new_env.data, sizeof(new_env.data)); *env = new_env; } int main(int argc, char *argv[]) { struct environment *env; const char *key = NULL, *val = NULL; char path[MAXPATHLEN]; int fd, flags; if (argc < 2 || argc > 4) { usage(argv[0]); /* NOTREACHED */ } if (argc > 2) { key = argv[2]; } if (argc > 3) { val = argv[3]; } flags = val ? O_RDWR : O_RDONLY; fd = opendisk(argv[1], flags, path, sizeof(path), 1); if (fd == -1) err(EXIT_FAILURE, "couldn't open %s", argv[1]); env = open_uenv(fd, flags); if (val) { update_uenv(env, key, val); } else { print_uenv(env, key); } close_uenv(env); close(fd); return EXIT_SUCCESS; }