Cleaup read() and write() variants, plus a couple of new functions like
[oweals/busybox.git] / libbb / xfuncs.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Utility routines.
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  */
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include "busybox.h"
19
20 #ifndef DMALLOC
21 #ifdef L_xmalloc
22 void *xmalloc(size_t size)
23 {
24         void *ptr = malloc(size);
25         if (ptr == NULL && size != 0)
26                 bb_error_msg_and_die(bb_msg_memory_exhausted);
27         return ptr;
28 }
29 #endif
30
31 #ifdef L_xrealloc
32 void *xrealloc(void *ptr, size_t size)
33 {
34         ptr = realloc(ptr, size);
35         if (ptr == NULL && size != 0)
36                 bb_error_msg_and_die(bb_msg_memory_exhausted);
37         return ptr;
38 }
39 #endif
40
41 #ifdef L_xzalloc
42 void *xzalloc(size_t size)
43 {
44         void *ptr = xmalloc(size);
45         memset(ptr, 0, size);
46         return ptr;
47 }
48 #endif
49
50 #ifdef L_xcalloc
51 void *xcalloc(size_t nmemb, size_t size)
52 {
53         void *ptr = calloc(nmemb, size);
54         if (ptr == NULL && nmemb != 0 && size != 0)
55                 bb_error_msg_and_die(bb_msg_memory_exhausted);
56         return ptr;
57 }
58 #endif
59 #endif /* DMALLOC */
60
61 #ifdef L_xstrdup
62 char * bb_xstrdup (const char *s)
63 {
64         char *t;
65
66         if (s == NULL)
67                 return NULL;
68
69         t = strdup (s);
70
71         if (t == NULL)
72                 bb_error_msg_and_die(bb_msg_memory_exhausted);
73
74         return t;
75 }
76 #endif
77
78 #ifdef L_xstrndup
79 char * bb_xstrndup (const char *s, int n)
80 {
81         char *t;
82
83         if (ENABLE_DEBUG && s == NULL)
84                 bb_error_msg_and_die("bb_xstrndup bug");
85
86         t = xmalloc(++n);
87
88         return safe_strncpy(t,s,n);
89 }
90 #endif
91
92 #ifdef L_xfopen
93 FILE *bb_xfopen(const char *path, const char *mode)
94 {
95         FILE *fp;
96         if ((fp = fopen(path, mode)) == NULL)
97                 bb_perror_msg_and_die("%s", path);
98         return fp;
99 }
100 #endif
101
102 #ifdef L_xopen
103 int bb_xopen(const char *pathname, int flags)
104 {
105         return bb_xopen3(pathname, flags, 0777);
106 }
107 #endif
108
109 #ifdef L_xopen3
110 int bb_xopen3(const char *pathname, int flags, int mode)
111 {
112         int ret;
113
114         ret = open(pathname, flags, mode);
115         if (ret < 0) {
116                 bb_perror_msg_and_die("%s", pathname);
117         }
118         return ret;
119 }
120 #endif
121
122 #ifdef L_xread
123
124 // Die with an error message if we can't read the entire buffer.
125
126 void xread(int fd, void *buf, size_t count)
127 {
128         while (count) {
129                 ssize_t size;
130
131                 if ((size = safe_read(fd, buf, count)) < 1)
132                         bb_error_msg_and_die("Short read");
133                 count -= size;
134                 buf = ((char *) buf) + size;
135         }
136 }
137 #endif
138
139 #ifdef L_xwrite
140
141 // Die with an error message if we can't write the entire buffer.
142
143 void xwrite(int fd, void *buf, size_t count)
144 {
145         while (count) {
146                 ssize_t size;
147
148                 if ((size = safe_write(fd, buf, count)) < 1)
149                         bb_error_msg_and_die("Short write");
150                 count -= size;
151                 buf = ((char *) buf) + size;
152         }
153 }
154 #endif
155
156 #ifdef L_xlseek
157
158 // Die if we can't lseek to the right spot.
159
160 void xlseek(int fd, off_t offset, int whence)
161 {
162         if (whence != lseek(fd, offset, whence)) bb_error_msg_and_die("lseek");
163 }
164 #endif
165
166 #ifdef L_xread_char
167 unsigned char xread_char(int fd)
168 {
169         char tmp;
170
171         xread(fd, &tmp, 1);
172
173         return(tmp);
174 }
175 #endif
176
177 #ifdef L_xferror
178 void bb_xferror(FILE *fp, const char *fn)
179 {
180         if (ferror(fp)) {
181                 bb_error_msg_and_die("%s", fn);
182         }
183 }
184 #endif
185
186 #ifdef L_xferror_stdout
187 void bb_xferror_stdout(void)
188 {
189         bb_xferror(stdout, bb_msg_standard_output);
190 }
191 #endif
192
193 #ifdef L_xfflush_stdout
194 void bb_xfflush_stdout(void)
195 {
196         if (fflush(stdout)) {
197                 bb_perror_msg_and_die(bb_msg_standard_output);
198         }
199 }
200 #endif
201
202 #ifdef L_spawn
203 // This does a fork/exec in one call, using vfork().
204 pid_t bb_spawn(char **argv)
205 {
206         static int failed;
207         pid_t pid;
208         void *app = find_applet_by_name(argv[0]);
209
210         // Be nice to nommu machines.
211         failed = 0;
212         pid = vfork();
213         if (pid < 0) return pid;
214         if (!pid) {
215                 execvp(app ? CONFIG_BUSYBOX_EXEC_PATH : *argv, argv);
216
217                 // We're sharing a stack with blocked parent, let parent know we failed
218                 // and then exit to unblock parent (but don't run atexit() stuff, which
219                 // would screw up parent.)
220
221                 failed = -1;
222                 _exit(0);
223         }
224         return failed ? failed : pid;
225 }
226 #endif
227
228 #ifdef L_xspawn
229 pid_t bb_xspawn(char **argv)
230 {
231         pid_t pid = bb_spawn(argv);
232         if (pid < 0) bb_perror_msg_and_die("%s", *argv);
233         return pid;
234 }
235 #endif
236
237 #ifdef L_wait4
238 int wait4pid(int pid)
239 {
240         int status;
241
242         if (pid == -1 || waitpid(pid, &status, 0) == -1) return -1;
243         if (WIFEXITED(status)) return WEXITSTATUS(status);
244         if (WIFSIGNALED(status)) return WTERMSIG(status);
245         return 0;
246 }
247 #endif
248
249 #ifdef L_itoa
250 // Largest 32 bit integer is -2 billion plus null terminator.
251 // Int should always be 32 bits on a Unix-oid system, see
252 // http://www.unix.org/whitepapers/64bit.html
253 static char local_buf[12];
254
255 void utoa_to_buf(unsigned n, char *buf, unsigned buflen)
256 {
257         int i, out = 0;
258         if (buflen) {
259                 for (i=1000000000; i; i/=10) {
260                         int res = n/i;
261
262                         if ((res || out || i == 1) && --buflen>0) {
263                                 out++;
264                                 n -= res*i;
265                                 *buf++ = '0' + res;
266                         }
267                 }
268                 *buf = 0;
269         }
270 }
271
272 // Note: uses static buffer, calling it twice in a row will overwrite.
273
274 char *utoa(unsigned n)
275 {
276         utoa_to_buf(n, local_buf, sizeof(local_buf));
277
278         return local_buf;
279 }
280
281 void itoa_to_buf(int n, char *buf, unsigned buflen)
282 {
283         if (buflen && n<0) {
284                 n = -n;
285                 *buf++ = '-';
286                 buflen--;
287         }
288         utoa_to_buf((unsigned)n, buf, buflen);
289 }
290
291 // Note: uses static buffer, calling it twice in a row will overwrite.
292
293 char *itoa(int n)
294 {
295         itoa_to_buf(n, local_buf, sizeof(local_buf));
296
297         return local_buf;
298 }
299 #endif
300
301 #ifdef L_setuid
302 void xsetgid(gid_t gid)
303 {
304         if (setgid(gid)) bb_error_msg_and_die("setgid");
305 }
306
307 void xsetuid(uid_t uid)
308 {
309         if (setuid(uid)) bb_error_msg_and_die("setuid");
310 }
311 #endif
312
313 #ifdef L_fdlength
314 off_t fdlength(int fd)
315 {
316         off_t bottom = 0, top = 0, pos;
317         long size;
318
319         // If the ioctl works for this, return it.
320
321         if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512;
322
323         // If not, do a binary search for the last location we can read.
324
325         do {
326                 char temp;
327
328                 pos = bottom + (top - bottom) / 2;;
329
330                 // If we can read from the current location, it's bigger.
331
332                 if (lseek(fd, pos, 0)>=0 && safe_read(fd, &temp, 1)==1) {
333                         if (bottom == top) bottom = top = (top+1) * 2;
334                         else bottom = pos;
335
336                 // If we can't, it's smaller.
337
338                 } else {
339                         if (bottom == top) {
340                                 if (!top) return 0;
341                                 bottom = top/2;
342                         }
343                         else top = pos;
344                 }
345         } while (bottom + 1 != top);
346
347         return pos + 1;
348 }
349 #endif