if (s == NULL)
return NULL;
- t = strdup (s);
+ t = strdup(s);
if (t == NULL)
bb_error_msg_and_die(bb_msg_memory_exhausted);
// the (possibly truncated to length n) string into it.
char * xstrndup(const char *s, int n)
{
+ int m;
char *t;
if (ENABLE_DEBUG && s == NULL)
bb_error_msg_and_die("xstrndup bug");
- t = xmalloc(++n);
+ /* We can just xmalloc(n+1) and strncpy into it, */
+ /* but think about xstrndup("abc", 10000) wastage! */
+ m = n;
+ t = (char*) s;
+ while (m) {
+ if (!*t) break;
+ m--; t++;
+ }
+ n = n - m;
+ t = xmalloc(n + 1);
+ t[n] = '\0';
- return safe_strncpy(t,s,n);
+ return memcpy(t,s,n);
}
// Die if we can't open a file and return a FILE * to it.
// Notice we haven't got xfread(), This is for use with fscanf() and friends.
FILE *xfopen(const char *path, const char *mode)
{
- FILE *fp;
- if ((fp = fopen(path, mode)) == NULL)
+ FILE *fp = fopen(path, mode);
+ if (fp == NULL)
bb_perror_msg_and_die("%s", path);
return fp;
}
// Die if we can't open an existing file and return an fd.
int xopen(const char *pathname, int flags)
{
- if (ENABLE_DEBUG && (flags & O_CREAT))
- bb_error_msg_and_die("xopen() with O_CREAT");
+ //if (ENABLE_DEBUG && (flags & O_CREAT))
+ // bb_error_msg_and_die("xopen() with O_CREAT");
return xopen3(pathname, flags, 0666);
}
return ret;
}
+// Turn on nonblocking I/O on a fd
+int ndelay_on(int fd)
+{
+ return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
+}
+
+int ndelay_off(int fd)
+{
+ return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
+}
+
// Die with an error message if we can't write the entire buffer.
-void xwrite(int fd, void *buf, size_t count)
+void xwrite(int fd, const void *buf, size_t count)
{
if (count) {
ssize_t size = full_write(fd, buf, count);
off_t xlseek(int fd, off_t offset, int whence)
{
off_t off = lseek(fd, offset, whence);
- if (off == (off_t)-1)
+ if (off == (off_t)-1) {
+ if (whence == SEEK_SET)
+ bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
bb_perror_msg_and_die("lseek");
+ }
return off;
}
-// Die with supplied error message if this FILE * has ferror set.
+// Die with supplied filename if this FILE * has ferror set.
void die_if_ferror(FILE *fp, const char *fn)
{
if (ferror(fp)) {
- bb_error_msg_and_die("%s", fn);
+ bb_error_msg_and_die("%s: I/O error", fn);
}
}
// -1 for failure. Runs argv[0], searching path if that has no / in it.
pid_t spawn(char **argv)
{
+ /* Why static? */
static int failed;
pid_t pid;
- void *app = ENABLE_FEATURE_SH_STANDALONE_SHELL ? find_applet_by_name(argv[0]) : 0;
+ char *prog;
// Be nice to nommu machines.
failed = 0;
pid = vfork();
if (pid < 0) return pid;
if (!pid) {
- execvp(app ? CONFIG_BUSYBOX_EXEC_PATH : *argv, argv);
+ prog = argv[0];
+ if (ENABLE_FEATURE_EXEC_PREFER_APPLETS && find_applet_by_name(prog))
+ prog = CONFIG_BUSYBOX_EXEC_PATH;
+ execvp(prog, argv);
// We're sharing a stack with blocked parent, let parent know we failed
// and then exit to unblock parent (but don't run atexit() stuff, which
// would screw up parent.)
- failed = -1;
+ failed = errno;
_exit(0);
}
- return failed ? failed : pid;
+ if (failed) {
+ errno = failed;
+ return -1;
+ }
+ return pid;
}
// Die with an error message if we can't spawn a child process.
bb_error_msg_and_die(bb_msg_memory_exhausted);
}
-
// Converts unsigned long long value into compact 4-char
// representation. Examples: "1234", "1.2k", " 27M", "123T"
// Fifth char is always '\0'
buf[4] = '\0';
}
-
// Convert unsigned integer to ascii, writing into supplied buffer. A
// truncated result is always null terminated (unless buflen is 0), and
// contains the first few digits of the result ala strncpy.
return local_buf;
}
+// Emit a string of hex representation of bytes
+char *bin2hex(char *p, const char *cp, int count)
+{
+ while (count) {
+ unsigned char c = *cp++;
+ /* put lowercase hex digits */
+ *p++ = 0x10 | bb_hexdigits_upcase[c >> 4];
+ *p++ = 0x10 | bb_hexdigits_upcase[c & 0xf];
+ count--;
+ }
+ return p;
+}
+
// Die with an error message if we can't set gid. (Because resource limits may
// limit this user to a given number of processes, and if that fills up the
// setgid() will fail and we'll _still_be_root_, which is bad.)
return string_ptr;
}
+#if 0 /* If we will ever meet a libc which hasn't [f]dprintf... */
+int fdprintf(int fd, const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+#if 1
+ // GNU extension
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+#else
+ // Bloat for systems that haven't got the GNU extension.
+ va_start(p, format);
+ r = vsnprintf(NULL, 0, format, p);
+ va_end(p);
+ string_ptr = xmalloc(r+1);
+ va_start(p, format);
+ r = vsnprintf(string_ptr, r+1, format, p);
+ va_end(p);
+#endif
+
+ if (r >= 0) {
+ full_write(fd, string_ptr, r);
+ free(string_ptr);
+ }
+ return r;
+}
+#endif
+
// Die with an error message if we can't copy an entire FILE * to stdout, then
// close that file.
void xprint_and_close_file(FILE *file)
DIR *dp;
if ((dp = opendir(path)) == NULL) {
- bb_perror_msg("unable to open `%s'", path);
+ bb_perror_msg("cannot open '%s'", path);
return NULL;
}
return dp;
DIR *dp;
if ((dp = opendir(path)) == NULL)
- bb_perror_msg_and_die("unable to open `%s'", path);
+ bb_perror_msg_and_die("cannot open '%s'", path);
return dp;
}
}
#endif
+void bb_sanitize_stdio_maybe_daemonize(int daemonize)
+{
+ int fd;
+ /* Mega-paranoid */
+ fd = xopen(bb_dev_null, O_RDWR);
+ while (fd < 2)
+ fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
+ if (daemonize) {
+ pid_t pid = fork();
+ if (pid < 0) /* wtf? */
+ bb_perror_msg_and_die("fork");
+ if (pid) /* parent */
+ exit(0);
+ /* child */
+ /* if daemonizing, make sure we detach from stdio */
+ setsid();
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+ while (fd > 2)
+ close(fd--); /* close everything after fd#2 */
+}
+void bb_sanitize_stdio(void)
+{
+ bb_sanitize_stdio_maybe_daemonize(0);
+}
+void bb_daemonize(void)
+{
+ bb_sanitize_stdio_maybe_daemonize(1);
+}
+
// Die with an error message if we can't open a new socket.
int xsocket(int domain, int type, int protocol)
{
/* It is perfectly ok to pass in a NULL for either width or for
* height, in which case that value will not be set. */
-int get_terminal_width_height(int fd, int *width, int *height)
+int get_terminal_width_height(const int fd, int *width, int *height)
{
struct winsize win = { 0, 0, 0, 0 };
int ret = ioctl(fd, TIOCGWINSZ, &win);