330 lines
7.1 KiB
C
330 lines
7.1 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|