Made new xreadlink function for libbb and changed applets to use it instead of
readlink(2).
diff --git a/Makefile b/Makefile
index 5713cdc..91ed745 100644
--- a/Makefile
+++ b/Makefile
@@ -247,8 +247,8 @@
 process_escape_sequence.c read_package_field.c read_text_file_to_buffer.c \
 recursive_action.c safe_read.c safe_strncpy.c seek_ared_file.c syscalls.c \
 syslog_msg_with_name.c time_string.c trim.c untar.c unzip.c vdprintf.c \
-verror_msg.c vperror_msg.c wfopen.c xfuncs.c xgetcwd.c xregcomp.c interface.c \
-remove_file.c last_char_is.c
+verror_msg.c vperror_msg.c wfopen.c xfuncs.c xgetcwd.c xreadlink.c\
+xregcomp.c interface.c remove_file.c last_char_is.c
 LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC))
 LIBBB_CFLAGS = -I$(LIBBB)
 ifneq ($(strip $(BB_SRC_DIR)),)
diff --git a/applets/busybox.c b/applets/busybox.c
index b4939e1..badd53d 100644
--- a/applets/busybox.c
+++ b/applets/busybox.c
@@ -37,21 +37,10 @@
  */
 static char *busybox_fullpath()
 {
-	pid_t pid;
-	char path[256];
 	char proc[256];
-	int len;
 
-	pid = getpid();
-	sprintf(proc, "/proc/%d/exe", pid);
-	len = readlink(proc, path, 256);
-	if (len != -1) {
-		path[len] = 0;
-	} else {
-		perror_msg("%s", proc);
-		return NULL;
-	}
-	return strdup(path);
+	sprintf(proc, "/proc/%d/exe", getpid());
+	return xreadlink(proc);
 }
 
 /* create (sym)links for each applet */
diff --git a/archival/tar.c b/archival/tar.c
index c168564..4bf8004 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -921,16 +921,10 @@
 		header.typeflag = LNKTYPE;
 		strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
 	} else if (S_ISLNK(statbuf->st_mode)) {
-		int link_size=0;
-		char buffer[BUFSIZ];
+		char *lpath = xreadlink(real_name);
 		header.typeflag  = SYMTYPE;
-		link_size = readlink(real_name, buffer, sizeof(buffer) - 1);
-		if ( link_size < 0) {
-			perror_msg("Error reading symlink '%s'", header.name);
-			return ( FALSE);
-		}
-		buffer[link_size] = '\0';
-		strncpy(header.linkname, buffer, sizeof(header.linkname)); 
+		strncpy(header.linkname, lpath, sizeof(header.linkname)); 
+		free(lpath);
 	} else if (S_ISDIR(statbuf->st_mode)) {
 		header.typeflag  = DIRTYPE;
 		strncat(header.name, "/", sizeof(header.name)); 
diff --git a/busybox.c b/busybox.c
index b4939e1..badd53d 100644
--- a/busybox.c
+++ b/busybox.c
@@ -37,21 +37,10 @@
  */
 static char *busybox_fullpath()
 {
-	pid_t pid;
-	char path[256];
 	char proc[256];
-	int len;
 
-	pid = getpid();
-	sprintf(proc, "/proc/%d/exe", pid);
-	len = readlink(proc, path, 256);
-	if (len != -1) {
-		path[len] = 0;
-	} else {
-		perror_msg("%s", proc);
-		return NULL;
-	}
-	return strdup(path);
+	sprintf(proc, "/proc/%d/exe", getpid());
+	return xreadlink(proc);
 }
 
 /* create (sym)links for each applet */
diff --git a/coreutils/ls.c b/coreutils/ls.c
index d24ba98..c13b225 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -577,7 +577,7 @@
 /*----------------------------------------------------------------------*/
 static int list_single(struct dnode *dn)
 {
-	int i, len;
+	int i;
 	char scratch[BUFSIZ + 1];
 #ifdef BB_FEATURE_LS_TIMESTAMPS
 	char *filetime;
@@ -688,16 +688,16 @@
 				break;
 			case LIST_SYMLINK:
 				if (S_ISLNK(dn->dstat.st_mode)) {
-					len= readlink(dn->fullname, scratch, (sizeof scratch)-1);
-					if (len > 0) {
-						scratch[len]= '\0';
-						printf(" -> %s", scratch);
+					char *lpath = xreadlink(dn->fullname);
+					if (lpath) {
+						printf(" -> %s", lpath);
 #ifdef BB_FEATURE_LS_FILETYPES
 						if (!stat(dn->fullname, &info)) {
 							append = append_char(info.st_mode);
 						}
 #endif
-						column += len+4;
+						column += strlen(lpath) + 4;
+						free(lpath);
 					}
 				}
 				break;
diff --git a/include/libbb.h b/include/libbb.h
index a53e647..d2f9a95 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -217,6 +217,7 @@
 int klogctl(int type, char * b, int len);
 
 char *xgetcwd(char *cwd);
+char *xreadlink(const char *path);
 char *concat_path_file(const char *path, const char *filename);
 int last_char_is(const char *s, const int c);
 
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 2d18b60..22684be 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -196,19 +196,12 @@
 			return -1;
 		}
 	} else if (S_ISLNK(source_stat.st_mode)) {
-		int size;
-		char buf[BUFSIZ + 1];
-
-		if ((size = readlink(source, buf, BUFSIZ)) < 0) {
-			perror_msg("cannot read `%s'", source);
-			return -1;
-		}
-		buf[size] = '\0';
-
-		if (symlink(buf, dest) < 0) {
+		char *lpath = xreadlink(source);
+		if (symlink(lpath, dest) < 0) {
 			perror_msg("cannot create symlink `%s'", dest);
 			return -1;
 		}
+		free(lpath);
 
 #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
 		if (flags & FILEUTILS_PRESERVE_STATUS)
diff --git a/libbb/libbb.h b/libbb/libbb.h
index a53e647..d2f9a95 100644
--- a/libbb/libbb.h
+++ b/libbb/libbb.h
@@ -217,6 +217,7 @@
 int klogctl(int type, char * b, int len);
 
 char *xgetcwd(char *cwd);
+char *xreadlink(const char *path);
 char *concat_path_file(const char *path, const char *filename);
 int last_char_is(const char *s, const int c);
 
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
new file mode 100644
index 0000000..66f63b8
--- /dev/null
+++ b/libbb/xreadlink.c
@@ -0,0 +1,34 @@
+/*
+ *  xreadlink.c - safe implementation of readlink
+ */
+
+#include <stdio.h>
+
+/*
+ * NOTE: This function returns a malloced char* that you will have to free
+ * yourself. You have been warned.
+ */
+
+#include <unistd.h>
+#include "libbb.h"
+
+extern char *xreadlink(const char *path)
+{                       
+	static const int GROWBY = 80; /* how large we will grow strings by */
+
+	char *buf = NULL;   
+	int bufsize = 0, readsize = 0;
+
+	do {
+		buf = xrealloc(buf, bufsize += GROWBY);
+		readsize = readlink(path, buf, bufsize); /* 1st try */
+		if (readsize == -1)
+			perror_msg("%s:%s", applet_name, path);
+	}           
+	while (bufsize < readsize + 1);
+
+	buf[readsize] = '\0';
+
+	return buf;
+}       
+
diff --git a/ls.c b/ls.c
index d24ba98..c13b225 100644
--- a/ls.c
+++ b/ls.c
@@ -577,7 +577,7 @@
 /*----------------------------------------------------------------------*/
 static int list_single(struct dnode *dn)
 {
-	int i, len;
+	int i;
 	char scratch[BUFSIZ + 1];
 #ifdef BB_FEATURE_LS_TIMESTAMPS
 	char *filetime;
@@ -688,16 +688,16 @@
 				break;
 			case LIST_SYMLINK:
 				if (S_ISLNK(dn->dstat.st_mode)) {
-					len= readlink(dn->fullname, scratch, (sizeof scratch)-1);
-					if (len > 0) {
-						scratch[len]= '\0';
-						printf(" -> %s", scratch);
+					char *lpath = xreadlink(dn->fullname);
+					if (lpath) {
+						printf(" -> %s", lpath);
 #ifdef BB_FEATURE_LS_FILETYPES
 						if (!stat(dn->fullname, &info)) {
 							append = append_char(info.st_mode);
 						}
 #endif
-						column += len+4;
+						column += strlen(lpath) + 4;
+						free(lpath);
 					}
 				}
 				break;
diff --git a/miscutils/readlink.c b/miscutils/readlink.c
index 74196e1..2266495 100644
--- a/miscutils/readlink.c
+++ b/miscutils/readlink.c
@@ -30,21 +30,17 @@
 int readlink_main(int argc, char **argv)
 {
 	char *buf = NULL;
-	int bufsize = 128, size = 128;
+
+	/* no options, no getopt */
 
 	if (argc != 2)
 		show_usage();
 
-	while (bufsize < size + 1) {
-		bufsize *= 2;
-		buf = xrealloc(buf, bufsize);
-		size = readlink(argv[1], buf, bufsize);
-		if (size == -1)
-			perror_msg_and_die("%s", argv[1]);
-	}
-
-	buf[size] = '\0';
+	buf = xreadlink(argv[1]);
 	puts(buf);
+#ifdef BB_FEATURE_CLEAN_UP
+	free(buf);
+#endif
 
 	return EXIT_SUCCESS;
 }
diff --git a/readlink.c b/readlink.c
index 74196e1..2266495 100644
--- a/readlink.c
+++ b/readlink.c
@@ -30,21 +30,17 @@
 int readlink_main(int argc, char **argv)
 {
 	char *buf = NULL;
-	int bufsize = 128, size = 128;
+
+	/* no options, no getopt */
 
 	if (argc != 2)
 		show_usage();
 
-	while (bufsize < size + 1) {
-		bufsize *= 2;
-		buf = xrealloc(buf, bufsize);
-		size = readlink(argv[1], buf, bufsize);
-		if (size == -1)
-			perror_msg_and_die("%s", argv[1]);
-	}
-
-	buf[size] = '\0';
+	buf = xreadlink(argv[1]);
 	puts(buf);
+#ifdef BB_FEATURE_CLEAN_UP
+	free(buf);
+#endif
 
 	return EXIT_SUCCESS;
 }
diff --git a/tar.c b/tar.c
index c168564..4bf8004 100644
--- a/tar.c
+++ b/tar.c
@@ -921,16 +921,10 @@
 		header.typeflag = LNKTYPE;
 		strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname));
 	} else if (S_ISLNK(statbuf->st_mode)) {
-		int link_size=0;
-		char buffer[BUFSIZ];
+		char *lpath = xreadlink(real_name);
 		header.typeflag  = SYMTYPE;
-		link_size = readlink(real_name, buffer, sizeof(buffer) - 1);
-		if ( link_size < 0) {
-			perror_msg("Error reading symlink '%s'", header.name);
-			return ( FALSE);
-		}
-		buffer[link_size] = '\0';
-		strncpy(header.linkname, buffer, sizeof(header.linkname)); 
+		strncpy(header.linkname, lpath, sizeof(header.linkname)); 
+		free(lpath);
 	} else if (S_ISDIR(statbuf->st_mode)) {
 		header.typeflag  = DIRTYPE;
 		strncat(header.name, "/", sizeof(header.name));