start_stop_daemon: fix bug where any program name was "matching"
processes for which readlink(/proc/N/exe) fails
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index f523529..399f9f5 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -26,7 +26,7 @@
 	pid_t pid;
 };
 
-static struct pid_list *found = NULL;
+static struct pid_list *found;
 
 static inline void push(pid_t pid)
 {
@@ -42,13 +42,16 @@
 {
 	char buf[sizeof("/proc//exe") + sizeof(int)*3];
 	char *execbuf;
+	int sz;
 	int equal;
 
 	sprintf(buf, "/proc/%d/exe", pid);
-	execbuf = xstrdup(name);
-	readlink(buf, execbuf, strlen(name)+1);
+	sz = strlen(name) + 1;
+	execbuf = xzalloc(sz);
+	readlink(buf, execbuf, sz);
 
-	equal = ! strcmp(execbuf, name);
+	/* if readlink fails, execbuf still contains "" */
+	equal = !strcmp(execbuf, name);
 	if (ENABLE_FEATURE_CLEAN_UP)
 		free(execbuf);
 	return equal;
@@ -59,7 +62,7 @@
 	struct stat sb;
 	char buf[sizeof("/proc/") + sizeof(int)*3];
 
-	sprintf(buf, "/proc/%d", pid);
+	sprintf(buf, "/proc/%u", pid);
 	if (stat(buf, &sb) != 0)
 		return 0;
 	return (sb.st_uid == uid);
@@ -67,25 +70,24 @@
 
 static int pid_is_cmd(pid_t pid, const char *name)
 {
-	char buf[sizeof("/proc//stat") + sizeof(int)*3];
-	FILE *f;
-	int c;
+	char fname[sizeof("/proc//stat") + sizeof(int)*3];
+	char *buf;
+	int r = 0;
 
-	sprintf(buf, "/proc/%d/stat", pid);
-	f = fopen(buf, "r");
-	if (!f)
-		return 0;
-	while ((c = getc(f)) != EOF && c != '(')
-		;
-	if (c != '(') {
-		fclose(f);
-		return 0;
+	sprintf(fname, "/proc/%u/stat", pid);
+	buf = xmalloc_open_read_close(fname, NULL);
+	if (buf) {
+		char *p = strchr(buf, '(');
+		if (p) {
+			char *pe = strrchr(++p, ')');
+			if (pe) {
+				*pe = '\0';
+				r = !strcmp(p, name);
+			}
+		}
+		free(buf);
 	}
-	/* this hopefully handles command names containing ')' */
-	while ((c = getc(f)) != EOF && c == *name)
-		name++;
-	fclose(f);
-	return (c == ')' && *name == '\0');
+	return r;
 }
 
 
@@ -111,7 +113,7 @@
 
 	f = fopen(pidfile, "r");
 	if (f) {
-		if (fscanf(f, "%d", &pid) == 1)
+		if (fscanf(f, "%u", &pid) == 1)
 			check(pid);
 		fclose(f);
 	} else if (errno != ENOENT)
@@ -133,7 +135,8 @@
 
 	foundany = 0;
 	while ((entry = readdir(procdir)) != NULL) {
-		if (sscanf(entry->d_name, "%d", &pid) != 1)
+		pid = bb_strtou(entry->d_name, NULL, 10);
+		if (errno)
 			continue;
 		foundany++;
 		check(pid);
@@ -269,8 +272,11 @@
 	argc -= optind;
 	argv += optind;
 
-	if (userspec && sscanf(userspec, "%d", &user_id) != 1)
-		user_id = bb_xgetpwnam(userspec);
+	if (userspec) {
+		user_id = bb_strtou(userspec, NULL, 10);
+		if (errno)
+			user_id = bb_xgetpwnam(userspec);
+	}
 
 	if (opt & SSD_CTX_STOP) {
 		int i = do_stop();
@@ -301,7 +307,8 @@
 		fclose(pidf);
 	}
 	if (chuid) {
-		if (sscanf(chuid, "%d", &user_id) != 1)
+		user_id = bb_strtou(chuid, NULL, 10);
+		if (errno)
 			user_id = bb_xgetpwnam(chuid);
 		xsetuid(user_id);
 	}
diff --git a/libbb/read.c b/libbb/read.c
index b3648b4..50e0354 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -118,16 +118,19 @@
 	char *buf;
 	size_t size = sizep ? *sizep : INT_MAX;
 	int fd = xopen(filename, O_RDONLY);
-	off_t len = xlseek(fd, 0, SEEK_END);
+	/* /proc/N/stat files report len 0 here */
+	/* In order to make such files readable, we add small const */
+	off_t len = xlseek(fd, 0, SEEK_END) + 256;
 	xlseek(fd, 0, SEEK_SET);
 
 	if (len > size)
 		bb_error_msg_and_die("file '%s' is too big", filename);
 	size = len;
-	buf = xmalloc(size+1);
+	buf = xmalloc(size + 1);
 	size = read_close(fd, buf, size);
 	if ((ssize_t)size < 0)
     		bb_perror_msg_and_die("'%s'", filename);
+	xrealloc(buf, size + 1);
 	buf[size] = '\0';
 	if (sizep) *sizep = size;
 	return buf;