/*************************************************************************
* (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
* by Michael Pounov <misho@aitbg.com>
*
* $Author: misho $
* $Id: upd.c,v 1.1.2.10 2011/06/08 09:15:32 misho Exp $
*
*************************************************************************/
#include "global.h"
#include "upd.h"
int Kill;
static inline int ChkImg(const char *csImg, char *psDir)
{
int res = 0;
getcwd(psDir, MAXPATHLEN);
if (access(csImg, R_OK) == -1) {
printf("Error:: Unable to find new image %s #%d - %s\n",
csImg, errno, strerror(errno));
res = -1;
} else {
strlcat(psDir, "/", MAXPATHLEN);
strlcat(psDir, csImg, MAXPATHLEN);
}
return res;
}
// -------------------------------
int Activate(const char *csImg)
{
char szDir[MAXPATHLEN];
if (ChkImg(csImg, szDir) == -1)
return -1;
VERB(3) printf("Activate procedure for %s\n", szDir);
unlink(FIRMWARE_IMG);
if (symlink(szDir, FIRMWARE_IMG) == -1) {
printf("Error:: Unable to activate new image %s #%d - %s\n",
csImg, errno, strerror(errno));
return -2;
}
syslog(LOG_NOTICE, "Activate new image %s", csImg);
VERB(1) printf("Activate new image %s\n", csImg);
return 0;
}
int Install(const char *csImg, const char *psDir)
{
int src, dst, len;
u_char buf[BUFSIZ];
char szDir[MAXPATHLEN], szFile[MAXPATHLEN];
struct stat ss, ds;
strlcpy(szFile, psDir, MAXPATHLEN);
strlcat(szFile, "/", MAXPATHLEN);
strlcat(szFile, csImg, MAXPATHLEN);
if (access(szFile, R_OK) == -1) {
printf("Error:: Unable to find new image %s #%d - %s\n",
csImg, errno, strerror(errno));
return -1;
} else {
memset(&ss, 0, sizeof ss);
if (stat(szFile, &ss) == -1) {
printf("Error:: Unable to find new image %s #%d - %s\n",
csImg, errno, strerror(errno));
return -1;
}
}
getcwd(szDir, MAXPATHLEN);
VERB(3) printf("Install procedure from %s to %s\n", szFile, szDir);
strlcat(szDir, "/", MAXPATHLEN);
strlcat(szDir, csImg, MAXPATHLEN);
memset(&ds, 0, sizeof ds);
if (stat(szDir, &ds) == -1 && ENOENT != errno) {
printf("Error:: Unable to stat target #%d - %s\n",
errno, strerror(errno));
return -1;
}
if (ss.st_dev == ds.st_dev && ss.st_ino == ds.st_ino) {
printf("Error:: Unable to install into self ...\n");
return -1;
}
dst = open(szDir, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dst == -1) {
printf("Error:: in create image %s #%d - %s\n",
szDir, errno, strerror(errno));
return -1;
}
src = open(szFile, O_RDONLY);
if (src == -1) {
printf("Error:: in open image %s #%d - %s\n",
szFile, errno, strerror(errno));
close(dst);
unlink(szDir);
return -1;
}
while ((len = read(src, buf, BUFSIZ)) > 0)
if (write(dst, buf, len) == -1) {
printf("Error:: in write image #%d - %s\n",
errno, strerror(errno));
close(src);
close(dst);
unlink(szDir);
len = -1;
break;
}
close(src);
close(dst);
if (!len) {
syslog(LOG_NOTICE, "Install image %s to %s", csImg, szDir);
VERB(1) printf("Install image %s to %s\n", csImg, szDir);
}
return len;
}
int Rollback(const char *csImg)
{
int src, dst, len;
u_char buf[BUFSIZ];
char szDir[MAXPATHLEN], szFile[MAXPATHLEN];
struct stat ss, ds;
getcwd(szFile, MAXPATHLEN);
strlcat(szFile, "/", MAXPATHLEN);
strlcat(szFile, FIRMWARE_BAK, MAXPATHLEN);
if (access(szFile, R_OK) == -1) {
printf("Error:: Unable to find backup image #%d - %s\n",
errno, strerror(errno));
return -1;
} else {
memset(&ss, 0, sizeof ss);
if (stat(szFile, &ss) == -1) {
printf("Error:: Unable to find backup image #%d - %s\n",
errno, strerror(errno));
return -1;
}
}
getcwd(szDir, MAXPATHLEN);
strlcat(szDir, "/", MAXPATHLEN);
strlcat(szDir, csImg, MAXPATHLEN);
VERB(3) printf("Rollback procedure for image %s from backup!\n", csImg);
memset(&ds, 0, sizeof ds);
if (stat(szDir, &ds) == -1 && ENOENT != errno) {
printf("Error:: Unable to stat target #%d - %s\n",
errno, strerror(errno));
return -1;
}
if (ss.st_dev == ds.st_dev && ss.st_ino == ds.st_ino) {
printf("Error:: Unable to rollback into self ...\n");
return -1;
}
src = open(szFile, O_RDONLY);
if (src == -1) {
printf("Error:: in open backup %s #%d - %s\n",
szFile, errno, strerror(errno));
return -1;
}
dst = open(szDir, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dst == -1) {
printf("Error:: in create image %s #%d - %s\n",
szDir, errno, strerror(errno));
close(src);
return -1;
}
while ((len = read(src, buf, BUFSIZ)) > 0)
if (write(dst, buf, len) == -1) {
printf("Error:: in write image #%d - %s\n",
errno, strerror(errno));
close(dst);
close(src);
unlink(szDir);
len = -1;
break;
}
close(dst);
close(src);
if (!len) {
syslog(LOG_NOTICE, "Rollback image %s to %s", csImg, szDir);
VERB(1) printf("Rollback image %s to %s\n", csImg, szDir);
}
return len;
return 0;
}
int tFTP(const char *csImg, const char *psDir)
{
int src, dst, len;
u_char buf[BUFSIZ];
char szDir[MAXPATHLEN], szFile[MAXPATHLEN];
struct stat ss, ds;
if (ChkImg(csImg, szDir) == -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);
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;
}
if (ss.st_dev == ds.st_dev && ss.st_ino == ds.st_ino) {
printf("Error:: Unable to copy into self ...\n");
return -1;
}
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);
VERB(1) printf("Export tFTP image %s to %s\n", csImg, psDir);
}
return len;
}
int Backup(const char *csImg)
{
int src, dst, len;
u_char buf[BUFSIZ];
char szDir[MAXPATHLEN], szFile[MAXPATHLEN];
if (ChkImg(csImg, szDir) == -1)
return -1;
getcwd(szFile, MAXPATHLEN);
strlcat(szFile, "/", MAXPATHLEN);
strlcat(szFile, FIRMWARE_BAK, MAXPATHLEN);
VERB(3) printf("Backup procedure for %s\n", szDir);
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, "Backup image %s", csImg);
VERB(1) printf("Backup image %s\n", csImg);
}
return len;
}
int Clean(const char *csImg)
{
char szDir[MAXPATHLEN], szFile[MAXPATHLEN];
if (ChkImg(csImg, szDir) == -1)
return -1;
getcwd(szFile, MAXPATHLEN);
strlcat(szFile, "/", MAXPATHLEN);
strlcat(szFile, FIRMWARE_BAK, MAXPATHLEN);
VERB(3) printf("Clean procedure for %s\n", szDir);
if (unlink(szFile) == -1) {
printf("Error:: in clean backup #%d - %s\n", errno, strerror(errno));
return -1;
}
syslog(LOG_NOTICE, "Clean backup for image %s", 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[MAX_STR];
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, MAX_STR);
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, MAX_STR);
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;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>