376 lines
8.5 KiB
Plaintext
376 lines
8.5 KiB
Plaintext
--- libinit.c
|
|
+++ libinit.c 2011-01-27 12:58:48.944425833 +0000
|
|
@@ -218,6 +218,26 @@ static struct _sys_signals {
|
|
{ 0, "EXIT" }
|
|
};
|
|
|
|
+/*
|
|
+ * Calculate the depth of a directory, root has zero depth.
|
|
+ */
|
|
+static size_t dirdepth(const char *const path)
|
|
+{
|
|
+ const char *ptr = path;
|
|
+ size_t cnt = 0;
|
|
+
|
|
+ do {
|
|
+ const size_t off = strcspn(ptr, "/");
|
|
+ ptr += off;
|
|
+ if (*ptr++ != '/')
|
|
+ break;
|
|
+ if (*ptr)
|
|
+ cnt++;
|
|
+ } while (*ptr);
|
|
+
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
typedef struct _mntinfo_
|
|
{
|
|
struct _mntinfo_ *next;
|
|
@@ -226,6 +246,7 @@ typedef struct _mntinfo_
|
|
int id, parid;
|
|
dev_t dev;
|
|
size_t nlen;
|
|
+ size_t deep;
|
|
char * point;
|
|
} MNTINFO;
|
|
|
|
@@ -253,6 +274,7 @@ static void init_mounts(void)
|
|
p->point = ((char*)p)+alignof(MNTINFO);
|
|
strcpy(p->point, point);
|
|
p->nlen = nlen;
|
|
+ p->deep = dirdepth(point);
|
|
p->parid = parid;
|
|
p->dev = makedev(maj, min);
|
|
p->id = mid;
|
|
@@ -262,20 +284,20 @@ static void init_mounts(void)
|
|
p->prev = (MNTINFO*)0;
|
|
p->parent = p;
|
|
mounts = p;
|
|
- if (mid > max)
|
|
- max = mid;
|
|
+ if (p->id > max)
|
|
+ max = p->id;
|
|
}
|
|
fclose(mnt);
|
|
|
|
- /* Sort mount points accordingly to the reverse mount order */
|
|
+ /* Sort mount points accordingly to their reverse directory depth */
|
|
save = (MNTINFO*)0;
|
|
- for (mid = 1; mid <= max; mid++) {
|
|
+ for (mid = 0; mounts; mid++) {
|
|
MNTINFO *m, *n, *l;
|
|
n = mounts;
|
|
l = (MNTINFO*)0;
|
|
for (m = mounts; n; m = n) {
|
|
n = m->next;
|
|
- if (m->id != mid)
|
|
+ if (m->deep != mid)
|
|
continue;
|
|
l = m->prev;
|
|
if (m == mounts) {
|
|
@@ -290,7 +312,6 @@ static void init_mounts(void)
|
|
m->next = save;
|
|
m->prev = (MNTINFO*)0;
|
|
save = m;
|
|
- break;
|
|
}
|
|
}
|
|
mounts = save;
|
|
@@ -307,15 +328,14 @@ static void init_mounts(void)
|
|
}
|
|
}
|
|
|
|
-static MNTINFO *find_mount(const char * path)
|
|
+static int find_mount(const char * path, MNTINFO *s)
|
|
{
|
|
MNTINFO *m;
|
|
for (m = mounts; m; m = m->next) {
|
|
- if (strncmp(path, m->point, m->nlen))
|
|
- continue;
|
|
- break;
|
|
+ if (s == m)
|
|
+ return 1;
|
|
}
|
|
- return m;
|
|
+ return 0;
|
|
}
|
|
|
|
extern inline char * handl_buf(char *restrict buf)
|
|
@@ -627,6 +647,7 @@ int pidof (const char * inname, const ch
|
|
pid_t pid;
|
|
char *swapname = NULL;
|
|
char *fullname = (char *)inname;
|
|
+ char *realname = NULL;
|
|
MNTINFO *prefix = NULL;
|
|
PROC *p, *n;
|
|
|
|
@@ -659,12 +680,17 @@ int pidof (const char * inname, const ch
|
|
warn("cannot stat %s: %s\n", fullname, strerror(errno));
|
|
return -1;
|
|
}
|
|
- init_mounts();
|
|
- for (m = mounts; m; m = m->next) {
|
|
- if (m->dev != full_st.st_dev)
|
|
- continue;
|
|
- prefix = m;
|
|
- break;
|
|
+ realname = expandpath(fullname);
|
|
+ if (realname) {
|
|
+ init_mounts();
|
|
+ for (m = mounts; m; m = m->next) {
|
|
+ if (m->dev != full_st.st_dev)
|
|
+ continue;
|
|
+ if (strncmp(realname, m->point, m->nlen) != 0)
|
|
+ continue;
|
|
+ prefix = m;
|
|
+ break;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -727,20 +753,21 @@ int pidof (const char * inname, const ch
|
|
*/
|
|
if (!(flags & (KTHREAD|KSHORT)) && !isscrpt) {
|
|
char entry[PATH_MAX+1];
|
|
- char *realname = NULL;
|
|
- const char *name;
|
|
+ const char *name = NULL;
|
|
boolean found;
|
|
|
|
- if ((rll = readlinkat(dfd, here(d->d_name, "exe"), entry, PATH_MAX)) < 0) {
|
|
- if (errno != EPERM && errno != EACCES)
|
|
- goto risky;
|
|
- continue;
|
|
- }
|
|
- entry[rll] = '\0';
|
|
- name = handl_buf(entry);
|
|
+ if (prefix) {
|
|
+ if ((rll = readlinkat(dfd, here(d->d_name, "exe"), entry, PATH_MAX)) < 0) {
|
|
+ if (errno != EPERM && errno != EACCES)
|
|
+ goto risky;
|
|
+ continue;
|
|
+ }
|
|
+ entry[rll] = '\0';
|
|
+ name = handl_buf(entry);
|
|
|
|
- if (prefix && find_mount(name) != prefix)
|
|
- continue;
|
|
+ if (!find_mount(name, prefix))
|
|
+ continue;
|
|
+ }
|
|
|
|
if (fstatat(dfd, here(d->d_name, "exe"), &pid_st, 0) < 0) {
|
|
if (errno != EPERM && errno != EACCES)
|
|
@@ -765,18 +792,24 @@ int pidof (const char * inname, const ch
|
|
if (strlen(fullname) > PATH_MAX)
|
|
continue;
|
|
|
|
+ if (!name) {
|
|
+ if ((rll = readlinkat(dfd, here(d->d_name, "exe"), entry, PATH_MAX)) < 0) {
|
|
+ if (errno != EPERM && errno != EACCES)
|
|
+ goto risky;
|
|
+ continue;
|
|
+ }
|
|
+ entry[rll] = '\0';
|
|
+ name = handl_buf(entry);
|
|
+ }
|
|
+
|
|
if (strncmp(fullname, name, PATH_MAX) == 0) {
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
- if ((realname = realpath(name, NULL)) == (char*)0)
|
|
- continue;
|
|
-
|
|
- if (strncmp(realname, name, PATH_MAX) == 0)
|
|
+ if (realname && strncmp(realname, name, PATH_MAX) == 0)
|
|
found = true;
|
|
|
|
- free(realname);
|
|
|
|
break;
|
|
}
|
|
@@ -896,6 +929,7 @@ int verify_pidfile (const char * pid_fil
|
|
pid_t pid;
|
|
char *swapname = NULL, *bufp;
|
|
char *fullname = (char *)inname;
|
|
+ char *realname = NULL;
|
|
struct stat pid_st, full_st;
|
|
char buf[BUFSIZ];
|
|
|
|
@@ -958,6 +992,7 @@ int verify_pidfile (const char * pid_fil
|
|
warn("cannot stat %s: %s\n", fullname, strerror(errno));
|
|
return -1;
|
|
}
|
|
+ realname = expandpath(fullname);
|
|
}
|
|
|
|
if (flags & (KTHREAD|KSHORT)) {
|
|
@@ -997,7 +1032,6 @@ int verify_pidfile (const char * pid_fil
|
|
|
|
char entry[PATH_MAX+1];
|
|
const char *name;
|
|
- char *realname;
|
|
boolean found;
|
|
ssize_t rll;
|
|
|
|
@@ -1028,14 +1062,9 @@ int verify_pidfile (const char * pid_fil
|
|
break;
|
|
}
|
|
|
|
- if ((realname = realpath(fullname, NULL)) == (char*)0)
|
|
- goto out;
|
|
-
|
|
- if (strncmp(realname, name, PATH_MAX) == 0)
|
|
+ if (realname && strncmp(realname, name, PATH_MAX) == 0)
|
|
found = true;
|
|
|
|
- free(realname);
|
|
-
|
|
break;
|
|
}
|
|
|
|
@@ -1115,6 +1144,7 @@ int check_pids (const char * inname, con
|
|
boolean isscrpt = false;
|
|
char *swapname = (char*)0;
|
|
char *fullname = (char *)inname;
|
|
+ char *realname = (char*)0;
|
|
const char *pid;
|
|
struct stat pid_st, full_st;
|
|
PROC *p, *n, *l;
|
|
@@ -1132,6 +1162,7 @@ int check_pids (const char * inname, con
|
|
warn("cannot stat %s: %s\n", fullname, strerror(errno));
|
|
return -1;
|
|
}
|
|
+ realname = expandpath(fullname);
|
|
}
|
|
|
|
if (flags & (KTHREAD|KSHORT)) {
|
|
@@ -1191,7 +1222,6 @@ int check_pids (const char * inname, con
|
|
|
|
char entry[PATH_MAX+1];
|
|
const char *name;
|
|
- char *realname;
|
|
ssize_t rll;
|
|
|
|
if (pid_st.st_dev != full_st.st_dev)
|
|
@@ -1218,14 +1248,8 @@ int check_pids (const char * inname, con
|
|
if (strncmp(fullname, name, PATH_MAX) == 0)
|
|
continue; /* Found */
|
|
|
|
- if ((realname = realpath(fullname, NULL)) == (char*)0)
|
|
- goto ignore; /* Bogus */
|
|
-
|
|
- if (strncmp(realname, name, PATH_MAX) == 0) {
|
|
- free(realname);
|
|
+ if (realname && strncmp(realname, name, PATH_MAX) == 0)
|
|
continue; /* Found */
|
|
- }
|
|
- free(realname);
|
|
|
|
break;
|
|
}
|
|
@@ -1807,4 +1831,100 @@ void clear_nfs(void)
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * Somehow the realpath(3) glibc function call, nevertheless
|
|
+ * it avoids lstat(2) system calls.
|
|
+ */
|
|
+static char real[PATH_MAX+1];
|
|
+char* expandpath(const char * path)
|
|
+{
|
|
+ char tmpbuf[PATH_MAX+1];
|
|
+ const char *start, *end;
|
|
+ char *curr, *dest;
|
|
+ int deep = MAXSYMLINKS;
|
|
+
|
|
+ if (!path || *path == '\0')
|
|
+ return (char*)0;
|
|
+
|
|
+ curr = &real[0];
|
|
+
|
|
+ if (*path != '/') {
|
|
+ if (!getcwd(curr, PATH_MAX))
|
|
+ return (char*)0;
|
|
+ dest = rawmemchr(curr, '\0');
|
|
+ } else {
|
|
+ *curr = '/';
|
|
+ dest = curr + 1;
|
|
+ }
|
|
+
|
|
+ for (start = end = path; *start; start = end) {
|
|
+
|
|
+ while (*start == '/')
|
|
+ ++start;
|
|
+
|
|
+ for (end = start; *end && *end != '/'; ++end)
|
|
+ ;
|
|
+
|
|
+ if (end - start == 0)
|
|
+ break;
|
|
+ else if (end - start == 1 && start[0] == '.') {
|
|
+ ;
|
|
+ } else if (end - start == 2 && start[0] == '.' && start[1] == '.') {
|
|
+ if (dest > curr + 1)
|
|
+ while ((--dest)[-1] != '/')
|
|
+ ;
|
|
+ } else {
|
|
+ char lnkbuf[PATH_MAX+1];
|
|
+ size_t len;
|
|
+ ssize_t n;
|
|
+
|
|
+ if (dest[-1] != '/')
|
|
+ *dest++ = '/';
|
|
+
|
|
+ if (dest + (end - start) > curr + PATH_MAX) {
|
|
+ errno = ENAMETOOLONG;
|
|
+ return (char*)0;
|
|
+ }
|
|
+
|
|
+ dest = mempcpy(dest, start, end - start);
|
|
+ *dest = '\0';
|
|
+
|
|
+ if (deep-- < 0) {
|
|
+ errno = ELOOP;
|
|
+ return (char*)0;
|
|
+ }
|
|
+
|
|
+ errno = 0;
|
|
+ if ((n = readlink(curr, lnkbuf, PATH_MAX)) < 0) {
|
|
+ deep = MAXSYMLINKS;
|
|
+ if (errno == EINVAL)
|
|
+ continue; /* Not a symlink */
|
|
+ return (char*)0;
|
|
+ }
|
|
+ lnkbuf[n] = '\0'; /* Don't be fooled by readlink(2) */
|
|
+
|
|
+ len = strlen(end);
|
|
+ if ((n + len) > PATH_MAX) {
|
|
+ errno = ENAMETOOLONG;
|
|
+ return (char*)0;
|
|
+ }
|
|
+
|
|
+ memmove(&tmpbuf[n], end, len + 1);
|
|
+ path = end = memcpy(tmpbuf, lnkbuf, n);
|
|
+
|
|
+ if (lnkbuf[0] == '/')
|
|
+ dest = curr + 1;
|
|
+ else if (dest > curr + 1)
|
|
+ while ((--dest)[-1] != '/');
|
|
+
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (dest > curr + 1 && dest[-1] == '/')
|
|
+ --dest;
|
|
+ *dest = '\0';
|
|
+
|
|
+ return curr;
|
|
+}
|
|
+
|
|
/* libinit.c ends here */
|