File:  [ELWIX - Embedded LightWeight unIX -] / embedtools / src / Attic / upd.c
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Wed Jun 8 12:45:41 2011 UTC (13 years ago) by misho
Branches: MAIN
CVS tags: tools1_1, TOOLS1_0, HEAD
new ver

/*************************************************************************
 * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com>
 *  by Michael Pounov <misho@aitbg.com>
 *
 * $Author: misho $
 * $Id: upd.c,v 1.2 2011/06/08 12:45:41 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>