finally move buildroot-ng to trunk
[openwrt/openwrt.git] / package / nvram / src / shutils.c
diff --git a/package/nvram/src/shutils.c b/package/nvram/src/shutils.c
new file mode 100644 (file)
index 0000000..49ad41a
--- /dev/null
@@ -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;
+}