/* * env.c * * Copyright (C) 2005 Andreas Oberritter * * Homepage: http://www.saftware.de/ * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define list_for_each(elem, list) \ for (elem = list; elem != NULL; elem = elem->next) struct nv_var { unsigned char flags; char *name; char *value; struct nv_var *next; }; static struct nv_var *vars; static void hd(const char *text, const char *buf, size_t len) { unsigned int i; printf("%s", text); for (i = 0; i < len; i++) printf(" %02x", buf[i]); printf("\n"); } static void nv_env(void) { struct nv_var *ptr; list_for_each(ptr, vars) printf("%s=\"%s\"\n", ptr->name, ptr->value); } static bool nv_printenv(const char *name) { struct nv_var *ptr; list_for_each(ptr, vars) if (!strcmp(ptr->name, name)) { printf("%s\n", ptr->value); return true; } return false; } static bool _nv_setenv(unsigned char flags, const char *name, size_t nlen, const char *value, size_t vlen) { struct nv_var *ptr; list_for_each(ptr, vars) if (!strcmp(ptr->name, name)) { free(ptr->value); ptr->flags = flags; ptr->value = strndup(value, vlen); return true; } ptr = malloc(sizeof(struct nv_var)); if (!ptr) { perror("malloc"); return false; } /* insert at end to keep the order */ if (!vars) { vars = ptr; } else { struct nv_var *tmp; for (tmp = vars; tmp->next != NULL; tmp = tmp->next); tmp->next = ptr; } ptr->flags = flags; ptr->name = strndup(name, nlen); ptr->value = strndup(value, vlen); ptr->next = NULL; return true; } static bool nv_setenv(const char *name, const char *value) { return _nv_setenv(0x00, name, strlen(name), value, strlen(value)); } static bool nv_readenv(const char *cfgarea, unsigned int len) { const char *ptr = cfgarea; const char *delim; unsigned int dtag; unsigned int dlen; for (ptr = cfgarea; ; ptr += dlen + 2) { dtag = ptr[0] & 0xff; if (dtag == 0x00) break; dlen = ptr[1] & 0xff; if (dtag == 0x01) { delim = strchr(&ptr[3], '='); if (delim) { if (_nv_setenv(ptr[2], &ptr[3], delim - &ptr[3], &ptr[3 + (delim - &ptr[3]) + 1], dlen - 2 - (delim - &ptr[3])) == false) { fprintf(stderr, "could not set variable\n"); return false; } } else { fprintf(stderr, "not a variable\n"); return false; } } else { hd("tag:", cfgarea, len); hd("err:", ptr, dlen + 2); fprintf(stderr, "unhandled tag %02x\n", dtag); return false; } } return true; } static void nv_erase(unsigned char *cfgarea, unsigned int len) { memset(cfgarea, 0xff, len); } static void nv_writeenv(unsigned char *cfgarea, unsigned int len) { struct nv_var *ptr; unsigned int nlen, vlen; list_for_each(ptr, vars) { nlen = strlen(ptr->name); vlen = strlen(ptr->value); *cfgarea++ = 0x01; *cfgarea++ = nlen + vlen + 2; *cfgarea++ = ptr->flags; memcpy(cfgarea, ptr->name, nlen); cfgarea += nlen; *cfgarea++ = '='; memcpy(cfgarea, ptr->value, vlen); cfgarea += vlen; } *cfgarea++ = 0x00; } static void help(FILE *f) { fprintf(f, "Usage: env [OPTION]...\n\n"); fprintf(f, "printenv\n"); fprintf(f, "\tenv [-f ]\n\n"); fprintf(f, "getenv\n"); fprintf(f, "\tenv [-f ] -n \n\n"); fprintf(f, "setenv\n"); fprintf(f, "\tenv [-f ] -n -v \n\n"); } int main(int argc, char *argv[]) { const char *filename = "mtd4"; unsigned int cfglen = 0x1000; int fd, ret = EXIT_FAILURE; void *cfgarea; extern char *optarg; int flags; int c; char *name = NULL; char *value = NULL; while ((c = getopt(argc, argv, "f:hn:v:")) != -1) { switch (c) { case 'f': filename = strdup(optarg); break; case 'h': help(stdout); return EXIT_SUCCESS; case 'n': name = strdup(optarg); break; case 'v': value = strdup(optarg); break; default: help(stderr); return EXIT_FAILURE; } } if (((name == NULL) && (value != NULL)) || (optind < argc)) { help(stderr); return EXIT_FAILURE; } flags = value ? O_RDWR : O_RDONLY; fd = open(filename, flags); if (fd == -1) { perror(filename); return EXIT_FAILURE; } flags = value ? PROT_READ | PROT_WRITE : PROT_READ; cfgarea = mmap(NULL, cfglen, flags, MAP_SHARED, fd, 0x1e000); if (cfgarea == MAP_FAILED) { perror("mmap"); goto out_close; } if (nv_readenv(cfgarea, cfglen) == false) { fprintf(stderr, "readenv failed\n"); goto out_munmap; } if (name && value) { if (nv_setenv(name, value) == false) { fprintf(stderr, "setenv failed\n"); goto out_munmap; } nv_erase(cfgarea, cfglen); nv_writeenv(cfgarea, cfglen); } else if (name) { if (nv_printenv(name) == false) fprintf(stderr, "printenv failed\n"); } else { nv_env(); } out_munmap: munmap(cfgarea, cfglen); out_close: close(fd); return ret; }