You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
12 KiB
412 lines
12 KiB
/**************************************************************************** |
|
* 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; |
|
}
|
|
|