diff options
Diffstat (limited to 'apps/system/install/install.c')
-rwxr-xr-x | apps/system/install/install.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/apps/system/install/install.c b/apps/system/install/install.c new file mode 100755 index 000000000..2f11c6434 --- /dev/null +++ b/apps/system/install/install.c @@ -0,0 +1,412 @@ +/**************************************************************************** + * apps/system/install/install.c + * + * Copyright (C) 2011 Uros Platise. All rights reserved. + * Author: Uros Platise <uros.platise@isotel.eu> + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + * + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/progmem.h> +#include <sys/stat.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define ACTION_INSTALL 0x01 +#define ACTION_REMOVE 0x00 +#define ACTION_REINSTALL 0x03 +#define ACTION_INSUFPARAM 0x80 + +#define INSTALL_PROGRAMBLOCKSIZE 1024 + + +/**************************************************************************** + * Private data + ****************************************************************************/ + +const char *install_help = + "Installs XIP program into flash and creates a start-up script in the\n" + "destination directory.\n\n" + "Usage:\t%s [options] source-file.xip destination-directory\n\n" + "Example:\n\t%s --stack 1024 /sdcard/demo.xip /usr/bin\n\n" + "Options:\n" + "\t--stack <required_stack_space>\n" + "\t--priority <priority>\n" + "\t--remove <dest-file>\tRemoves installed application\n" + "\t--force\t\t\tReplaces existing installation\n" + "\t--start <page>\t\tInstalls application at or after <page>\n" + "\t--margin <pages>\tLeave some free space after the kernel (default 16)\n"; + +const char *install_script_text = + "# XIP stacksize=%x priority=%x size=%x\n"; + +const char *install_script_exec = + "exec 0x%x\n"; + + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +int install_getstartpage(int startpage, int pagemargin, int desiredsize) +{ + uint16_t page = 0, stpage = 0xFFFF; + uint16_t pagesize = 0; + int maxlen = -1; + int maxlen_start = 0xFFFF; + int status; + + for (status=0, page=0; status >= 0; page++) { + + status = up_progmem_ispageerased(page); + pagesize = up_progmem_pagesize(page); + + /* Is this beginning of new free space section */ + if (status == 0) { + if (stpage == 0xFFFF) stpage = page; + } + else if (status != 0) { + + if (stpage != 0xFFFF) { + + if ( (page - stpage) > maxlen) { + + if (maxlen==-1) { /* First time found sth? */ + stpage += pagemargin; + maxlen = 0; + } + + if(stpage < startpage) + stpage = startpage; + + if (page > stpage) { + maxlen = page - stpage; + maxlen_start = stpage; + } + + if (maxlen*pagesize >= desiredsize) { + /* printf("Found page at %d ... %d\n", stpage, page); */ + return maxlen_start*pagesize; + } + } + + stpage = 0xFFFF; + } + } + } + + /* Requested space is not available */ + + return -1; +} + + +int install_programflash(int startaddr, const char *source) +{ + int status; + int count; + int totalsize = 0; + char *buf; + FILE *fp; + + if ( (buf = malloc(INSTALL_PROGRAMBLOCKSIZE)) == NULL ) + return -errno; + + if ( (fp=fopen(source, "r")) ) { + do { + count = fread(buf, 1, INSTALL_PROGRAMBLOCKSIZE, fp); + + if ( (status = up_progmem_write(startaddr, buf, count)) < 0) { + totalsize = status; + break; + } + + startaddr += count; + totalsize += count; + } + while(count); + } + else totalsize = -errno; + + fclose(fp); + free(buf); + + return totalsize; +} + + +void install_getscriptname(char *scriptname, const char *progname, const char *destdir) +{ + const char * progonly; + + /* I.e. as /usr/bin */ + strcpy(scriptname, destdir); + + /* extract from i.e. /sdcard/demo -> /demo, together with / */ + progonly = strrchr(progname, '/'); + strcat(scriptname, progonly); +} + + +int install_getprogsize(const char *progname) +{ + struct stat fileinfo; + + if ( stat(progname, &fileinfo) < 0 ) + return -1; + + return fileinfo.st_size; +} + + +int install_alreadyexists(const char *scriptname) +{ + FILE *fp; + + if ( (fp=fopen(scriptname, "r"))==NULL ) + return 0; + + fclose(fp); + return 1; +} + + +int install_createscript(int addr, int stacksize, int progsize, + int priority, const char *scriptname) +{ + FILE *fp; + + if ( (fp=fopen(scriptname, "w+"))==NULL ) + return -errno; + + fprintf(fp, install_script_text, stacksize, priority, progsize); + fprintf(fp, install_script_exec, addr); + + fflush(fp); + fclose(fp); + + return 0; +} + + +int install_getlasthexvalue(FILE *fp, char delimiter) +{ + char buf[128]; + char *p; + + if (fgets(buf, 127, fp)) { + if ( (p = strrchr(buf, delimiter)) ) { + return strtol(p+1, NULL, 16); + } + } + return -1; +} + + +int install_remove(const char *scriptname) +{ + FILE *fp; + int progsize, addr, freedsize; + uint16_t page; + int status = 0; + + /* Parse script */ + + if ( (fp=fopen(scriptname, "r")) ) { + progsize = install_getlasthexvalue(fp,'='); + addr = install_getlasthexvalue(fp,' '); + freedsize = progsize; + } + else return -errno; + + fclose(fp); + + /* Remove pages */ + + if (progsize <= 0 || addr <= 0) + return -EIO; + + do { + if ((page = up_progmem_getpage(addr)) < 0) { + status = -page; + break; + } + + if ( up_progmem_erasepage(page) < 0) { + status = -page; + break; + } + + addr += up_progmem_pagesize(page); + progsize -= up_progmem_pagesize(page); + + } while(progsize > 0); + + if (status < 0) return status; + + /* Remove script file */ + + if (unlink(scriptname) < 0) return -errno; + + return freedsize; +} + + +/**************************************************************************** + * Start + ****************************************************************************/ + +int install_main(int argc, char *argv[]) +{ + int i; + int progsize; + int scrsta; + int stacksize = 4096; + int priority = SCHED_PRIORITY_DEFAULT; + int pagemargin = 16; + int startpage = 0; + int startaddr = 0; + int action = ACTION_INSTALL; + char scriptname[128]; + + /* Supported? */ + + if ( !up_progmem_isuniform() ) { + fprintf(stderr, "Error: install supports uniform organization only.\n"); + return -1; + } + + /* Parse arguments */ + + for (i=1; i<argc; i++) { + if (argv[i][0]=='-' && argv[i][1]=='-' && i<=argc) { + + if (strcmp(argv[i]+2, "stack")==0) { + stacksize = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "priority")==0) { + priority = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "start")==0) { + startpage = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "margin")==0) { + pagemargin = atoi(argv[++i]); + } + else if (strcmp(argv[i]+2, "remove")==0) { + action = ACTION_REMOVE; + } + else if (strcmp(argv[i]+2, "force")==0) { + action = ACTION_REINSTALL; + } + else fprintf(stderr, "Unknown option: %s\n", argv[i]); + } + else break; + } + + /* Do the job */ + + switch(action & 1) { + + case ACTION_REMOVE: + if (i > argc-1) { + action = ACTION_INSUFPARAM; + break; /* are there sufficient parameters */ + } + if ( (scrsta=install_remove(argv[i])) < 0) { + fprintf(stderr, "Could not remove program: %s\n", strerror(-scrsta) ); + return -1; + } + printf("Removed %s and freed %d bytes\n", argv[i], scrsta); + return 0; + + + case ACTION_INSTALL: + if (i > argc-2) { + action = ACTION_INSUFPARAM; + break; /* are there sufficient parameters */ + } + + install_getscriptname(scriptname, argv[i], argv[i+1]); + + // script-exists? + if (install_alreadyexists(scriptname)==1) { + + if (action != ACTION_REINSTALL) { + fprintf(stderr, "Program with that name already exists.\n"); + return -EEXIST; + } + + if ( (scrsta=install_remove(scriptname)) < 0) { + fprintf(stderr, "Could not remove program: %s\n", strerror(-scrsta) ); + return -1; + } + + printf("Replacing %s\n", scriptname); + } + + startaddr = install_getstartpage(startpage, pagemargin, install_getprogsize(argv[i]) ); + if (startpage < 0) { + fprintf(stderr, "Not enough memory\n"); + return -ENOMEM; + } + + if ( (progsize = install_programflash(startaddr, argv[i])) <= 0) { + fprintf(stderr, "Error writing program memory: %s\n" + "Note: Flash pages are not released, so you may try again and program will be\n" + " written in other pages.\n", strerror(-progsize) ); + + return -EIO; + } + if ( (scrsta = install_createscript(startaddr, stacksize, progsize, + priority, scriptname)) < 0) { + fprintf(stderr, "Error writing program script at %s: %s\n", + argv[i+1], strerror(-scrsta) ); + return -EIO; + } + + printf("Installed application of size %d bytes to program memory [%xh - %xh].\n", + progsize, startaddr, startaddr + progsize); + + return 0; + } + + fprintf(stderr, install_help, argv[0], argv[0]); + return -1; +} |