let ipkg fail when a package file to be installed is not found
[openwrt.git] / openwrt / package / nvram / src / 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 }