/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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 */ if (path) { flags = O_WRONLY | O_CREAT; if (!strncmp(path, ">>", 2)) { /* append to */ flags |= O_APPEND; path += 2; } else if (!strncmp(path, ">", 1)) { /* overwrite */ 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; }