summaryrefslogtreecommitdiffstats
path: root/package/nvram/src/shutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/nvram/src/shutils.c')
-rw-r--r--package/nvram/src/shutils.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/package/nvram/src/shutils.c b/package/nvram/src/shutils.c
new file mode 100644
index 000000000..49ad41af8
--- /dev/null
+++ b/package/nvram/src/shutils.c
@@ -0,0 +1,329 @@
+/*
+ * Shell-like utility functions
+ *
+ * Copyright 2004, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <net/ethernet.h>
+
+#include <shutils.h>
+
+/*
+ * Reads file and returns contents
+ * @param fd file descriptor
+ * @return contents of file or NULL if an error occurred
+ */
+char *
+fd2str(int fd)
+{
+ char *buf = NULL;
+ size_t count = 0, n;
+
+ do {
+ buf = realloc(buf, count + 512);
+ n = read(fd, buf + count, 512);
+ if (n < 0) {
+ free(buf);
+ buf = NULL;
+ }
+ count += n;
+ } while (n == 512);
+
+ close(fd);
+ if (buf)
+ buf[count] = '\0';
+ return buf;
+}
+
+/*
+ * Reads file and returns contents
+ * @param path path to file
+ * @return contents of file or NULL if an error occurred
+ */
+char *
+file2str(const char *path)
+{
+ int fd;
+
+ if ((fd = open(path, O_RDONLY)) == -1) {
+ perror(path);
+ return NULL;
+ }
+
+ return fd2str(fd);
+}
+
+/*
+ * Waits for a file descriptor to change status or unblocked signal
+ * @param fd file descriptor
+ * @param timeout seconds to wait before timing out or 0 for no timeout
+ * @return 1 if descriptor changed status or 0 if timed out or -1 on error
+ */
+int
+waitfor(int fd, int timeout)
+{
+ fd_set rfds;
+ struct timeval tv = { timeout, 0 };
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ return select(fd + 1, &rfds, NULL, NULL, (timeout > 0) ? &tv : NULL);
+}
+
+/*
+ * Concatenates NULL-terminated list of arguments into a single
+ * commmand and executes it
+ * @param argv argument list
+ * @param path NULL, ">output", or ">>output"
+ * @param timeout seconds to wait before timing out or 0 for no timeout
+ * @param ppid NULL to wait for child termination or pointer to pid
+ * @return return value of executed command or errno
+ */
+int
+_eval(char *const argv[], char *path, int timeout, int *ppid)
+{
+ pid_t pid;
+ int status;
+ int fd;
+ int flags;
+ int sig;
+ char buf[254]="";
+ int i;
+
+ switch (pid = fork()) {
+ case -1: /* error */
+ perror("fork");
+ return errno;
+ case 0: /* child */
+ /* Reset signal handlers set for parent process */
+ for (sig = 0; sig < (_NSIG-1); sig++)
+ signal(sig, SIG_DFL);
+
+ /* Clean up */
+ ioctl(0, TIOCNOTTY, 0);
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ setsid();
+
+ /* We want to check the board if exist UART? , add by honor 2003-12-04 */
+ if ((fd = open("/dev/console", O_RDWR)) < 0) {
+ (void) open("/dev/null", O_RDONLY);
+ (void) open("/dev/null", O_WRONLY);
+ (void) open("/dev/null", O_WRONLY);
+ }
+ else{
+ close(fd);
+ (void) open("/dev/console", O_RDONLY);
+ (void) open("/dev/console", O_WRONLY);
+ (void) open("/dev/console", O_WRONLY);
+ }
+
+ /* Redirect stdout to <path> */
+ if (path) {
+ flags = O_WRONLY | O_CREAT;
+ if (!strncmp(path, ">>", 2)) {
+ /* append to <path> */
+ flags |= O_APPEND;
+ path += 2;
+ } else if (!strncmp(path, ">", 1)) {
+ /* overwrite <path> */
+ flags |= O_TRUNC;
+ path += 1;
+ }
+ if ((fd = open(path, flags, 0644)) < 0)
+ perror(path);
+ else {
+ dup2(fd, STDOUT_FILENO);
+ close(fd);
+ }
+ }
+
+ /* execute command */
+ for(i=0 ; argv[i] ; i++)
+ snprintf(buf+strlen(buf), sizeof(buf), "%s ", argv[i]);
+ dprintf("cmd=[%s]\n", buf);
+ setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
+ alarm(timeout);
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ exit(errno);
+ default: /* parent */
+ if (ppid) {
+ *ppid = pid;
+ return 0;
+ } else {
+ waitpid(pid, &status, 0);
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else
+ return status;
+ }
+ }
+}
+
+/*
+ * Concatenates NULL-terminated list of arguments into a single
+ * commmand and executes it
+ * @param argv argument list
+ * @return stdout of executed command or NULL if an error occurred
+ */
+char *
+_backtick(char *const argv[])
+{
+ int filedes[2];
+ pid_t pid;
+ int status;
+ char *buf = NULL;
+
+ /* create pipe */
+ if (pipe(filedes) == -1) {
+ perror(argv[0]);
+ return NULL;
+ }
+
+ switch (pid = fork()) {
+ case -1: /* error */
+ return NULL;
+ case 0: /* child */
+ close(filedes[0]); /* close read end of pipe */
+ dup2(filedes[1], 1); /* redirect stdout to write end of pipe */
+ close(filedes[1]); /* close write end of pipe */
+ execvp(argv[0], argv);
+ exit(errno);
+ break;
+ default: /* parent */
+ close(filedes[1]); /* close write end of pipe */
+ buf = fd2str(filedes[0]);
+ waitpid(pid, &status, 0);
+ break;
+ }
+
+ return buf;
+}
+
+/*
+ * Kills process whose PID is stored in plaintext in pidfile
+ * @param pidfile PID file
+ * @return 0 on success and errno on failure
+ */
+int
+kill_pidfile(char *pidfile)
+{
+ FILE *fp = fopen(pidfile, "r");
+ char buf[256];
+
+ if (fp && fgets(buf, sizeof(buf), fp)) {
+ pid_t pid = strtoul(buf, NULL, 0);
+ fclose(fp);
+ return kill(pid, SIGTERM);
+ } else
+ return errno;
+}
+
+/*
+ * fread() with automatic retry on syscall interrupt
+ * @param ptr location to store to
+ * @param size size of each element of data
+ * @param nmemb number of elements
+ * @param stream file stream
+ * @return number of items successfully read
+ */
+int
+safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t ret = 0;
+
+ do {
+ clearerr(stream);
+ ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
+ } while (ret < nmemb && ferror(stream) && errno == EINTR);
+
+ return ret;
+}
+
+/*
+ * fwrite() with automatic retry on syscall interrupt
+ * @param ptr location to read from
+ * @param size size of each element of data
+ * @param nmemb number of elements
+ * @param stream file stream
+ * @return number of items successfully written
+ */
+int
+safe_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t ret = 0;
+
+ do {
+ clearerr(stream);
+ ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
+ } while (ret < nmemb && ferror(stream) && errno == EINTR);
+
+ return ret;
+}
+
+/*
+ * Convert Ethernet address string representation to binary data
+ * @param a string in xx:xx:xx:xx:xx:xx notation
+ * @param e binary data
+ * @return TRUE if conversion was successful and FALSE otherwise
+ */
+int
+ether_atoe(const char *a, unsigned char *e)
+{
+ char *c = (char *) a;
+ int i = 0;
+
+ memset(e, 0, ETHER_ADDR_LEN);
+ for (;;) {
+ e[i++] = (unsigned char) strtoul(c, &c, 16);
+ if (!*c++ || i == ETHER_ADDR_LEN)
+ break;
+ }
+ return (i == ETHER_ADDR_LEN);
+}
+
+/*
+ * Convert Ethernet address binary data to string representation
+ * @param e binary data
+ * @param a string in xx:xx:xx:xx:xx:xx notation
+ * @return a
+ */
+char *
+ether_etoa(const unsigned char *e, char *a)
+{
+ char *c = a;
+ int i;
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ if (i)
+ *c++ = ':';
+ c += sprintf(c, "%02X", e[i] & 0xff);
+ }
+ return a;
+}