add libshared/libnvram and required includes under version control
[openwrt/svn-archive/archive.git] / openwrt / package / openwrt / libshared / shutils.c
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$
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 */
40 char *
41 fd2str(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 */
67 char *
68 file2str(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 */
86 int
87 waitfor(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 */
106 int
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 char buf[254]="";
115 int i;
116
117 switch (pid = fork()) {
118 case -1: /* error */
119 perror("fork");
120 return errno;
121 case 0: /* child */
122 /* Reset signal handlers set for parent process */
123 for (sig = 0; sig < (_NSIG-1); sig++)
124 signal(sig, SIG_DFL);
125
126 /* Clean up */
127 ioctl(0, TIOCNOTTY, 0);
128 close(STDIN_FILENO);
129 close(STDOUT_FILENO);
130 close(STDERR_FILENO);
131 setsid();
132
133 /* We want to check the board if exist UART? , add by honor 2003-12-04 */
134 if ((fd = open("/dev/console", O_RDWR)) < 0) {
135 (void) open("/dev/null", O_RDONLY);
136 (void) open("/dev/null", O_WRONLY);
137 (void) open("/dev/null", O_WRONLY);
138 }
139 else{
140 close(fd);
141 (void) open("/dev/console", O_RDONLY);
142 (void) open("/dev/console", O_WRONLY);
143 (void) open("/dev/console", O_WRONLY);
144 }
145
146 /* Redirect stdout to <path> */
147 if (path) {
148 flags = O_WRONLY | O_CREAT;
149 if (!strncmp(path, ">>", 2)) {
150 /* append to <path> */
151 flags |= O_APPEND;
152 path += 2;
153 } else if (!strncmp(path, ">", 1)) {
154 /* overwrite <path> */
155 flags |= O_TRUNC;
156 path += 1;
157 }
158 if ((fd = open(path, flags, 0644)) < 0)
159 perror(path);
160 else {
161 dup2(fd, STDOUT_FILENO);
162 close(fd);
163 }
164 }
165
166 /* execute command */
167 for(i=0 ; argv[i] ; i++)
168 snprintf(buf+strlen(buf), sizeof(buf), "%s ", argv[i]);
169 dprintf("cmd=[%s]\n", buf);
170 setenv("PATH", "/sbin:/bin:/usr/sbin:/usr/bin", 1);
171 alarm(timeout);
172 execvp(argv[0], argv);
173 perror(argv[0]);
174 exit(errno);
175 default: /* parent */
176 if (ppid) {
177 *ppid = pid;
178 return 0;
179 } else {
180 waitpid(pid, &status, 0);
181 if (WIFEXITED(status))
182 return WEXITSTATUS(status);
183 else
184 return status;
185 }
186 }
187 }
188
189 /*
190 * Concatenates NULL-terminated list of arguments into a single
191 * commmand and executes it
192 * @param argv argument list
193 * @return stdout of executed command or NULL if an error occurred
194 */
195 char *
196 _backtick(char *const argv[])
197 {
198 int filedes[2];
199 pid_t pid;
200 int status;
201 char *buf = NULL;
202
203 /* create pipe */
204 if (pipe(filedes) == -1) {
205 perror(argv[0]);
206 return NULL;
207 }
208
209 switch (pid = fork()) {
210 case -1: /* error */
211 return NULL;
212 case 0: /* child */
213 close(filedes[0]); /* close read end of pipe */
214 dup2(filedes[1], 1); /* redirect stdout to write end of pipe */
215 close(filedes[1]); /* close write end of pipe */
216 execvp(argv[0], argv);
217 exit(errno);
218 break;
219 default: /* parent */
220 close(filedes[1]); /* close write end of pipe */
221 buf = fd2str(filedes[0]);
222 waitpid(pid, &status, 0);
223 break;
224 }
225
226 return buf;
227 }
228
229 /*
230 * Kills process whose PID is stored in plaintext in pidfile
231 * @param pidfile PID file
232 * @return 0 on success and errno on failure
233 */
234 int
235 kill_pidfile(char *pidfile)
236 {
237 FILE *fp = fopen(pidfile, "r");
238 char buf[256];
239
240 if (fp && fgets(buf, sizeof(buf), fp)) {
241 pid_t pid = strtoul(buf, NULL, 0);
242 fclose(fp);
243 return kill(pid, SIGTERM);
244 } else
245 return errno;
246 }
247
248 /*
249 * fread() with automatic retry on syscall interrupt
250 * @param ptr location to store to
251 * @param size size of each element of data
252 * @param nmemb number of elements
253 * @param stream file stream
254 * @return number of items successfully read
255 */
256 int
257 safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
258 {
259 size_t ret = 0;
260
261 do {
262 clearerr(stream);
263 ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream);
264 } while (ret < nmemb && ferror(stream) && errno == EINTR);
265
266 return ret;
267 }
268
269 /*
270 * fwrite() with automatic retry on syscall interrupt
271 * @param ptr location to read from
272 * @param size size of each element of data
273 * @param nmemb number of elements
274 * @param stream file stream
275 * @return number of items successfully written
276 */
277 int
278 safe_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
279 {
280 size_t ret = 0;
281
282 do {
283 clearerr(stream);
284 ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream);
285 } while (ret < nmemb && ferror(stream) && errno == EINTR);
286
287 return ret;
288 }
289
290 /*
291 * Convert Ethernet address string representation to binary data
292 * @param a string in xx:xx:xx:xx:xx:xx notation
293 * @param e binary data
294 * @return TRUE if conversion was successful and FALSE otherwise
295 */
296 int
297 ether_atoe(const char *a, unsigned char *e)
298 {
299 char *c = (char *) a;
300 int i = 0;
301
302 memset(e, 0, ETHER_ADDR_LEN);
303 for (;;) {
304 e[i++] = (unsigned char) strtoul(c, &c, 16);
305 if (!*c++ || i == ETHER_ADDR_LEN)
306 break;
307 }
308 return (i == ETHER_ADDR_LEN);
309 }
310
311 /*
312 * Convert Ethernet address binary data to string representation
313 * @param e binary data
314 * @param a string in xx:xx:xx:xx:xx:xx notation
315 * @return a
316 */
317 char *
318 ether_etoa(const unsigned char *e, char *a)
319 {
320 char *c = a;
321 int i;
322
323 for (i = 0; i < ETHER_ADDR_LEN; i++) {
324 if (i)
325 *c++ = ':';
326 c += sprintf(c, "%02X", e[i] & 0xff);
327 }
328 return a;
329 }