--- embedtools/src/Attic/upd.c 2009/11/13 16:25:38 1.1.2.2 +++ embedtools/src/Attic/upd.c 2011/06/08 09:15:32 1.1.2.10 @@ -1,23 +1,46 @@ +/************************************************************************* + * (C) 2010 AITNET - Sofia/Bulgaria - + * by Michael Pounov + * + * $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 Activate(const char *csImg) -{ - char szDir[MAXPATHLEN]; +int Kill; - getcwd(szDir, MAXPATHLEN); - VERB(3) printf("Activate procedure for %s\n", szDir); +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)); - return -1; + res = -1; } else { - strlcat(szDir, "/", MAXPATHLEN); - strlcat(szDir, csImg, MAXPATHLEN); + 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", @@ -30,37 +53,631 @@ int Activate(const char *csImg) return 0; } -int Install() +int Install(const char *csImg, const char *psDir) { - VERB(3) printf("Install procedure\n"); + int src, dst, len; + u_char buf[BUFSIZ]; + char szDir[MAXPATHLEN], szFile[MAXPATHLEN]; + struct stat ss, ds; - return 0; + 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() +int Rollback(const char *csImg) { - VERB(3) printf("Rollback procedure\n"); + 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() +int tFTP(const char *csImg, const char *psDir) { - VERB(3) printf("tFTP procedure\n"); + int src, dst, len; + u_char buf[BUFSIZ]; + char szDir[MAXPATHLEN], szFile[MAXPATHLEN]; + struct stat ss, ds; - return 0; + 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() +int Backup(const char *csImg) { - VERB(3) printf("Backup procedure\n"); + 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; } -int Clean() +// ---------------------------------- + +static void Signal(int sig) { - VERB(3) printf("Clean procedure\n"); + 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; }