|
version 1.1.2.4, 2009/11/14 00:37:20
|
version 1.3.2.1, 2012/07/22 22:54:53
|
|
Line 1
|
Line 1
|
| |
/************************************************************************* |
| |
* (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> |
| |
* by Michael Pounov <misho@aitbg.com> |
| |
* |
| |
* $Author$ |
| |
* $Id$ |
| |
* |
| |
************************************************************************* |
| |
The ELWIX and AITNET software is distributed under the following |
| |
terms: |
| |
|
| |
All of the documentation and software included in the ELWIX and AITNET |
| |
Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> |
| |
|
| |
Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 |
| |
by Michael Pounov <misho@elwix.org>. 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. |
| |
3. All advertising materials mentioning features or use of this software |
| |
must display the following acknowledgement: |
| |
This product includes software developed by Michael Pounov <misho@elwix.org> |
| |
ELWIX - Embedded LightWeight unIX and its contributors. |
| |
4. Neither the name of AITNET 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 AITNET 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 REGENTS 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 "global.h" |
#include "global.h" |
| #include "upd.h" |
#include "upd.h" |
| |
|
| |
|
| |
int Kill; |
| |
|
| |
|
| static inline int ChkImg(const char *csImg, char *psDir) |
static inline int ChkImg(const char *csImg, char *psDir) |
| { |
{ |
| int res = 0; |
int res = 0; |
|
Line 197 int Rollback(const char *csImg)
|
Line 245 int Rollback(const char *csImg)
|
| |
|
| int tFTP(const char *csImg, const char *psDir) |
int tFTP(const char *csImg, const char *psDir) |
| { |
{ |
| int res = 0; | int src, dst, len; |
| char szDir[MAXPATHLEN]; | u_char buf[BUFSIZ]; |
| | char szDir[MAXPATHLEN], szFile[MAXPATHLEN]; |
| | struct stat ss, ds; |
| |
|
| if (ChkImg(csImg, szDir) == -1) |
if (ChkImg(csImg, szDir) == -1) |
| return -1; |
return -1; |
| |
else { |
| |
memset(&ss, 0, sizeof ss); |
| |
if (stat(szDir, &ss) == -1) { |
| |
printf("Error:: Unable to find image %s #%d - %s\n", |
| |
szDir, errno, strerror(errno)); |
| |
return -1; |
| |
} |
| |
} |
| |
|
| VERB(3) printf("tFTP procedure for %s to %s\n", szDir, psDir); |
VERB(3) printf("tFTP procedure for %s to %s\n", szDir, psDir); |
| |
strlcpy(szFile, psDir, MAXPATHLEN); |
| |
strlcat(szFile, "/", MAXPATHLEN); |
| |
strlcat(szFile, csImg, MAXPATHLEN); |
| |
memset(&ds, 0, sizeof ds); |
| |
if (stat(szFile, &ds) == -1 && ENOENT != errno) { |
| |
printf("Error:: Unable to stat target %s #%d - %s\n", |
| |
szFile, errno, strerror(errno)); |
| |
return -1; |
| |
} |
| |
|
| res = Backup(csImg, psDir); | if (ss.st_dev == ds.st_dev && ss.st_ino == ds.st_ino) { |
| | printf("Error:: Unable to copy into self ...\n"); |
| | return -1; |
| | } |
| |
|
| if (!res) { | dst = open(szFile, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
| | if (dst == -1) { |
| | printf("Error:: in create backup %s #%d - %s\n", |
| | szFile, errno, strerror(errno)); |
| | return -1; |
| | } |
| | src = open(szDir, O_RDONLY); |
| | if (src == -1) { |
| | printf("Error:: in open image %s #%d - %s\n", |
| | szDir, errno, strerror(errno)); |
| | close(dst); |
| | unlink(szFile); |
| | return -1; |
| | } |
| | |
| | while ((len = read(src, buf, BUFSIZ)) > 0) |
| | if (write(dst, buf, len) == -1) { |
| | printf("Error:: in write backup #%d - %s\n", |
| | errno, strerror(errno)); |
| | close(src); |
| | close(dst); |
| | unlink(szFile); |
| | |
| | len = -1; |
| | break; |
| | } |
| | |
| | close(src); |
| | close(dst); |
| | |
| | if (!len) { |
| syslog(LOG_NOTICE, "Export tFTP image %s to %s", csImg, psDir); |
syslog(LOG_NOTICE, "Export tFTP image %s to %s", csImg, psDir); |
| VERB(1) printf("Export tFTP image %s to %s\n", csImg, psDir); |
VERB(1) printf("Export tFTP image %s to %s\n", csImg, psDir); |
| } |
} |
| return res; | return len; |
| } |
} |
| |
|
| int Backup(const char *csImg, const char *psDir) | int Backup(const char *csImg) |
| { |
{ |
| int src, dst, len; |
int src, dst, len; |
| u_char buf[BUFSIZ]; |
u_char buf[BUFSIZ]; |
|
Line 223 int Backup(const char *csImg, const char *psDir)
|
Line 323 int Backup(const char *csImg, const char *psDir)
|
| if (ChkImg(csImg, szDir) == -1) |
if (ChkImg(csImg, szDir) == -1) |
| return -1; |
return -1; |
| |
|
| if (!psDir) | getcwd(szFile, MAXPATHLEN); |
| getcwd(szFile, MAXPATHLEN); | |
| else | |
| strlcpy(szFile, psDir, MAXPATHLEN); | |
| strlcat(szFile, "/", MAXPATHLEN); |
strlcat(szFile, "/", MAXPATHLEN); |
| strlcat(szFile, FIRMWARE_BAK, MAXPATHLEN); |
strlcat(szFile, FIRMWARE_BAK, MAXPATHLEN); |
| |
VERB(3) printf("Backup procedure for %s\n", szDir); |
| |
|
| if (!psDir) |
|
| VERB(3) printf("Backup procedure for %s\n", szDir); |
|
| |
|
| dst = open(szFile, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
dst = open(szFile, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
| if (dst == -1) { |
if (dst == -1) { |
| printf("Error:: in create backup %s #%d - %s\n", |
printf("Error:: in create backup %s #%d - %s\n", |
|
Line 263 int Backup(const char *csImg, const char *psDir)
|
Line 358 int Backup(const char *csImg, const char *psDir)
|
| close(src); |
close(src); |
| close(dst); |
close(dst); |
| |
|
| if (!psDir && !len) { | if (!len) { |
| syslog(LOG_NOTICE, "Backup image %s", csImg); |
syslog(LOG_NOTICE, "Backup image %s", csImg); |
| VERB(1) printf("Backup image %s\n", csImg); |
VERB(1) printf("Backup image %s\n", csImg); |
| } |
} |
|
Line 290 int Clean(const char *csImg)
|
Line 385 int Clean(const char *csImg)
|
| |
|
| syslog(LOG_NOTICE, "Clean backup for image %s", csImg); |
syslog(LOG_NOTICE, "Clean backup for image %s", csImg); |
| VERB(1) printf("Clean backup for image %s\n", csImg); |
VERB(1) printf("Clean backup for image %s\n", csImg); |
| |
return 0; |
| |
} |
| |
|
| |
// ---------------------------------- |
| |
|
| |
static void Signal(int sig) |
| |
{ |
| |
int stat; |
| |
|
| |
switch (sig) { |
| |
case SIGHUP: |
| |
VERB(5) printf("Info(5):: Signal arrived #%d\n", sig); |
| |
break; |
| |
case SIGCHLD: |
| |
while (waitpid(-1, &stat, WNOHANG) > 0); |
| |
break; |
| |
case SIGTERM: |
| |
Kill = 1; |
| |
VERB(5) printf("Info(5):: Signal arrived #%d\n", sig); |
| |
break; |
| |
} |
| |
} |
| |
|
| |
int Daemonize(struct sockaddr_in sin, const char *csTFTP) |
| |
{ |
| |
int s, n = 1; |
| |
pid_t pid; |
| |
fd_set rfd; |
| |
u_short seq = 0xffff; |
| |
int clilen, len, f, retry; |
| |
struct sockaddr_in cli, rcv; |
| |
struct sigaction sa; |
| |
u_char buf[TFTP_BUF], *pos; |
| |
char szFName[STRSIZ]; |
| |
struct tftphdr *tftp = (struct tftphdr*) buf; |
| |
struct timeval tv = { TFTP_TIMEOUT, 0 }; |
| |
|
| |
VERB(3) printf("Daemonize procedure for %s:%d to %s\n", |
| |
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), csTFTP); |
| |
|
| |
memset(&sa, 0, sizeof sa); |
| |
sigemptyset(&sa.sa_mask); |
| |
sa.sa_handler = Signal; |
| |
sigaction(SIGCHLD, &sa, NULL); |
| |
sigaction(SIGTERM, &sa, NULL); |
| |
sigaction(SIGHUP, &sa, NULL); |
| |
|
| |
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| |
if (s == -1) { |
| |
printf("Error:: in create socket #%d - %s\n", errno, strerror(errno)); |
| |
return -1; |
| |
} |
| |
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n) == -1) { |
| |
printf("Error:: in socket options #%d - %s\n", errno, strerror(errno)); |
| |
close(s); |
| |
return -1; |
| |
} |
| |
if (bind(s, (struct sockaddr*) &sin, sizeof sin) == -1) { |
| |
printf("Error:: in bind #%d - %s\n", errno, strerror(errno)); |
| |
close(s); |
| |
return -1; |
| |
} |
| |
|
| |
switch ((pid = fork())) { |
| |
case -1: |
| |
printf("Error:: in socket options #%d - %s\n", errno, strerror(errno)); |
| |
close(s); |
| |
return -1; |
| |
case 0: |
| |
setsid(); |
| |
|
| |
while (!Kill) { |
| |
FD_ZERO(&rfd); |
| |
FD_SET(s, &rfd); |
| |
if (select(s + 1, &rfd, NULL, NULL, NULL) == -1) |
| |
continue; |
| |
|
| |
memset(buf, 0, TFTP_BUF); |
| |
clilen = sizeof cli; |
| |
len = recvfrom(s, buf, TFTP_BUF, 0, (struct sockaddr*) &cli, |
| |
(socklen_t*) &clilen); |
| |
if (len == -1) { |
| |
VERB(5) printf("Error:: in recvfrom #%d - %s\n", |
| |
errno, strerror(errno)); |
| |
continue; |
| |
} |
| |
|
| |
tftp = (struct tftphdr*) (pos = buf); |
| |
VERB(5) printf("Info(5):: Received packet from %s len %d with opcode=%hd\n", |
| |
inet_ntoa(cli.sin_addr), len, ntohs(tftp->th_opcode)); |
| |
switch (ntohs(tftp->th_opcode)) { |
| |
case WRQ: |
| |
len -= 2; |
| |
pos += 2; |
| |
strlcpy(szFName, (char*) pos, sizeof szFName); |
| |
VERB(5) printf("Info(5):: Get filename %s\n", szFName); |
| |
len -= strlen((char*) pos) + 1; |
| |
pos += strlen((char*) pos) + 1; |
| |
VERB(5) printf("Info(5):: Get mode %s len=%d\n", pos, len); |
| |
if (strncmp((char*) pos, "octet", len)) { |
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ERROR); |
| |
tftp->th_code = htons(EBADOP); |
| |
strncpy(tftp->th_data, "Error:: mode not supported", 27); |
| |
sendto(s, buf, 31, 0, (struct sockaddr*) &cli, sizeof cli); |
| |
continue; |
| |
} |
| |
VERB(2) printf("Info(2):: Receive file %s from %s\n", |
| |
szFName, inet_ntoa(cli.sin_addr)); |
| |
|
| |
f = open(szFName, O_WRONLY | O_CREAT | O_EXCL, 0644); |
| |
if (f == -1) { |
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ERROR); |
| |
switch (errno) { |
| |
case EACCES: |
| |
case EPERM: |
| |
tftp->th_code = htons(EACCESS); |
| |
break; |
| |
case EEXIST: |
| |
tftp->th_code = htons(EEXISTS); |
| |
break; |
| |
default: |
| |
tftp->th_code = htons(ENOSPACE); |
| |
} |
| |
snprintf(tftp->th_data, STRSIZ, "Error:: in file %s", |
| |
strerror(errno)); |
| |
sendto(s, buf, strlen(tftp->th_data) + 4, 0, |
| |
(struct sockaddr*) &cli, sizeof cli); |
| |
continue; |
| |
} |
| |
|
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ACK); |
| |
tftp->th_block = seq = 0; |
| |
sendto(s, tftp, 4, 0, (struct sockaddr*) &cli, sizeof cli); |
| |
|
| |
for (retry = TFTP_RETRY; retry;) { |
| |
FD_ZERO(&rfd); |
| |
FD_SET(s, &rfd); |
| |
if (select(s + 1, &rfd, NULL, NULL, &tv) < 1) { |
| |
retry--; |
| |
continue; |
| |
} |
| |
memset(buf, 0, TFTP_BUF); |
| |
clilen = sizeof sin; |
| |
if ((len = recvfrom(s, buf, TFTP_BUF, 0, |
| |
(struct sockaddr*) &rcv, |
| |
(socklen_t*) &clilen)) == -1) { |
| |
VERB(5) printf("Error:: in recvfrom #%d - %s\n", |
| |
errno, strerror(errno)); |
| |
retry--; |
| |
continue; |
| |
} else |
| |
if (cli.sin_addr.s_addr != rcv.sin_addr.s_addr) |
| |
continue; |
| |
|
| |
VERB(5) printf("Info(5):: received opcode=%d block=%d seq=%d\n", |
| |
ntohs(tftp->th_opcode), ntohs(tftp->th_block), seq); |
| |
if (ERROR == ntohs(tftp->th_opcode)) { |
| |
syslog(LOG_ERR, "Error:: in tftp receiving #%d - %s", |
| |
tftp->th_code, tftp->th_data); |
| |
close(f); |
| |
unlink(szFName); |
| |
break; |
| |
} |
| |
if (DATA == ntohs(tftp->th_opcode) && |
| |
++seq == ntohs(tftp->th_block)) { |
| |
if (write(f, tftp->th_data, len - 4) == -1) { |
| |
syslog(LOG_ERR, "Error:: Can`t write to file %s\n", |
| |
szFName); |
| |
close(f); |
| |
unlink(szFName); |
| |
break; |
| |
} |
| |
|
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ACK); |
| |
tftp->th_block = htons(seq); |
| |
sendto(s, tftp, 4, 0, (struct sockaddr*) &rcv, sizeof rcv); |
| |
VERB(5) printf("Info(5):: Send ACK for %s block=%d\n", |
| |
inet_ntoa(cli.sin_addr), seq); |
| |
|
| |
if (SEGSIZE > len - 4) { |
| |
close(f); |
| |
syslog(LOG_INFO, "TFTP transfer complete to %s", |
| |
szFName); |
| |
break; |
| |
} |
| |
} else { |
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ERROR); |
| |
tftp->th_code = htons(EBADID); |
| |
snprintf(tftp->th_data, STRSIZ, "Error:: in transfer #%d", |
| |
seq); |
| |
sendto(s, buf, strlen(tftp->th_data) + 4, 0, |
| |
(struct sockaddr*) &cli, sizeof cli); |
| |
retry--; |
| |
} |
| |
} |
| |
if (!retry) { |
| |
close(f); |
| |
unlink(szFName); |
| |
syslog(LOG_ERR, "Error:: transfer aborted - timeout!"); |
| |
} |
| |
|
| |
break; |
| |
case RRQ: |
| |
len -= 2; |
| |
pos += 2; |
| |
strlcpy(szFName, (char*) pos, sizeof szFName); |
| |
VERB(5) printf("Info(5):: Get filename %s\n", szFName); |
| |
len -= strlen((char*) pos) + 1; |
| |
pos += strlen((char*) pos) + 1; |
| |
VERB(5) printf("Info(5):: Get mode %s len=%d\n", pos, len); |
| |
if (strncmp((char*) pos, "octet", len)) { |
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ERROR); |
| |
tftp->th_code = htons(EBADOP); |
| |
strncpy(tftp->th_data, "Error:: mode not supported", 27); |
| |
sendto(s, buf, 31, 0, (struct sockaddr*) &cli, sizeof cli); |
| |
continue; |
| |
} |
| |
VERB(2) printf("Info(2):: Send file %s to %s\n", |
| |
szFName, inet_ntoa(cli.sin_addr)); |
| |
|
| |
f = open(szFName, O_RDONLY); |
| |
if (f == -1) { |
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ERROR); |
| |
switch (errno) { |
| |
case EACCES: |
| |
case EPERM: |
| |
tftp->th_code = htons(EACCESS); |
| |
break; |
| |
case ENOENT: |
| |
tftp->th_code = htons(ENOTFOUND); |
| |
break; |
| |
default: |
| |
tftp->th_code = htons(ENOSPACE); |
| |
} |
| |
snprintf(tftp->th_data, STRSIZ, "Error:: in file %s", |
| |
strerror(errno)); |
| |
sendto(s, buf, strlen(tftp->th_data) + 4, 0, |
| |
(struct sockaddr*) &cli, sizeof cli); |
| |
continue; |
| |
} else |
| |
seq = 1; |
| |
|
| |
for (retry = TFTP_RETRY; retry;) { |
| |
tftp->th_opcode = htons(DATA); |
| |
tftp->th_block = htons(seq); |
| |
if ((len = read(f, tftp->th_data, SEGSIZE)) == -1) { |
| |
syslog(LOG_ERR, "Error:: Can`t read from file %s\n", |
| |
szFName); |
| |
close(f); |
| |
break; |
| |
} else |
| |
sendto(s, buf, len + 4, 0, |
| |
(struct sockaddr*) &cli, sizeof cli); |
| |
|
| |
FD_ZERO(&rfd); |
| |
FD_SET(s, &rfd); |
| |
if (select(s + 1, &rfd, NULL, NULL, &tv) < 1) { |
| |
retry--; |
| |
continue; |
| |
} |
| |
memset(buf, 0, TFTP_BUF); |
| |
clilen = sizeof sin; |
| |
if (recvfrom(s, buf, TFTP_BUF, 0, (struct sockaddr*) &rcv, |
| |
(socklen_t*) &clilen) == -1) { |
| |
VERB(5) printf("Error:: in recvfrom #%d - %s\n", |
| |
errno, strerror(errno)); |
| |
retry--; |
| |
continue; |
| |
} else |
| |
if (cli.sin_addr.s_addr != rcv.sin_addr.s_addr) |
| |
continue; |
| |
|
| |
VERB(5) printf("Info(5):: received opcode=%d block=%d seq=%d\n", |
| |
ntohs(tftp->th_opcode), ntohs(tftp->th_block), seq); |
| |
if (ERROR == ntohs(tftp->th_opcode)) { |
| |
syslog(LOG_ERR, "Error:: in tftp sending #%d - %s", |
| |
tftp->th_code, tftp->th_data); |
| |
if (lseek(f, len * -1, SEEK_CUR) == -1) { |
| |
syslog(LOG_ERR, "Error:: revert sending #%d - %s", |
| |
errno, strerror(errno)); |
| |
close(f); |
| |
break; |
| |
} |
| |
retry--; |
| |
continue; |
| |
} |
| |
if (ACK == ntohs(tftp->th_opcode) && |
| |
seq == ntohs(tftp->th_block)) { |
| |
seq++; |
| |
if (SEGSIZE > len) { |
| |
close(f); |
| |
syslog(LOG_INFO, "TFTP transfer complete to %s", |
| |
szFName); |
| |
break; |
| |
} |
| |
} else { |
| |
memset(buf, 0, TFTP_BUF); |
| |
tftp->th_opcode = htons(ERROR); |
| |
tftp->th_code = htons(EBADID); |
| |
snprintf(tftp->th_data, STRSIZ, "Error:: in transfer #%d", |
| |
seq); |
| |
sendto(s, buf, strlen(tftp->th_data) + 4, 0, |
| |
(struct sockaddr*) &cli, sizeof cli); |
| |
retry--; |
| |
} |
| |
} |
| |
if (!retry) { |
| |
close(f); |
| |
syslog(LOG_ERR, "Error:: transfer aborted - timeout!"); |
| |
} |
| |
|
| |
break; |
| |
case DATA: |
| |
if (seq == 0xffff) |
| |
VERB(5) printf("Error:: not specified operation!\n"); |
| |
break; |
| |
} |
| |
} |
| |
|
| |
break; |
| |
} |
| |
|
| |
|
| |
close(s); |
| return 0; |
return 0; |
| } |
} |