summaryrefslogtreecommitdiffstats
path: root/apps/system/install/install.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/system/install/install.c')
-rwxr-xr-xapps/system/install/install.c411
1 files changed, 411 insertions, 0 deletions
diff --git a/apps/system/install/install.c b/apps/system/install/install.c
new file mode 100755
index 0000000000..f1fe7207ee
--- /dev/null
+++ b/apps/system/install/install.c
@@ -0,0 +1,411 @@
+/****************************************************************************
+ * 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 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 %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 = 0, 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 && up_progmem_isuniform()) {
+
+ 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[2*CONFIG_NAME_MAX];
+
+ /* 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;
+}