1/* 2 * Shell-like utility functions 3 * 4 * Copyright 2004, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: shutils.c,v 1.1.1.1 2008/10/15 03:31:22 james26_jang Exp $ 13 */ 14 15#include <stdio.h> 16#include <stdlib.h> 17#include <stdarg.h> 18#include <errno.h> 19#include <error.h> 20#include <fcntl.h> 21#include <limits.h> 22#include <unistd.h> 23#include <signal.h> 24#include <string.h> 25#include <sys/types.h> 26#include <sys/stat.h> 27#include <sys/wait.h> 28#include <termios.h> 29#include <sys/ioctl.h> 30#include <sys/time.h> 31#include <net/ethernet.h> 32 33#include <shutils.h> 34 35/* 36 * Reads file and returns contents 37 * @param fd file descriptor 38 * @return contents of file or NULL if an error occurred 39 */ 40char * 41fd2str(int fd) 42{ 43 char *buf = NULL; 44 size_t count = 0, n; 45 46 do { 47 buf = realloc(buf, count + 512); 48 n = read(fd, buf + count, 512); 49 if (n < 0) { 50 free(buf); 51 buf = NULL; 52 } 53 count += n; 54 } while (n == 512); 55 56 close(fd); 57 if (buf) 58 buf[count] = '\0'; 59 return buf; 60} 61 62/* 63 * Reads file and returns contents 64 * @param path path to file 65 * @return contents of file or NULL if an error occurred 66 */ 67char * 68file2str(const char *path) 69{ 70 int fd; 71 72 if ((fd = open(path, O_RDONLY)) == -1) { 73 perror(path); 74 return NULL; 75 } 76 77 return fd2str(fd); 78} 79 80/* 81 * Waits for a file descriptor to change status or unblocked signal 82 * @param fd file descriptor 83 * @param timeout seconds to wait before timing out or 0 for no timeout 84 * @return 1 if descriptor changed status or 0 if timed out or -1 on error 85 */ 86int 87waitfor(int fd, int timeout) 88{ 89 fd_set rfds; 90 struct timeval tv = { timeout, 0 }; 91 92 FD_ZERO(&rfds); 93 FD_SET(fd, &rfds); 94 return select(fd + 1, &rfds, NULL, NULL, (timeout > 0) ? &tv : NULL); 95} 96 97/* 98 * Concatenates NULL-terminated list of arguments into a single 99 * commmand and executes it 100 * @param argv argument list 101 * @param path NULL, ">output", or ">>output" 102 * @param timeout seconds to wait before timing out or 0 for no timeout 103 * @param ppid NULL to wait for child termination or pointer to pid 104 * @return return value of executed command or errno 105 */ 106int 107_eval(char *const argv[], char *path, int timeout, int *ppid) 108{ 109 pid_t pid; 110 int status; 111 int fd; 112 int flags; 113 int sig; 114 115 switch (pid = fork()) { 116 case -1: /* error */ 117 perror("fork"); 118 return errno; 119 case 0: /* child */ 120 /* Reset signal handlers set for parent process */ 121 for (sig = 0; sig < (_NSIG-1); sig++) 122 signal(sig, SIG_DFL); 123 124 /* Clean up */ 125 ioctl(0, TIOCNOTTY, 0); 126 close(STDIN_FILENO); 127 setsid(); 128 129 /* Redirect stdout to <path> */ 130 if (path) { 131 flags = O_WRONLY | O_CREAT; 132 if (!strncmp(path, ">>", 2)) { 133 /* append to <path> */ 134 flags |= O_APPEND; 135 path += 2; 136 } else if (!strncmp(path, ">", 1)) { 137 /* overwrite <path> */ 138 flags |= O_TRUNC; 139 path += 1; 140 } 141 if ((fd = open(path, flags, 0644)) < 0) 142 perror(path); 143 else { 144 dup2(fd, STDOUT_FILENO); 145 dup2(fd, STDERR_FILENO); 146 close(fd); 147 } 148 } 149 150 /* execute command */ 151 dprintf("%s\n", argv[0]); 152 setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1); 153 alarm(timeout); 154 execvp(argv[0], argv); 155 perror(argv[0]); 156 exit(errno); 157 default: /* parent */ 158 if (ppid) { 159 *ppid = pid; 160 return 0; 161 } else { 162 waitpid(pid, &status, 0); 163 if (WIFEXITED(status)) 164 return WEXITSTATUS(status); 165 else 166 return status; 167 } 168 } 169} 170 171/* 172 * Concatenates NULL-terminated list of arguments into a single 173 * commmand and executes it 174 * @param argv argument list 175 * @return stdout of executed command or NULL if an error occurred 176 */ 177char * 178_backtick(char *const argv[]) 179{ 180 int filedes[2]; 181 pid_t pid; 182 int status; 183 char *buf = NULL; 184 185 /* create pipe */ 186 if (pipe(filedes) == -1) { 187 perror(argv[0]); 188 return NULL; 189 } 190 191 switch (pid = fork()) { 192 case -1: /* error */ 193 return NULL; 194 case 0: /* child */ 195 close(filedes[0]); /* close read end of pipe */ 196 dup2(filedes[1], 1); /* redirect stdout to write end of pipe */ 197 close(filedes[1]); /* close write end of pipe */ 198 execvp(argv[0], argv); 199 exit(errno); 200 break; 201 default: /* parent */ 202 close(filedes[1]); /* close write end of pipe */ 203 buf = fd2str(filedes[0]); 204 waitpid(pid, &status, 0); 205 break; 206 } 207 208 return buf; 209} 210 211/* 212 * Kills process whose PID is stored in plaintext in pidfile 213 * @param pidfile PID file 214 * @return 0 on success and errno on failure 215 */ 216int 217kill_pidfile(char *pidfile) 218{ 219 FILE *fp = fopen(pidfile, "r"); 220 char buf[256]; 221 222 if (fp && fgets(buf, sizeof(buf), fp)) { 223 pid_t pid = strtoul(buf, NULL, 0); 224 fclose(fp); 225 return kill(pid, SIGTERM); 226 } else 227 return errno; 228} 229 230/* 231 * fread() with automatic retry on syscall interrupt 232 * @param ptr location to store to 233 * @param size size of each element of data 234 * @param nmemb number of elements 235 * @param stream file stream 236 * @return number of items successfully read 237 */ 238int 239safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 240{ 241 size_t ret = 0; 242 243 do { 244 clearerr(stream); 245 ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream); 246 } while (ret < nmemb && ferror(stream) && errno == EINTR); 247 248 return ret; 249} 250 251/* 252 * fwrite() with automatic retry on syscall interrupt 253 * @param ptr location to read from 254 * @param size size of each element of data 255 * @param nmemb number of elements 256 * @param stream file stream 257 * @return number of items successfully written 258 */ 259int 260safe_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 261{ 262 size_t ret = 0; 263 264 do { 265 clearerr(stream); 266 ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream); 267 } while (ret < nmemb && ferror(stream) && errno == EINTR); 268 269 return ret; 270} 271 272/* 273 * Convert Ethernet address string representation to binary data 274 * @param a string in xx:xx:xx:xx:xx:xx notation 275 * @param e binary data 276 * @return TRUE if conversion was successful and FALSE otherwise 277 */ 278int 279ether_atoe(const char *a, unsigned char *e) 280{ 281 char *c = (char *) a; 282 int i = 0; 283 284 memset(e, 0, ETHER_ADDR_LEN); 285 for (;;) { 286 e[i++] = (unsigned char) strtoul(c, &c, 16); 287 if (!*c++ || i == ETHER_ADDR_LEN) 288 break; 289 } 290 return (i == ETHER_ADDR_LEN); 291} 292 293/* 294 * Convert Ethernet address binary data to string representation 295 * @param e binary data 296 * @param a string in xx:xx:xx:xx:xx:xx notation 297 * @return a 298 */ 299char * 300ether_etoa(const unsigned char *e, char *a) 301{ 302 char *c = a; 303 int i; 304 305 for (i = 0; i < ETHER_ADDR_LEN; i++) { 306 if (i) 307 *c++ = ':'; 308 c += sprintf(c, "%02X", e[i] & 0xff); 309 } 310 return a; 311} 312