2212 lines
55 KiB
Plaintext
2212 lines
55 KiB
Plaintext
--- Makefile
|
|
+++ Makefile 2011-02-04 14:36:46.959926571 +0000
|
|
@@ -12,7 +12,7 @@ INITDIR = /etc/init.d
|
|
PREFIX = /usr
|
|
DEBUG =
|
|
DESTDIR =
|
|
-VERSION = 2.17
|
|
+VERSION = 2.18
|
|
DATE = $(shell date +'%d%b%y' | tr '[:lower:]' '[:upper:]')
|
|
|
|
ifneq ($(INC),)
|
|
@@ -55,6 +55,7 @@ UBINPRG =
|
|
ifeq ($(DISTRO),SuSE)
|
|
UBINPRG += usleep
|
|
UBINPRG += fsync
|
|
+ SBINPRG += rvmtab
|
|
SBINPRG += vhangup
|
|
SBINPRG += mkill
|
|
endif
|
|
@@ -101,6 +102,9 @@ vhangup: vhangup.c
|
|
mkill: mkill.c libinit.o
|
|
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
|
|
|
+rvmtab: rvmtab.c libinit.o
|
|
+ $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
|
+
|
|
clean:
|
|
$(RM) *.o *~ $(SBINPRG) $(UBINPRG)
|
|
|
|
@@ -143,6 +147,7 @@ FILES = README \
|
|
checkproc.8 \
|
|
libinit.c \
|
|
libinit.h \
|
|
+ lists.h \
|
|
usleep.c \
|
|
usleep.1 \
|
|
fsync.c \
|
|
@@ -151,6 +156,8 @@ FILES = README \
|
|
vhangup.8 \
|
|
mkill.c \
|
|
mkill.8 \
|
|
+ rvmtab.c \
|
|
+ rvmtab.8 \
|
|
killproc-$(VERSION).lsm
|
|
|
|
dest:
|
|
--- checkproc.c
|
|
+++ checkproc.c 2011-02-04 14:01:49.604190644 +0000
|
|
@@ -31,10 +31,11 @@ int main(int argc, char **argv)
|
|
int blog = 0;
|
|
#endif
|
|
struct stat st;
|
|
- PROC * list;
|
|
+ list_t *list;
|
|
char *fullname = NULL, * basename = NULL;
|
|
char *pid_file = NULL, *ignore_file = NULL;
|
|
- char *root = NULL, *iargv[argc];
|
|
+ char *root = NULL;
|
|
+ extension char *iargv[argc];
|
|
char *posixa, *posixb; /* Don't fool me with posix correct */
|
|
int quiet = 1, iargc = 0;
|
|
unsigned short flags = (DAEMON|PIDOF|NZOMBIE);
|
|
@@ -166,7 +167,7 @@ int main(int argc, char **argv)
|
|
if (remember_pids(pid_file,fullname,root,flags) < 0)
|
|
exit(LSB_STATUS_PROOFX);
|
|
|
|
- if (!remember)
|
|
+ if (list_empty(&remember))
|
|
exit(LSB_STATUS_NOPROC); /* New LSB: no pid file is no job */
|
|
}
|
|
free(pid_file);
|
|
@@ -210,7 +211,7 @@ int main(int argc, char **argv)
|
|
if (verify_pidfile(pid_file,fullname,root,flags,false) < 0)
|
|
exit(LSB_STATUS_PROOFX);
|
|
}
|
|
- if (!remember) { /* No process found with pid file */
|
|
+ if (list_empty(&remember)) { /* No process found with pid file */
|
|
if (pid_forced)
|
|
exit(LSB_STATUS_PROOFX);
|
|
if (pidof(fullname,root,flags) < 0)
|
|
@@ -228,16 +229,17 @@ int main(int argc, char **argv)
|
|
clear_pids(); /* Remove all pids which should be ignored */
|
|
|
|
num = 0; /* If quiet we could test 'remember' and exit appropiate */
|
|
- for(list = remember; list; list = list->next) {
|
|
+ list_for_each(list, &remember) {
|
|
+ PROC *proc = list_entry(list, PROC);
|
|
if (!quiet) {
|
|
if (num) putchar(' ');
|
|
- printf("%d", (int)list->pid);
|
|
+ printf("%ld", (long int)proc->pid);
|
|
}
|
|
#ifdef USE_BLOGD
|
|
if (bootlog(B_NOTICE, "%s: %s ", we_are, fullname) == 0) {
|
|
blog++;
|
|
if (num) bootlog(-1, " ");
|
|
- bootlog(-1, "%d", (int)list->pid);
|
|
+ bootlog(-1, "%ld", (long int)proc->pid);
|
|
}
|
|
#endif
|
|
num++;
|
|
--- killproc.c
|
|
+++ killproc.c 2011-02-04 14:00:52.143926916 +0000
|
|
@@ -40,10 +40,11 @@ int main(int argc, char **argv)
|
|
{
|
|
int c, snum;
|
|
struct stat st;
|
|
- PROC * list;
|
|
+ list_t *list;
|
|
char *fullname = NULL, *basename = NULL;
|
|
char *pid_file = NULL, *ignore_file = NULL;
|
|
- char *root = NULL, *iargv[argc];
|
|
+ char *root = NULL;
|
|
+ extension char *iargv[argc];
|
|
char *posixa, *posixb; /* Don't fool me with posix correct */
|
|
int process_group = 0, group_leader = 0, wait = 5, iargc = 0;
|
|
unsigned short flags = (KILL|PIDOF|KSTOP);
|
|
@@ -216,7 +217,7 @@ int main(int argc, char **argv)
|
|
if (remember_pids(pid_file,fullname,root,flags) < 0)
|
|
exit(LSB_PROOFX);
|
|
|
|
- if (!remember)
|
|
+ if (list_empty(&remember))
|
|
exit(LSB_NOPROC); /* New LSB: no pid file is no job */
|
|
}
|
|
free(pid_file);
|
|
@@ -266,7 +267,7 @@ int main(int argc, char **argv)
|
|
clear_pids(); /* Remove all pids which should be ignored */
|
|
|
|
/* Do main work */
|
|
- if (!remember) {
|
|
+ if (list_empty(&remember)) {
|
|
/* killing a none existing process is already success.
|
|
* Nevertheless LSB says that we should note that if
|
|
* a signal is explicit given.
|
|
@@ -275,8 +276,10 @@ int main(int argc, char **argv)
|
|
}
|
|
|
|
num = 0;
|
|
- for(list = remember; list; list = list->next)
|
|
- do_kill(basename, list->pid, snum, group_leader, process_group);
|
|
+ list_for_each(list, &remember) {
|
|
+ PROC *proc = list_entry(list, PROC);
|
|
+ do_kill(basename, proc->pid, snum, group_leader, process_group);
|
|
+ }
|
|
|
|
if (snum == SIGTERM || snum == SIGKILL) {
|
|
int partsec = 5*wait; /* We look 5 times within a second */
|
|
@@ -290,7 +293,7 @@ again:
|
|
if (check_pids(fullname,root,flags) < 0)
|
|
exit(LSB_PROOFX);
|
|
|
|
- if (!remember) /* success */
|
|
+ if (list_empty(&remember)) /* success */
|
|
goto success;
|
|
|
|
fflush(stdout);
|
|
@@ -309,8 +312,10 @@ again:
|
|
if (check_pids(fullname,root,flags) < 0)
|
|
exit(LSB_PROOFX);
|
|
|
|
- for(list = remember; list; list = list->next)
|
|
- do_kill(basename, list->pid, SIGKILL, group_leader, process_group);
|
|
+ list_for_each(list, &remember) {
|
|
+ PROC *proc = list_entry(list, PROC);
|
|
+ do_kill(basename, proc->pid, SIGKILL, group_leader, process_group);
|
|
+ }
|
|
|
|
/* Do we have killed them? */
|
|
|
|
@@ -318,7 +323,7 @@ again:
|
|
if (check_pids(fullname,root,flags) < 0)
|
|
exit(LSB_PROOFX);
|
|
|
|
- if (remember)
|
|
+ if (!list_empty(&remember))
|
|
goto badterm;
|
|
|
|
success:
|
|
--- libinit.c
|
|
+++ libinit.c 2011-02-04 13:59:58.869397977 +0000
|
|
@@ -41,8 +41,14 @@ extern void vsyslog (int, const char *,
|
|
|
|
char * newenvp[MAXENV];
|
|
unsigned newenvc = 0;
|
|
+
|
|
+#if 1
|
|
+list_t remember = {&remember, &remember};
|
|
+list_t doignore = {&doignore, &doignore};
|
|
+#else
|
|
PROC * remember = (PROC*)0;
|
|
PROC * doignore = (PROC*)0;
|
|
+#endif
|
|
|
|
char * we_are;
|
|
unsigned short stopped = 0;
|
|
@@ -218,29 +224,50 @@ static struct _sys_signals {
|
|
{ 0, "EXIT" }
|
|
};
|
|
|
|
+/*
|
|
+ * Calculate the depth of a directory, root has zero depth.
|
|
+ */
|
|
+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;
|
|
- struct _mntinfo_ *prev;
|
|
- struct _mntinfo_ *parent;
|
|
+ list_t this;
|
|
int id, parid;
|
|
- dev_t dev;
|
|
- size_t nlen;
|
|
- char * point;
|
|
+ dev_t dev;
|
|
+ size_t nlen;
|
|
+ char *point;
|
|
} MNTINFO;
|
|
|
|
-static MNTINFO *mounts;
|
|
+static list_t mounts = {&mounts, &mounts};
|
|
+static list_t save = {&save, &save};
|
|
|
|
static void init_mounts(void)
|
|
{
|
|
char point[PATH_MAX+1];
|
|
+ struct stat st;
|
|
int mid, parid, max = 0;
|
|
uint maj, min;
|
|
- MNTINFO *save;
|
|
FILE * mnt;
|
|
-
|
|
- if (mounts)
|
|
- return;
|
|
+
|
|
+ /* Stat /proc/version to see if /proc is mounted. */
|
|
+ if (stat("/proc/version", &st) < 0)
|
|
+ getproc();
|
|
+
|
|
if ((mnt = fopen("/proc/self/mountinfo", "r")) == (FILE*)0)
|
|
return;
|
|
while (fscanf(mnt, "%i %i %u:%u %*s %s %*[^\n]", &mid, &parid, &maj, &min, &point[0]) == 5) {
|
|
@@ -250,72 +277,46 @@ static void init_mounts(void)
|
|
if (stopped) kill(-1, SIGCONT);
|
|
error(100, "malloc(): %s\n", strerror(errno));
|
|
}
|
|
+ append(p, mounts);
|
|
p->point = ((char*)p)+alignof(MNTINFO);
|
|
strcpy(p->point, point);
|
|
p->nlen = nlen;
|
|
p->parid = parid;
|
|
p->dev = makedev(maj, min);
|
|
p->id = mid;
|
|
- if (mounts)
|
|
- mounts->prev = p;
|
|
- p->next = mounts;
|
|
- 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 */
|
|
- save = (MNTINFO*)0;
|
|
+ /* Sort mount points accordingly to their reverse mount order */
|
|
+ initial(&save);
|
|
for (mid = 1; mid <= max; mid++) {
|
|
- MNTINFO *m, *n, *l;
|
|
- n = mounts;
|
|
- l = (MNTINFO*)0;
|
|
- for (m = mounts; n; m = n) {
|
|
- n = m->next;
|
|
- if (m->id != mid)
|
|
+ list_t *this, *cpy;
|
|
+ list_for_each_safe(this, cpy, &mounts) {
|
|
+ MNTINFO *m = list_entry(this, MNTINFO);
|
|
+ if (mid != m->id)
|
|
continue;
|
|
- l = m->prev;
|
|
- if (m == mounts) {
|
|
- if (n) n->prev = (MNTINFO*)0;
|
|
- mounts = n;
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- }
|
|
- if (save)
|
|
- save->prev = m;
|
|
- m->next = save;
|
|
- m->prev = (MNTINFO*)0;
|
|
- save = m;
|
|
+ move_head(this, &save);
|
|
break;
|
|
}
|
|
- }
|
|
- mounts = save;
|
|
-
|
|
- /* Now determine the parent of each mount point */
|
|
- for (save = mounts; save; save = save->next) {
|
|
- MNTINFO *p;
|
|
- for (p = mounts; p; p = p->next) {
|
|
- if (save->parid != p->id)
|
|
+ list_for_each_safe(this, cpy, &mounts) {
|
|
+ MNTINFO *m = list_entry(this, MNTINFO);
|
|
+ if (mid != m->parid)
|
|
continue;
|
|
- save->parent = p;
|
|
- break;
|
|
+ move_head(this, &save);
|
|
}
|
|
}
|
|
+ if (!list_empty(&mounts)) {
|
|
+ if (stopped) kill(-1, SIGCONT);
|
|
+ error(100, "sort(): %s\n", strerror(EBADE));
|
|
+ }
|
|
+ join(&save, &mounts);
|
|
}
|
|
|
|
-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;
|
|
- }
|
|
- return m;
|
|
+ return (strncmp(path, s->point, s->nlen) == 0);
|
|
}
|
|
|
|
extern inline char * handl_buf(char *restrict buf)
|
|
@@ -333,7 +334,7 @@ extern inline char * handl_buf(char *res
|
|
/* write to syslog file if not open terminal */
|
|
static void nsyslog(int pri, const char *fmt, va_list args)
|
|
{
|
|
- char newfmt[strlen(we_are)+2+strlen(fmt)+1];
|
|
+ extension char newfmt[strlen(we_are)+2+strlen(fmt)+1];
|
|
|
|
strcat(strcat(strcpy(newfmt, we_are), ": "), fmt);
|
|
|
|
@@ -365,7 +366,7 @@ void warn(const char *fmt, ...)
|
|
|
|
static void dsyslog(int pri, const char *fmt, va_list args)
|
|
{
|
|
- char newfmt[strlen(we_are)+2+strlen(fmt)+1];
|
|
+ extension char newfmt[strlen(we_are)+2+strlen(fmt)+1];
|
|
|
|
strcat(strcat(strcpy(newfmt, we_are), ": "), fmt);
|
|
vsyslog(pri, newfmt, args);
|
|
@@ -627,8 +628,9 @@ 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;
|
|
+ list_t *m, *n;
|
|
|
|
p_pid = getpid();
|
|
p_ppid = getppid();
|
|
@@ -641,30 +643,35 @@ int pidof (const char * inname, const ch
|
|
return -1;
|
|
}
|
|
|
|
- n = remember;
|
|
- for (p = remember; n; p = n) {
|
|
- n = p->next;
|
|
+ list_for_each_safe(m, n, &remember) {
|
|
+ PROC *p = list_entry(m, PROC);
|
|
+ delete(m);
|
|
free(p);
|
|
}
|
|
- remember = (PROC*)0;
|
|
|
|
/* killproc, daemon/startproc, pidof/pidofproc: stat fullname if a
|
|
* real program is handled, skip this if we handle a kernel thread */
|
|
|
|
if (!(flags & (KTHREAD|KSHORT))) {
|
|
- MNTINFO *m;
|
|
errno = 0;
|
|
if (rlstat(&fullname, &full_st, flags) < 0) {
|
|
/* stat() follows soft links -> security */
|
|
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) {
|
|
+ list_t *ptr;
|
|
+ init_mounts();
|
|
+ list_for_each(ptr, &mounts) {
|
|
+ MNTINFO *m = list_entry(ptr, MNTINFO);
|
|
+ if (m->dev != full_st.st_dev)
|
|
+ continue;
|
|
+ if (strncmp(realname, m->point, m->nlen) != 0)
|
|
+ continue;
|
|
+ prefix = m;
|
|
+ break;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -727,20 +734,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 +773,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,17 +910,17 @@ 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];
|
|
|
|
if (!ignore) {
|
|
- PROC *p, *n;
|
|
- n = remember;
|
|
- for (p = remember; n; p = n) {
|
|
- n = p->next;
|
|
+ list_t *m, *n;
|
|
+ list_for_each_safe(m, n, &remember) {
|
|
+ PROC *p = list_entry(m, PROC);
|
|
+ delete(m);
|
|
free(p);
|
|
}
|
|
- remember = (PROC*)0;
|
|
}
|
|
|
|
errno = 0;
|
|
@@ -958,6 +972,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 +1012,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 +1042,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,9 +1124,10 @@ 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;
|
|
+ list_t *m, *n;
|
|
int fp;
|
|
|
|
if (!fullname) {
|
|
@@ -1132,6 +1142,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)) {
|
|
@@ -1144,12 +1155,9 @@ int check_pids (const char * inname, con
|
|
swapname = swap_name(base_name(fullname));
|
|
}
|
|
|
|
- n = remember;
|
|
- l = (PROC*)0;
|
|
- for(p = remember; n; p = n) {
|
|
+ list_for_each_safe(m, n, &remember) {
|
|
+ PROC *p = list_entry(m, PROC);
|
|
boolean skip = false;
|
|
- l = p->prev;
|
|
- n = p->next;
|
|
|
|
errno = 0;
|
|
if ((kill(p->pid, 0) < 0) && (errno == ESRCH))
|
|
@@ -1191,7 +1199,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 +1225,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;
|
|
}
|
|
@@ -1277,20 +1278,8 @@ int check_pids (const char * inname, con
|
|
ignore:
|
|
|
|
/* Remove this entry in remember */
|
|
- if (p == remember) {
|
|
- if (n) n->prev = (PROC*)0;
|
|
- remember = n;
|
|
- free(p);
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- free(p);
|
|
- } else {
|
|
- warn("error in linked list handling\n");
|
|
- free(swapname);
|
|
- return -1;
|
|
- }
|
|
-
|
|
+ delete(m);
|
|
+ free(p);
|
|
}
|
|
|
|
free(swapname);
|
|
@@ -1302,27 +1291,17 @@ int check_pids (const char * inname, con
|
|
*/
|
|
void clear_pids (void)
|
|
{
|
|
- PROC *p, *n, *l;
|
|
+ list_t *n, *l;
|
|
|
|
- n = remember;
|
|
- l = (PROC*)0;
|
|
- for(p = remember; n; p = n) {
|
|
- l = p->prev;
|
|
- n = p->next;
|
|
+ list_for_each_safe(n, l, &remember) {
|
|
+ PROC *p = list_entry(n, PROC);
|
|
|
|
if (!check_ignore(p->pid) && !check_ignore(p->sid))
|
|
continue;
|
|
|
|
/* Remove this entry in remember */
|
|
- if (p == remember) {
|
|
- if (n) n->prev = (PROC*)0;
|
|
- remember = n;
|
|
- free(p);
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- free(p);
|
|
- }
|
|
+ delete(n);
|
|
+ free(p);
|
|
}
|
|
}
|
|
|
|
@@ -1590,22 +1569,22 @@ out:
|
|
|
|
typedef struct _shadow_
|
|
{
|
|
- struct _shadow_ *next;
|
|
- struct _shadow_ *prev;
|
|
+ list_t this;
|
|
size_t nlen;
|
|
char * name;
|
|
} SHADOW;
|
|
|
|
typedef struct _nfs_
|
|
{
|
|
- struct _nfs_ *next; /* Pointer to next struct. */
|
|
- struct _nfs_ *prev; /* Pointer to previous st. */
|
|
- SHADOW *shadow; /* Pointer to shadows */
|
|
+ list_t this;
|
|
+ SHADOW shadow; /* Pointer to shadows */
|
|
+ int order;
|
|
+ int parent;
|
|
size_t nlen;
|
|
char * name;
|
|
} NFS;
|
|
|
|
-NFS * nfs = (NFS*)0;
|
|
+static list_t nfs = {&nfs, &nfs};
|
|
|
|
static inline int isnetfs(const char * type)
|
|
{
|
|
@@ -1619,35 +1598,86 @@ static inline int isnetfs(const char * t
|
|
|
|
void init_nfs(void)
|
|
{
|
|
+ char buffer[LINE_MAX];
|
|
struct stat st;
|
|
- struct mntent * ent;
|
|
+ struct mntent ent;
|
|
FILE * mnt;
|
|
|
|
/* Stat /proc/version to see if /proc is mounted. */
|
|
if (stat("/proc/version", &st) < 0)
|
|
getproc();
|
|
|
|
+ /* Use /proc/self/mountinfo if available */
|
|
+ if ((mnt = fopen("/proc/self/mountinfo", "r"))) {
|
|
+ char fstype[126];
|
|
+ int mid, parid, max = 1;
|
|
+
|
|
+ while (fscanf(mnt, "%i %i %*u:%*u %*s %s - %*s %s %*[^\n]", &mid, &parid, &buffer[0], &fstype[0]) == 3) {
|
|
+ NFS *restrict ptr;
|
|
+ size_t nlen;
|
|
+
|
|
+ if (!isnetfs(fstype))
|
|
+ continue;
|
|
+ nlen = strlen(buffer);
|
|
+
|
|
+ if (posix_memalign((void*)&ptr, sizeof(void*), alignof(NFS)+(nlen+1)) != 0)
|
|
+ error(100, "malloc(): %s\n", strerror(errno));
|
|
+ append(ptr, nfs);
|
|
+ ptr->order = mid;
|
|
+ ptr->parent = parid;
|
|
+ ptr->name = ((char*)ptr)+alignof(NFS);
|
|
+ strcpy(ptr->name, buffer);
|
|
+ ptr->nlen = nlen;
|
|
+ initial(&ptr->shadow.this); /* not required as we sort below */
|
|
+ if (mid > max)
|
|
+ max = mid;
|
|
+ }
|
|
+ fclose(mnt);
|
|
+
|
|
+ /*
|
|
+ * Now sort into reverse mount order, with this we do not
|
|
+ * need any shadow mounts anymore.
|
|
+ */
|
|
+ initial(&save);
|
|
+ for (mid = 1; mid <= max; mid++) {
|
|
+ list_t *this, *cpy;
|
|
+ list_for_each_safe(this, cpy, &nfs) {
|
|
+ NFS * m = list_entry(this, NFS);
|
|
+ if (mid != m->order)
|
|
+ continue;
|
|
+ move_head(this, &save);
|
|
+ break;
|
|
+ }
|
|
+ list_for_each_safe(this, cpy, &nfs) {
|
|
+ NFS * m = list_entry(this, NFS);
|
|
+ if (mid != m->parent)
|
|
+ continue;
|
|
+ move_head(this, &save);
|
|
+ }
|
|
+ }
|
|
+ if (!list_empty(&nfs))
|
|
+ error(100, "init_mnt(): %s\n", strerror(EBADE));
|
|
+ join(&save, &nfs);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
|
|
return;
|
|
|
|
- while ((ent = getmntent(mnt))) {
|
|
- if (isnetfs(ent->mnt_type)) {
|
|
- const size_t nlen = strlen(ent->mnt_dir);
|
|
+ while (getmntent_r(mnt, &ent, buffer, sizeof(buffer))) {
|
|
+ if (isnetfs(ent.mnt_type)) {
|
|
+ const size_t nlen = strlen(ent.mnt_dir);
|
|
NFS *restrict p;
|
|
|
|
if (posix_memalign((void*)&p, sizeof(void*), alignof(NFS)+(nlen+1)) != 0) {
|
|
if (stopped) kill(-1, SIGCONT);
|
|
error(100, "malloc(): %s\n", strerror(errno));
|
|
}
|
|
+ append(p, nfs);
|
|
p->name = ((char*)p)+alignof(NFS);
|
|
- strcpy(p->name, ent->mnt_dir);
|
|
+ strcpy(p->name, ent.mnt_dir);
|
|
p->nlen = nlen;
|
|
- p->shadow = (SHADOW*)0;
|
|
- if (nfs)
|
|
- nfs->prev = p;
|
|
- p->next = nfs;
|
|
- p->prev = (NFS*)0;
|
|
- nfs = p;
|
|
+ initial(&p->shadow.this);
|
|
}
|
|
}
|
|
endmntent(mnt);
|
|
@@ -1655,43 +1685,41 @@ void init_nfs(void)
|
|
if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
|
|
return;
|
|
|
|
- while ((ent = getmntent(mnt))) {
|
|
- NFS *p;
|
|
+ while (getmntent_r(mnt, &ent, buffer, sizeof(buffer))) {
|
|
+ list_t *ptr;
|
|
|
|
- for (p = nfs; p; p = p->next) {
|
|
+ list_for_each(ptr, &nfs) {
|
|
+ NFS *p = list_entry(ptr, NFS);
|
|
SHADOW * restrict s;
|
|
size_t nlen;
|
|
|
|
- if (strcmp(ent->mnt_dir, p->name) == 0)
|
|
+ if (strcmp(ent.mnt_dir, p->name) == 0)
|
|
continue;
|
|
- if (strncmp(ent->mnt_dir, p->name, p->nlen) != 0)
|
|
+ if (strncmp(ent.mnt_dir, p->name, p->nlen) != 0)
|
|
continue;
|
|
|
|
- nlen = strlen(ent->mnt_dir);
|
|
+ nlen = strlen(ent.mnt_dir);
|
|
if (posix_memalign((void*)&s, sizeof(void*), alignof(SHADOW)+(nlen+1))) {
|
|
if (stopped) kill(-1, SIGCONT);
|
|
error(100, "malloc(): %s\n", strerror(errno));
|
|
}
|
|
+ append(s, p->shadow.this);
|
|
s->name = ((char*)s)+alignof(SHADOW);
|
|
- strcpy(s->name, ent->mnt_dir);
|
|
+ strcpy(s->name, ent.mnt_dir);
|
|
s->nlen = nlen;
|
|
- if (p->shadow)
|
|
- p->shadow->prev = s;
|
|
- s->next = p->shadow;
|
|
- s->prev = (SHADOW*)0;
|
|
- p->shadow = s;
|
|
}
|
|
}
|
|
endmntent(mnt);
|
|
}
|
|
|
|
-static inline boolean shadow(SHADOW *restrict this, const char *restrict name, const size_t nlen)
|
|
+static inline boolean shadow(list_t *restrict shadow, const char *restrict name, const size_t nlen)
|
|
{
|
|
- SHADOW *s;
|
|
+ list_t *ptr;
|
|
|
|
- if (!this)
|
|
+ if (!shadow || list_empty(shadow))
|
|
goto out;
|
|
- for (s = this; s; s = s->next) {
|
|
+ list_for_each(ptr, shadow) {
|
|
+ SHADOW *s =list_entry(ptr, SHADOW);
|
|
if (nlen < s->nlen)
|
|
continue;
|
|
if (name[s->nlen] != '\0' && name[s->nlen] != '/')
|
|
@@ -1709,7 +1737,8 @@ boolean check4nfs(const char * path)
|
|
const char *curr;
|
|
int deep = MAXSYMLINKS;
|
|
|
|
- if (!nfs) goto out;
|
|
+ if (list_empty(&nfs))
|
|
+ goto out;
|
|
|
|
curr = path;
|
|
do {
|
|
@@ -1747,15 +1776,16 @@ boolean check4nfs(const char * path)
|
|
} while (true);
|
|
|
|
if (errno == EINVAL) {
|
|
+ list_t *ptr;
|
|
const size_t nlen = strlen(curr);
|
|
- NFS *p;
|
|
- for (p = nfs; p; p = p->next) {
|
|
+ list_for_each(ptr, &nfs) {
|
|
+ NFS *p = list_entry(ptr, NFS);
|
|
if (nlen < p->nlen)
|
|
continue;
|
|
if (curr[p->nlen] != '\0' && curr[p->nlen] != '/')
|
|
continue;
|
|
if (!strncmp(curr, p->name, p->nlen)) {
|
|
- if (shadow(p->shadow, curr, nlen))
|
|
+ if (shadow(&p->shadow.this, curr, nlen))
|
|
continue;
|
|
return true;
|
|
}
|
|
@@ -1765,46 +1795,123 @@ out:
|
|
return false;
|
|
}
|
|
|
|
-static inline void clear_shadow(SHADOW *restrict shadow)
|
|
+static void clear_shadow(list_t *restrict shadow)
|
|
{
|
|
- SHADOW *s, *n, *l;
|
|
-
|
|
- n = shadow;
|
|
- l = (SHADOW*)0;
|
|
- for (s = shadow; n; s = n) {
|
|
- l = s->prev;
|
|
- n = s->next;
|
|
- if (s == shadow) {
|
|
- if (n) n->prev = (SHADOW*)0;
|
|
- shadow = n;
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- }
|
|
+ list_t *this, *ptr;
|
|
+ list_for_each_safe(this, ptr, shadow) {
|
|
+ SHADOW *s = list_entry(this, SHADOW);
|
|
+ delete(this);
|
|
free(s);
|
|
}
|
|
}
|
|
|
|
void clear_nfs(void)
|
|
{
|
|
- NFS *p, *n, *l;
|
|
+ list_t *this, *ptr;
|
|
|
|
- n = nfs;
|
|
- l = (NFS*)0;
|
|
- for (p = nfs; n; p = n) {
|
|
- l = p->prev;
|
|
- n = p->next;
|
|
- if (p == nfs) {
|
|
- if (n) n->prev = (NFS*)0;
|
|
- nfs = n;
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- }
|
|
- if (p->shadow)
|
|
- clear_shadow(p->shadow);
|
|
+ list_for_each_safe(this, ptr, &nfs) {
|
|
+ NFS *p = list_entry(this, NFS);
|
|
+ delete(this);
|
|
+ if (!list_empty(&p->shadow.this))
|
|
+ clear_shadow(&p->shadow.this);
|
|
free(p);
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * 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 */
|
|
--- libinit.h
|
|
+++ libinit.h 2011-02-04 14:11:37.615926560 +0000
|
|
@@ -19,6 +19,8 @@
|
|
* 2000/11/10 Werner Fink: LSB specs, logging
|
|
*/
|
|
|
|
+#ifndef _LIBINIT_H
|
|
+#define _LIBINIT_H
|
|
#ifndef _GNU_SOURCE
|
|
# define _GNU_SOURCE
|
|
#endif
|
|
@@ -44,13 +46,7 @@
|
|
#ifdef USE_BLOGD
|
|
# include <libblogger.h>
|
|
#endif
|
|
-
|
|
-#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
|
|
-# ifndef restrict
|
|
-# define restrict __restrict__
|
|
-# endif
|
|
-#endif
|
|
-#define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
|
|
+#include "lists.h"
|
|
|
|
/*
|
|
* LSB specs:
|
|
@@ -118,8 +114,6 @@
|
|
#define DEFPIDEXT ".pid"
|
|
#define DEFPIDLEN 14 /* The string length of /var/run/.pid + 1 */
|
|
|
|
-typedef enum _boolean {false, true} boolean;
|
|
-
|
|
extern char **environ;
|
|
extern char * newenvp[];
|
|
extern unsigned newenvc;
|
|
@@ -139,10 +133,12 @@ extern void clear_pids (void);
|
|
extern void error(int stat, const char *fmt, ...);
|
|
extern void warn(const char *fmt, ...);
|
|
extern int rlstat(char ** file, struct stat *st, const unsigned short flag);
|
|
+extern char* expandpath(const char * path);
|
|
extern void init_nfs(void);
|
|
extern void clear_nfs(void);
|
|
extern void getproc(void);
|
|
extern boolean check4nfs(const char * path);
|
|
+extern size_t dirdepth(const char *const path);
|
|
|
|
/* Feature */
|
|
extern int signame_to_signum (const char *sig);
|
|
@@ -171,14 +167,13 @@ static inline void list_signames(void)
|
|
|
|
typedef struct _proc_
|
|
{
|
|
- struct _proc_ *next; /* Pointer to next struct. */
|
|
- struct _proc_ *prev; /* Pointer to previous st. */
|
|
- pid_t pid; /* Process ID. */
|
|
- pid_t sid; /* Session ID. */
|
|
+ list_t this;
|
|
+ pid_t pid; /* Process ID. */
|
|
+ pid_t sid; /* Session ID. */
|
|
} PROC;
|
|
|
|
-extern PROC * remember;
|
|
-extern PROC * doignore;
|
|
+extern list_t remember;
|
|
+extern list_t doignore;
|
|
|
|
/* Inlined functions: just like macros */
|
|
|
|
@@ -301,31 +296,21 @@ static inline void do_list(const pid_t p
|
|
p->pid = pid;
|
|
p->sid = sid;
|
|
if (ignore) {
|
|
- if (doignore)
|
|
- doignore->prev = p;
|
|
- p->next = doignore;
|
|
- p->prev = (PROC*)0;
|
|
- doignore = p;
|
|
+ append(p, doignore);
|
|
} else {
|
|
- if (remember)
|
|
- remember->prev = p;
|
|
- p->next = remember;
|
|
- p->prev = (PROC*)0;
|
|
- remember = p;
|
|
+ append(p, remember);
|
|
}
|
|
-
|
|
- return;
|
|
}
|
|
|
|
static inline boolean check_ignore(const pid_t pid)
|
|
{
|
|
- PROC * q, * m = doignore;
|
|
+ list_t *m;
|
|
|
|
if (pid <= 1)
|
|
goto out;
|
|
|
|
- for (q = doignore; m; q = m) {
|
|
- m = q->next;
|
|
+ list_for_each(m, &doignore) {
|
|
+ PROC *q = list_entry(m, PROC);
|
|
if (pid == q->pid)
|
|
return true;
|
|
}
|
|
@@ -335,28 +320,20 @@ out:
|
|
|
|
static inline void clear_ignore(void)
|
|
{
|
|
- PROC * p, *l, * n = remember;
|
|
+ list_t *n, *l;
|
|
|
|
- if (!doignore)
|
|
+ if (list_empty(&doignore))
|
|
return;
|
|
|
|
- for (p = remember; n; p = n) {
|
|
- l = p->prev;
|
|
- n = p->next;
|
|
+ list_for_each_safe(n, l, &remember) {
|
|
+ PROC *p = list_entry(n, PROC);
|
|
|
|
if (!check_ignore(p->pid))
|
|
continue;
|
|
|
|
/* Remove this entry in remember because we ignore it */
|
|
- if (p == remember) {
|
|
- if (n) n->prev = (PROC*)0;
|
|
- remember = n;
|
|
- free(p);
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- free(p);
|
|
- }
|
|
+ delete(n);
|
|
+ free(p);
|
|
}
|
|
}
|
|
-/* libinit.h ends here */
|
|
+#endif /* _LIBINIT_H */
|
|
--- lists.h
|
|
+++ lists.h 2011-02-03 09:46:06.375927048 +0000
|
|
@@ -0,0 +1,248 @@
|
|
+/*
|
|
+ * lists.h Simple doubly linked list implementation,
|
|
+ * based on <linux/list.h> and <linux/prefetch.h>.
|
|
+ *
|
|
+ * Version: 0.1 01-Feb-2011 Fink
|
|
+ *
|
|
+ * Copyright 2011 Werner Fink, 2005 SUSE LINUX Products GmbH, Germany.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * Author: Werner Fink <werner@suse.de>, 2011
|
|
+ */
|
|
+
|
|
+#ifndef _LISTS_H
|
|
+#define _LISTS_H
|
|
+
|
|
+#include <stddef.h>
|
|
+#include <sys/types.h>
|
|
+
|
|
+typedef enum _boolean {false, true} boolean;
|
|
+typedef unsigned char uchar;
|
|
+#ifndef __USE_MISC
|
|
+typedef unsigned short ushort;
|
|
+typedef unsigned int uint;
|
|
+#endif
|
|
+
|
|
+#ifndef __OPTIMIZE__
|
|
+# warning This will not compile without -O at least
|
|
+#endif
|
|
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
|
|
+# ifndef inline
|
|
+# define inline __inline__
|
|
+# endif
|
|
+# ifndef restrict
|
|
+# define restrict __restrict__
|
|
+# endif
|
|
+# ifndef volatile
|
|
+# define volatile __volatile__
|
|
+# endif
|
|
+# ifndef asm
|
|
+# define asm __asm__
|
|
+# endif
|
|
+# ifndef extension
|
|
+# define extension __extension__
|
|
+# endif
|
|
+#endif
|
|
+#ifndef attribute
|
|
+# define attribute(attr) __attribute__(attr)
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * This is lent from the kernel by e.g. using
|
|
+ *
|
|
+ * echo '#include <asm-i386/processor.h>\nint main () { prefetch(); return 0; }' | \
|
|
+ * gcc -I/usr/src/linux/include -D__KERNEL__ -x c -E -P - | \
|
|
+ * sed -rn '/void[[:blank:]]+prefetch[[:blank:]]*\(/,/^}/p'
|
|
+ *
|
|
+ * on the appropiate architecture (here on i686 for i586).
|
|
+ */
|
|
+static inline void prefetch(const void *restrict x) attribute((used,always_inline));
|
|
+static inline void prefetch(const void *restrict x)
|
|
+{
|
|
+#if defined(__x86_64__)
|
|
+ asm volatile ("prefetcht0 %0" :: "m" (*(unsigned long *)x))
|
|
+#elif defined(__ia64__)
|
|
+ asm volatile ("lfetch [%0]" :: "r" (x))
|
|
+#elif defined(__powerpc64__)
|
|
+ asm volatile ("dcbt 0,%0" :: "r" (x))
|
|
+#elif 1 && defined(__i386__)
|
|
+ asm volatile ("661:\n\t"
|
|
+ ".byte 0x8d,0x74,0x26,0x00\n"
|
|
+ "\n662:\n"
|
|
+ ".section .altinstructions,\"a\"\n"
|
|
+ " .align 4\n"
|
|
+ " .long 661b\n"
|
|
+ " .long 663f\n"
|
|
+ " .byte %c0\n"
|
|
+ " .byte 662b-661b\n"
|
|
+ " .byte 664f-663f\n"
|
|
+ ".previous\n"
|
|
+ ".section .altinstr_replacement,\"ax\"\n"
|
|
+ " 663:\n\t"
|
|
+ " prefetchnta (%1)"
|
|
+ " \n664:\n"
|
|
+ ".previous"
|
|
+ :: "i" ((0*32+25)), "r" (x))
|
|
+#endif
|
|
+ ;
|
|
+}
|
|
+
|
|
+#if defined(DEBUG) && (DEBUG > 0)
|
|
+# define __align attribute((packed))
|
|
+#else
|
|
+# define __align attribute((aligned(sizeof(struct list_struct*))))
|
|
+#endif
|
|
+#define __packed attribute((packed))
|
|
+
|
|
+#define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
|
|
+#define strsize(string) ((strlen(string)+1)*sizeof(char))
|
|
+
|
|
+typedef struct list_struct {
|
|
+ struct list_struct * next, * prev;
|
|
+} __align list_t;
|
|
+
|
|
+/*
|
|
+ * Linked list handling
|
|
+ * ====================
|
|
+ * The structures which will be linked into such lists have to be of the
|
|
+ * same type. The structures may have alway a list identifier of the type
|
|
+ * `list_t' as very first element. With this the macro list_entry() can
|
|
+ * be used to cast the memory address of a list member to the corresponding
|
|
+ * allocated structure.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Insert new entry as next member.
|
|
+ */
|
|
+static inline void _insert(list_t *restrict new, list_t *restrict here) attribute((always_inline,nonnull(1,2)));
|
|
+static inline void _insert(list_t *restrict new, list_t *restrict here)
|
|
+{
|
|
+ list_t * prev = here;
|
|
+ list_t * next = here->next;
|
|
+
|
|
+ next->prev = new;
|
|
+ new->next = next;
|
|
+ new->prev = prev;
|
|
+ prev->next = new;
|
|
+}
|
|
+
|
|
+#define insert(new, list) _insert(&((new)->this), (&(list)));
|
|
+#define append(new, list) _insert(&((new)->this), (&(list))->prev);
|
|
+
|
|
+/*
|
|
+ * Set head
|
|
+ */
|
|
+static inline void initial(list_t *restrict head) attribute((always_inline,nonnull(1)));
|
|
+static inline void initial(list_t *restrict head)
|
|
+{
|
|
+ head->prev = head->next = head;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Remove entries, note that the pointer its self remains.
|
|
+ */
|
|
+static inline void delete(list_t *restrict entry) attribute((always_inline,nonnull(1)));
|
|
+static inline void delete(list_t *restrict entry)
|
|
+{
|
|
+ list_t * prev = entry->prev;
|
|
+ list_t * next = entry->next;
|
|
+
|
|
+ next->prev = prev;
|
|
+ prev->next = next;
|
|
+
|
|
+ initial(entry);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Replace an entry by a new one.
|
|
+ */
|
|
+static inline void replace(list_t *restrict old, list_t *restrict new) attribute((always_inline,nonnull(1,2)));
|
|
+static inline void replace(list_t *restrict old, list_t *restrict new)
|
|
+{
|
|
+ new->next = old->next;
|
|
+ new->next->prev = new;
|
|
+ new->prev = old->prev;
|
|
+ new->prev->next = new;
|
|
+}
|
|
+
|
|
+static inline void join(list_t *restrict list, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
|
|
+static inline void join(list_t *restrict list, list_t *restrict head)
|
|
+{
|
|
+ list_t * first = list->next;
|
|
+
|
|
+ if (first != list) {
|
|
+ list_t * last = list->prev;
|
|
+ list_t * at = head->next;
|
|
+
|
|
+ first->prev = head;
|
|
+ head->next = first;
|
|
+
|
|
+ last->next = at;
|
|
+ at->prev = last;
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline boolean list_empty(const list_t *restrict const head) attribute((always_inline,nonnull(1)));
|
|
+static inline boolean list_empty(const list_t *restrict const head)
|
|
+{
|
|
+ return head->next == head;
|
|
+}
|
|
+
|
|
+static inline void move_head(list_t *restrict entry, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
|
|
+static inline void move_head(list_t *restrict entry, list_t *restrict head)
|
|
+{
|
|
+ list_t * prev = entry->prev;
|
|
+ list_t * next = entry->next;
|
|
+
|
|
+ next->prev = prev; /* remove entry from old list */
|
|
+ prev->next = next;
|
|
+
|
|
+ prev = head;
|
|
+ next = head->next;
|
|
+
|
|
+ next->prev = entry; /* and add it at head of new list */
|
|
+ entry->next = next;
|
|
+ entry->prev = prev;
|
|
+ prev->next = entry;
|
|
+}
|
|
+
|
|
+static inline void move_tail(list_t *restrict entry, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
|
|
+static inline void move_tail(list_t *restrict entry, list_t *restrict head)
|
|
+{
|
|
+ list_t * prev = entry->prev;
|
|
+ list_t * next = entry->next;
|
|
+
|
|
+ next->prev = prev; /* remove entry from old list */
|
|
+ prev->next = next;
|
|
+
|
|
+ prev = head->prev;
|
|
+ next = head;
|
|
+
|
|
+ next->prev = entry; /* and add it at tail of new list */
|
|
+ entry->next = next;
|
|
+ entry->prev = prev;
|
|
+ prev->next = entry;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * The handle of the list is named `this'
|
|
+ */
|
|
+#define list_entry(ptr, type) (__extension__ ({ \
|
|
+ const typeof( ((type *)0)->this ) *__mptr = (ptr); \
|
|
+ ((type *)( (char *)(__mptr) - offsetof(type,this) )); }))
|
|
+#define list_for_each(pos, head) \
|
|
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)
|
|
+#define np_list_for_each(pos, head) \
|
|
+ for (pos = (head)->next; pos != (head); pos = pos->next)
|
|
+#define list_for_each_safe(pos, safe, head) \
|
|
+ for (pos = (head)->next, safe = pos->next; pos != (head); pos = safe, safe = pos->next)
|
|
+#define list_for_each_prev(pos, head) \
|
|
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); pos = pos->prev)
|
|
+#define np_list_for_each_prev(pos, head) \
|
|
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
|
|
+
|
|
+#endif /* _LISTS_H */
|
|
--- mkill.c
|
|
+++ mkill.c 2011-02-04 12:55:08.072990008 +0000
|
|
@@ -29,6 +29,7 @@
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include "libinit.h"
|
|
+#include "lists.h"
|
|
|
|
#ifndef MNT_FORCE
|
|
# define MNT_FORCE 0x00000001
|
|
@@ -62,33 +63,33 @@ extern inline DIR * opendirat(int dirfd,
|
|
|
|
typedef struct _s_shadow
|
|
{
|
|
- struct _s_shadow *next;
|
|
- struct _s_shadow *prev;
|
|
+ list_t this;
|
|
size_t nlen;
|
|
char * name;
|
|
} shadow_t;
|
|
|
|
typedef struct _s_mnt
|
|
{
|
|
- struct _s_mnt *next; /* Pointer to next struct. */
|
|
- struct _s_mnt *prev; /* Pointer to previous st. */
|
|
- shadow_t *shadow; /* Pointer to shadows */
|
|
- size_t nlen;
|
|
- char * name;
|
|
- int order; /* Order of the mount point*/
|
|
+ list_t this;
|
|
+ int order; /* Order of the mount point*/
|
|
+ int parent; /* Order of the parent mount point*/
|
|
+ shadow_t shadow; /* Pointer to shadows */
|
|
+ size_t nlen;
|
|
+ char * name;
|
|
} mntent_t;
|
|
|
|
typedef struct _s_proc_
|
|
{
|
|
- struct _s_proc_ *next; /* Pointer to next struct. */
|
|
- struct _s_proc_ *prev; /* Pointer to previous st. */
|
|
- pid_t pid; /* Process ID. */
|
|
- int order; /* Order of the mount point*/
|
|
+ list_t this;
|
|
+ pid_t pid; /* Process ID. */
|
|
+ int order; /* Order of the mount point*/
|
|
} proc_t;
|
|
|
|
static int maxorder = 1; /* This has to be initial 1 */
|
|
-static mntent_t * mntent;
|
|
-static proc_t * procs;
|
|
+
|
|
+static list_t mntent = {&mntent, &mntent};
|
|
+static list_t procs = {&procs, &procs};
|
|
+static list_t sort = {&sort, &sort};
|
|
|
|
static void init_mnt(int argc, char* argv[]);
|
|
static void clear_mnt(const boolean lazy);
|
|
@@ -101,7 +102,7 @@ int main(int argc, char* argv[])
|
|
const pid_t pid = getpid();
|
|
const pid_t sid = getsid(0);
|
|
const pid_t ppid = getppid();
|
|
- proc_t * this, *ptr, * last;
|
|
+ list_t * this, *ptr;
|
|
struct dirent * dent;
|
|
int dfd, num, nsig = SIGTERM;
|
|
boolean lazy = false;
|
|
@@ -306,22 +307,12 @@ int main(int argc, char* argv[])
|
|
|
|
if (found) {
|
|
if (isfuse) {
|
|
- this = procs;
|
|
- last = (proc_t*)0;
|
|
-
|
|
- for (ptr = procs; this; ptr = this) {
|
|
- last = ptr->prev;
|
|
- this = ptr->next;
|
|
- if (ptr->pid != curr)
|
|
+ list_for_each_safe(this, ptr, &procs) {
|
|
+ proc_t *p = list_entry(this, proc_t);
|
|
+ if (p->pid != curr)
|
|
continue;
|
|
- if (ptr == procs) {
|
|
- if (this) this->prev = (proc_t*)0;
|
|
- procs = this;
|
|
- } else if (last) {
|
|
- if (this) this->prev = last;
|
|
- last->next = this;
|
|
- }
|
|
- free(ptr);
|
|
+ delete(this);
|
|
+ free(p);
|
|
}
|
|
break;
|
|
}
|
|
@@ -343,16 +334,17 @@ int main(int argc, char* argv[])
|
|
|
|
num = 0;
|
|
found = false;
|
|
- for (ptr = procs; ptr; ptr = ptr->next) {
|
|
+ list_for_each(ptr, &procs) {
|
|
+ proc_t *p = list_entry(ptr, proc_t);
|
|
if (nsig) {
|
|
if (stop)
|
|
- kill(ptr->pid, SIGSTOP);
|
|
- kill(ptr->pid, nsig);
|
|
+ kill(p->pid, SIGSTOP);
|
|
+ kill(p->pid, nsig);
|
|
found = true;
|
|
} else {
|
|
if (num++ > 0)
|
|
putc(' ', stdout);
|
|
- printf("%d", ptr->pid);
|
|
+ printf("%d", p->pid);
|
|
}
|
|
}
|
|
if (stop)
|
|
@@ -376,25 +368,14 @@ int main(int argc, char* argv[])
|
|
usleep(10000);
|
|
num -= 10000;
|
|
|
|
- this = procs;
|
|
- last = (proc_t*)0;
|
|
found = false;
|
|
- for (ptr = procs; this; ptr = this) {
|
|
- last = ptr->prev;
|
|
- this = ptr->next;
|
|
-
|
|
- if (kill (ptr->pid, 0) < 0) {
|
|
- if (ptr == procs) {
|
|
- if (this) this->prev = (proc_t*)0;
|
|
- procs = this;
|
|
- } else if (last) {
|
|
- if (this) this->prev = last;
|
|
- last->next = this;
|
|
- }
|
|
+ list_for_each_safe(this, ptr, &procs) {
|
|
+ proc_t *p = list_entry(this, proc_t);
|
|
+ if (kill (p->pid, 0) < 0) {
|
|
+ delete(this);
|
|
free(ptr);
|
|
continue;
|
|
}
|
|
-
|
|
found = true;
|
|
}
|
|
}
|
|
@@ -402,9 +383,10 @@ int main(int argc, char* argv[])
|
|
if (!found)
|
|
goto out;
|
|
|
|
- for (ptr = procs; ptr; ptr = ptr->next) {
|
|
- kill(ptr->pid, SIGSTOP);
|
|
- kill(ptr->pid, SIGKILL);
|
|
+ list_for_each(ptr, &procs) {
|
|
+ proc_t *p = list_entry(ptr, proc_t);
|
|
+ kill(p->pid, SIGSTOP);
|
|
+ kill(p->pid, SIGKILL);
|
|
}
|
|
kill(-1, SIGCONT);
|
|
|
|
@@ -414,48 +396,109 @@ out:
|
|
|
|
static void init_mnt(int argc, char* argv[])
|
|
{
|
|
+ char buffer[LINE_MAX];
|
|
struct stat st;
|
|
- struct mntent * ent;
|
|
+ struct mntent ent;
|
|
FILE * mnt;
|
|
- int order;
|
|
+ int order = maxorder;
|
|
|
|
/* Stat /proc/version to see if /proc is mounted. */
|
|
if (stat("/proc/version", &st) < 0)
|
|
getproc();
|
|
|
|
+ /* Use /proc/self/mountinfo if available */
|
|
+ if ((mnt = fopen("/proc/self/mountinfo", "r"))) {
|
|
+ int mid, parid;
|
|
+
|
|
+ while (fscanf(mnt, "%i %i %*u:%*u %*s %s %*[^\n]", &mid, &parid, &buffer[0]) == 3) {
|
|
+ mntent_t *restrict ptr;
|
|
+ boolean found = false;
|
|
+ size_t nlen;
|
|
+ int num;
|
|
+
|
|
+ for (num = 0; num < argc; num++) {
|
|
+ if (*(argv[num]) == '\0')
|
|
+ continue;
|
|
+ if ((found = (strcmp(argv[num], buffer) == 0)))
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!found)
|
|
+ continue;
|
|
+ nlen = strlen(buffer);
|
|
+
|
|
+ if (posix_memalign((void*)&ptr, sizeof(void*), alignof(mntent_t)+(nlen+1)) != 0)
|
|
+ error(100, "malloc(): %s\n", strerror(errno));
|
|
+ append(ptr, mntent);
|
|
+ ptr->order = mid;
|
|
+ ptr->parent = parid;
|
|
+ ptr->name = ((char*)ptr)+alignof(mntent_t);
|
|
+ strcpy(ptr->name, buffer);
|
|
+ ptr->nlen = nlen;
|
|
+ initial(&ptr->shadow.this); /* not required as we sort below */
|
|
+ if (mid > order)
|
|
+ order = mid;
|
|
+ }
|
|
+ fclose(mnt);
|
|
+ maxorder = order;
|
|
+
|
|
+ /*
|
|
+ * Now sort into reverse mount order, with this we do not
|
|
+ * need any shadow mounts anymore.
|
|
+ */
|
|
+ initial(&sort);
|
|
+ for (mid = 1; mid <= maxorder; mid++) {
|
|
+ list_t *this, *cpy;
|
|
+ list_for_each_safe(this, cpy, &mntent) {
|
|
+ mntent_t * m = list_entry(this, mntent_t);
|
|
+ if (mid != m->order)
|
|
+ continue;
|
|
+ move_head(this, &sort);
|
|
+ break;
|
|
+ }
|
|
+ list_for_each_safe(this, cpy, &mntent) {
|
|
+ mntent_t * m = list_entry(this, mntent_t);
|
|
+ if (mid != m->parent)
|
|
+ continue;
|
|
+ move_head(this, &sort);
|
|
+ }
|
|
+ }
|
|
+ if (!list_empty(&mntent))
|
|
+ error(100, "init_mnt(): %s\n", strerror(EBADE));
|
|
+ join(&sort, &mntent);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+
|
|
if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
|
|
error(100, "cannot open /proc/mounts: %s\n", strerror(errno));
|
|
|
|
- order = maxorder;
|
|
- while ((ent = getmntent(mnt))) {
|
|
- const size_t nlen = strlen(ent->mnt_dir);
|
|
+ while (getmntent_r(mnt, &ent, buffer, sizeof(buffer))) {
|
|
mntent_t *restrict ptr;
|
|
boolean found = false;
|
|
+ size_t nlen;
|
|
int num;
|
|
|
|
for (num = 0; num < argc; num++) {
|
|
if (*(argv[num]) == '\0')
|
|
continue;
|
|
- if ((found = (strcmp(argv[num], ent->mnt_dir) == 0)))
|
|
+ if ((found = (strcmp(argv[num], ent.mnt_dir) == 0)))
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
continue;
|
|
+ nlen = strlen(ent.mnt_dir);
|
|
|
|
if (posix_memalign((void*)&ptr, sizeof(void*), alignof(mntent_t)+(nlen+1)) != 0)
|
|
error(100, "malloc(): %s\n", strerror(errno));
|
|
+ append(ptr, mntent);
|
|
ptr->order = order++;
|
|
+ ptr->parent = -1;
|
|
ptr->name = ((char*)ptr)+alignof(mntent_t);
|
|
- ptr->shadow = (shadow_t*)0;
|
|
-
|
|
- strcpy(ptr->name, ent->mnt_dir);
|
|
+ strcpy(ptr->name, ent.mnt_dir);
|
|
ptr->nlen = nlen;
|
|
- if (mntent)
|
|
- mntent->prev = ptr;
|
|
- ptr->next = mntent;
|
|
- ptr->prev = (mntent_t*)0;
|
|
- mntent = ptr;
|
|
+ initial(&ptr->shadow.this);
|
|
}
|
|
endmntent(mnt);
|
|
maxorder = order;
|
|
@@ -463,134 +506,99 @@ static void init_mnt(int argc, char* arg
|
|
if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0)
|
|
error(100, "cannot open /proc/mounts: %s\n", strerror(errno));
|
|
|
|
- while ((ent = getmntent(mnt))) {
|
|
- mntent_t *p;
|
|
+ while (getmntent_r(mnt, &ent, buffer, sizeof(buffer))) {
|
|
+ list_t *ptr;
|
|
|
|
- for (p = mntent; p; p = p->next) {
|
|
+ list_for_each(ptr, &mntent) {
|
|
+ mntent_t *p = list_entry(ptr, mntent_t);
|
|
shadow_t *restrict s;
|
|
size_t nlen;
|
|
|
|
- if (strcmp(ent->mnt_dir, p->name) == 0)
|
|
+ if (strcmp(ent.mnt_dir, p->name) == 0)
|
|
continue;
|
|
- if (strncmp(ent->mnt_dir, p->name, p->nlen) != 0)
|
|
+ if (strncmp(ent.mnt_dir, p->name, p->nlen) != 0)
|
|
continue;
|
|
|
|
- nlen = strlen(ent->mnt_dir);
|
|
+ nlen = strlen(ent.mnt_dir);
|
|
if (posix_memalign((void*)&s, sizeof(void*), alignof(shadow_t)+(nlen+1)) != 0)
|
|
error(100, "malloc(): %s\n", strerror(errno));
|
|
+ append(s, p->shadow.this);
|
|
s->name = ((char*)s)+alignof(shadow_t);
|
|
-
|
|
- strcpy(s->name, ent->mnt_dir);
|
|
+ strcpy(s->name, ent.mnt_dir);
|
|
s->nlen = nlen;
|
|
- if (p->shadow)
|
|
- p->shadow->prev = s;
|
|
- s->next = p->shadow;
|
|
- s->prev = (shadow_t*)0;
|
|
- p->shadow = s;
|
|
}
|
|
}
|
|
endmntent(mnt);
|
|
}
|
|
|
|
-static void clear_shadow(shadow_t *restrict shadow)
|
|
+static void clear_shadow(list_t *restrict shadow, const boolean lazy)
|
|
{
|
|
- shadow_t *s, *n, *l;
|
|
-
|
|
- n = shadow;
|
|
- l = (shadow_t*)0;
|
|
- for (s = shadow; n; s = n) {
|
|
- l = s->prev;
|
|
- n = s->next;
|
|
- if (s == shadow) {
|
|
- if (n) n->prev = (shadow_t*)0;
|
|
- shadow = n;
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- }
|
|
+ list_t *this, *ptr;
|
|
+ list_for_each_safe(this, ptr, shadow) {
|
|
+ shadow_t *s = list_entry(this, shadow_t);
|
|
+ delete(this);
|
|
+ if (lazy)
|
|
+ umount2(s->name, MNT_DETACH);
|
|
free(s);
|
|
}
|
|
}
|
|
|
|
static void clear_mnt(const boolean lazy)
|
|
{
|
|
- mntent_t *p, *n, *l;
|
|
+ list_t *this, *ptr;
|
|
|
|
- n = mntent;
|
|
- l = (mntent_t*)0;
|
|
- for (p = mntent; n; p = n) {
|
|
- l = p->prev;
|
|
- n = p->next;
|
|
+ list_for_each_safe(this, ptr, &mntent) {
|
|
+ mntent_t *p = list_entry(this, mntent_t);
|
|
+ delete(this);
|
|
+ if (!list_empty(&p->shadow.this)) {
|
|
+ clear_shadow(&p->shadow.this, lazy);
|
|
+ }
|
|
if (lazy)
|
|
umount2(p->name, MNT_DETACH);
|
|
- if (p == mntent) {
|
|
- if (n) n->prev = (mntent_t*)0;
|
|
- mntent = n;
|
|
- } else if (l) {
|
|
- if (n) n->prev = l;
|
|
- l->next = n;
|
|
- }
|
|
- if (p->shadow)
|
|
- clear_shadow(p->shadow);
|
|
free(p);
|
|
}
|
|
}
|
|
|
|
static void add_proc(pid_t pid, int order)
|
|
{
|
|
- proc_t * ptr = (proc_t*)xmalloc(sizeof(proc_t));
|
|
+ proc_t *restrict ptr;
|
|
+
|
|
+ if (posix_memalign((void*)&ptr, sizeof(void*), alignof(proc_t)) != 0)
|
|
+ error(100, "malloc(): %s\n", strerror(errno));
|
|
+ append(ptr, procs);
|
|
ptr->pid = pid;
|
|
ptr->order = order;
|
|
- if (procs)
|
|
- procs->prev = ptr;
|
|
- ptr->next = procs;
|
|
- ptr->prev = (proc_t*)0;
|
|
- procs = ptr;
|
|
}
|
|
|
|
static void sort_proc(void)
|
|
{
|
|
- proc_t * sort = (proc_t*)0;
|
|
int order;
|
|
|
|
+ initial(&sort);
|
|
for (order = maxorder; order > 0; order--) {
|
|
- proc_t * this = procs;
|
|
- proc_t * last = (proc_t*)0;
|
|
- proc_t * ptr;
|
|
-
|
|
- for (ptr = procs; this; ptr = this) {
|
|
- last = ptr->prev;
|
|
- this = ptr->next;
|
|
+ list_t *this, *ptr;
|
|
|
|
- if (ptr->order != order)
|
|
- continue;
|
|
+ list_for_each_safe(this, ptr, &procs) {
|
|
+ proc_t *p = list_entry(this, proc_t);
|
|
|
|
- if (ptr == procs) {
|
|
- if (this) this->prev = (proc_t*)0;
|
|
- procs = this;
|
|
- } else if (last) {
|
|
- if (this) this->prev = last;
|
|
- last->next = this;
|
|
- }
|
|
+ if (p->order != order)
|
|
+ continue;
|
|
|
|
- if (sort)
|
|
- sort->prev = ptr;
|
|
- ptr->next = sort;
|
|
- ptr->prev = (proc_t*)0;
|
|
- sort = ptr;
|
|
+ move_tail(this, &sort);
|
|
}
|
|
}
|
|
-
|
|
- procs = sort;
|
|
+ join(&sort, &procs);
|
|
}
|
|
|
|
-static boolean shadow(shadow_t *restrict this, const char *restrict name, const size_t nlen)
|
|
+static boolean shadow(list_t *restrict shadow, const char *restrict name, const size_t nlen)
|
|
{
|
|
- shadow_t *s;
|
|
+ list_t *ptr;
|
|
|
|
- if (!this)
|
|
+ if (!shadow || list_empty(shadow))
|
|
goto out;
|
|
- for (s = this; s; s = s->next) {
|
|
+
|
|
+ list_for_each(ptr, shadow) {
|
|
+ shadow_t *s = list_entry(ptr, shadow_t);
|
|
if (nlen < s->nlen)
|
|
continue;
|
|
if (name[s->nlen] != '\0' && name[s->nlen] != '/')
|
|
@@ -605,15 +613,16 @@ out:
|
|
static int check(const char *restrict name)
|
|
{
|
|
const size_t nlen = strlen(name);
|
|
- mntent_t *p;
|
|
+ list_t *ptr;
|
|
|
|
- for (p = mntent; p; p = p->next) {
|
|
+ list_for_each(ptr, &mntent) {
|
|
+ mntent_t *p = list_entry(ptr, mntent_t);
|
|
if (nlen < p->nlen)
|
|
continue;
|
|
if (name[p->nlen] != '\0' && name[p->nlen] != '/')
|
|
continue;
|
|
if (strncmp(name, p->name, p->nlen) == 0) {
|
|
- if (shadow(p->shadow, name, nlen))
|
|
+ if (shadow(&p->shadow.this, name, nlen))
|
|
continue;
|
|
return p->order;
|
|
}
|
|
--- rvmtab.8
|
|
+++ rvmtab.8 2011-02-03 08:22:08.192425628 +0000
|
|
@@ -0,0 +1,62 @@
|
|
+.\"
|
|
+.\" Copyright 2011 Werner Fink, 2008 SUSE LINUX Products GmbH, Germany.
|
|
+.\"
|
|
+.\" This program is free software; you can redistribute it and/or modify
|
|
+.\" it under the terms of the GNU General Public License as published by
|
|
+.\" the Free Software Foundation; either version 2 of the License, or
|
|
+.\" (at your option) any later version.
|
|
+.\"
|
|
+.TH RVMTAB 8 "Feb 01, 2011" "Version 0.1" "The SuSE boot concept"
|
|
+.UC 8
|
|
+.SH RVMTAB
|
|
+Rvmtab \- Sort \fI/proc/mounts\fR in the order of \fI/proc/self/mountinfo\fR
|
|
+.\"
|
|
+.SH SYNOPSIS
|
|
+.\"
|
|
+.B rvmtab
|
|
+.\"
|
|
+.SH DESCRIPTION
|
|
+.B rvmtab
|
|
+will list out the content of
|
|
+.I /proc/mounts
|
|
+sorted first of all in the reverse order of the parent IDs found in
|
|
+.I /proc/self/mountinfo
|
|
+and then in a second sub sort in the reverse order of mount IDs
|
|
+also found in
|
|
+.IR /proc/self/mountinfo .
|
|
+.\"
|
|
+.SH OPTIONS
|
|
+Currently
|
|
+.B rvmtab
|
|
+does not know about any option.
|
|
+\."
|
|
+.SH EXAMPLES
|
|
+.nf
|
|
+.B rvmtab
|
|
+.fi
|
|
+\."
|
|
+.SH RETURN VALUE
|
|
+Beside permsissions and and alloc errors
|
|
+.B rvmtab
|
|
+always returns success.
|
|
+\."
|
|
+.SH FILES
|
|
+.TP
|
|
+.I /proc/
|
|
+path to the proc file system
|
|
+.RB (see " proc" (5)).
|
|
+.TP
|
|
+.I /proc/mounts
|
|
+this file contains of a list of all the file systems currently mounted.
|
|
+.TP
|
|
+.I /proc/self/mountinfo
|
|
+this file contains information about mount points like the unique mount ID.
|
|
+\."
|
|
+.SH SEE ALSO
|
|
+.BR proc (5),
|
|
+\."
|
|
+.SH COPYRIGHT
|
|
+2011 Werner Fink,
|
|
+2011 SUSE LINUX Products GmbH, Germany.
|
|
+.SH AUTHOR
|
|
+Werner Fink <werner@suse.de>
|
|
--- rvmtab.c
|
|
+++ rvmtab.c 2011-02-04 11:51:12.214987615 +0000
|
|
@@ -0,0 +1,172 @@
|
|
+/*
|
|
+ * rvmtab.c Sort /proc/mounts or /etc/mtab in the sorting order of
|
|
+ * /proc/self/mountinfo usable for sequential umount calls
|
|
+ *
|
|
+ * Version: 0.1 01-Feb-2011 Fink
|
|
+ *
|
|
+ * Copyright 2011 Werner Fink, 2005 SUSE LINUX Products GmbH, Germany.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * Author: Werner Fink <werner@suse.de>, 2011
|
|
+ */
|
|
+
|
|
+#ifndef _GNU_SOURCE
|
|
+# define _GNU_SOURCE
|
|
+#endif
|
|
+#include <errno.h>
|
|
+#include <limits.h>
|
|
+#include <mntent.h>
|
|
+#include <stddef.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <unistd.h>
|
|
+#include "libinit.h"
|
|
+#include "lists.h"
|
|
+
|
|
+typedef struct mounts_s {
|
|
+ list_t this;
|
|
+ int freq;
|
|
+ int passno;
|
|
+ size_t nlen;
|
|
+ char *device;
|
|
+ char *mpoint;
|
|
+ char *fstype;
|
|
+ char *mntopt;
|
|
+} mounts_t;
|
|
+
|
|
+typedef struct mntinfo_s {
|
|
+ list_t this;
|
|
+ int id, parid;
|
|
+ dev_t dev;
|
|
+ char *mpoint;
|
|
+} mntinfo_t;
|
|
+
|
|
+static list_t mounts = {&mounts, &mounts};
|
|
+static list_t mntinfo = {&mntinfo, &mntinfo};
|
|
+static list_t save = {&save, &save};
|
|
+
|
|
+int main ()
|
|
+{
|
|
+ list_t *ptr;
|
|
+ FILE *minfo, *mtab;
|
|
+ struct mntent ent;
|
|
+ struct stat st;
|
|
+ char buffer[LINE_MAX];
|
|
+ int mid, max, parid;
|
|
+ uint maj, min;
|
|
+
|
|
+ /* Stat /proc/version to see if /proc is mounted. */
|
|
+ if (stat("/proc/version", &st) < 0)
|
|
+ getproc();
|
|
+
|
|
+ mtab = setmntent("/proc/mounts", "r");
|
|
+ if (!mtab) {
|
|
+ mtab = setmntent("/etc/mtab", "r");
|
|
+ if (!mtab)
|
|
+ goto err;
|
|
+ }
|
|
+ while (getmntent_r(mtab, &ent, buffer, sizeof(buffer))) {
|
|
+ mounts_t *restrict p;
|
|
+ size_t l1, l2, l3, l4;
|
|
+
|
|
+ l1 = strlen(ent.mnt_fsname);
|
|
+ l2 = strlen(ent.mnt_dir);
|
|
+ l3 = strlen(ent.mnt_type);
|
|
+ l4 = strlen(ent.mnt_opts);
|
|
+
|
|
+ if (posix_memalign((void*)&p, sizeof(void*), alignof(mounts_t)+(l1+l2+l3+l4+4)) != 0)
|
|
+ goto err;
|
|
+ append(p, mounts);
|
|
+ p->freq = ent.mnt_freq;
|
|
+ p->passno = ent.mnt_passno;
|
|
+ p->nlen = l2;
|
|
+
|
|
+ p->device = ((char*)p)+alignof(mounts_t);
|
|
+ p->mpoint = p->device+l1+1;
|
|
+ p->fstype = p->mpoint+l2+1;
|
|
+ p->mntopt = p->fstype+l3+1;
|
|
+
|
|
+ strcpy(p->device, ent.mnt_fsname);
|
|
+ strcpy(p->mpoint, ent.mnt_dir);
|
|
+ strcpy(p->fstype, ent.mnt_type);
|
|
+ strcpy(p->mntopt, ent.mnt_opts);
|
|
+ }
|
|
+ endmntent(mtab);
|
|
+
|
|
+ minfo = fopen("/proc/self/mountinfo", "r");
|
|
+ if (!minfo)
|
|
+ goto err;
|
|
+ max = 1;
|
|
+ while (fscanf(minfo, "%i %i %u:%u %*s %s %*[^\n]", &mid, &parid, &maj, &min, &buffer[0]) == 5) {
|
|
+ mntinfo_t *restrict p;
|
|
+
|
|
+ if (posix_memalign((void*)&p, sizeof(void*), alignof(mntinfo_t)+(strlen(buffer)+1)) != 0)
|
|
+ goto err;
|
|
+ append(p, mntinfo);
|
|
+ p->mpoint = ((char*)p)+alignof(mntinfo_t);
|
|
+ strcpy(p->mpoint, buffer);
|
|
+ p->parid = parid;
|
|
+ p->dev = makedev(maj, min);
|
|
+ p->id = mid;
|
|
+ if (mid > max)
|
|
+ max = mid;
|
|
+ }
|
|
+ fclose(minfo);
|
|
+
|
|
+ initial(&save);
|
|
+ for (mid = 1; mid <= max; mid++) {
|
|
+ list_t *this, *cpy;
|
|
+ list_for_each_safe(this, cpy, &mntinfo) {
|
|
+ mntinfo_t * m = list_entry(this, mntinfo_t);
|
|
+ if (mid != m->id)
|
|
+ continue;
|
|
+ move_head(this, &save);
|
|
+ break;
|
|
+ }
|
|
+ list_for_each_safe(this, cpy, &mntinfo) {
|
|
+ mntinfo_t * m = list_entry(this, mntinfo_t);
|
|
+ if (mid != m->parid)
|
|
+ continue;
|
|
+ move_head(this, &save);
|
|
+ }
|
|
+ }
|
|
+ if (!list_empty(&mntinfo)) {
|
|
+ errno = EBADE;
|
|
+ goto err;
|
|
+ }
|
|
+ join(&save, &mntinfo);
|
|
+
|
|
+#if 0
|
|
+ list_for_each(ptr, &mntinfo) {
|
|
+ mntinfo_t *m = list_entry(ptr, mntinfo_t);
|
|
+ printf("%d %d 0x%3.3x %s\n", m->id, m->parid, (uint)m->dev, m->mpoint);
|
|
+ }
|
|
+ putchar('\n');
|
|
+#endif
|
|
+ list_for_each(ptr, &mntinfo) {
|
|
+ mntinfo_t *m = list_entry(ptr, mntinfo_t);
|
|
+ list_t *tmp;
|
|
+ list_for_each(tmp, &mounts) {
|
|
+ mounts_t *p = list_entry(tmp, mounts_t);
|
|
+ if (!p->mpoint || !p->device)
|
|
+ continue;
|
|
+ if (strcmp("rootfs", p->device) == 0)
|
|
+ continue;
|
|
+ if (strcmp(m->mpoint, p->mpoint))
|
|
+ continue;
|
|
+ printf("%s %s %s %s %d %d\n", p->device, p->mpoint, p->fstype,
|
|
+ p->mntopt, p->freq, p->passno);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+err:
|
|
+ fprintf(stderr, "rvmtab: %s\n", strerror(errno));
|
|
+ return 1;
|
|
+}
|
|
--- startproc.c
|
|
+++ startproc.c 2011-02-04 14:01:24.935925784 +0000
|
|
@@ -51,7 +51,7 @@ static int wpopts = WNOHANG|WUNTRACED;
|
|
static char *wlist = NULL;
|
|
|
|
static volatile sig_atomic_t signaled = 0;
|
|
-static void (*save_sigquit) = SIG_DFL;
|
|
+static sighandler_t save_sigquit = SIG_DFL;
|
|
static void sig_quit(int nsig)
|
|
{
|
|
(void)signal(nsig, save_sigquit);
|
|
@@ -71,7 +71,8 @@ int main(int argc, char **argv)
|
|
struct stat st;
|
|
char *fullname = NULL, *basename = NULL;
|
|
char *log_file = NULL, *pid_file = NULL, *ignore_file = NULL;
|
|
- char *root = NULL, *iargv[argc];
|
|
+ char *root = NULL;
|
|
+ extension char *iargv[argc];
|
|
int c, nicelvl = 0, env = 0, iargc = 0;
|
|
unsigned short flags = (DAEMON|PIDOF);
|
|
|
|
@@ -345,7 +346,7 @@ int main(int argc, char **argv)
|
|
clear_pids(); /* Remove all pids which should be ignored */
|
|
|
|
/* Do main work */
|
|
- if (!remember) { /* No process found with pid file */
|
|
+ if (list_empty(&remember)) { /* No process found with pid file */
|
|
if (force)
|
|
goto force;
|
|
if (pidof(fullname,root,flags) < 0)
|
|
@@ -353,7 +354,7 @@ int main(int argc, char **argv)
|
|
clear_pids(); /* Remove all pids which should be ignored */
|
|
}
|
|
|
|
- if (remember)
|
|
+ if (!list_empty(&remember))
|
|
exit(LSB_OK); /* Accordingly to LSB we have succeed. */
|
|
|
|
force:
|
|
@@ -369,7 +370,7 @@ check_again:
|
|
exit(LSB_PROOFX);
|
|
clear_pids(); /* Remove all pids which should be ignored */
|
|
|
|
- if (!remember)
|
|
+ if (list_empty(&remember))
|
|
exit(LSB_NOPROC);
|
|
|
|
if (seconds > 0) {
|
|
@@ -378,8 +379,16 @@ check_again:
|
|
goto check_again;
|
|
}
|
|
|
|
- if (!quiet)
|
|
- printf("%d\n", remember->pid);
|
|
+ if (!quiet) {
|
|
+ list_t *list;
|
|
+ int nl = 0;
|
|
+ list_for_each(list, &remember) {
|
|
+ PROC *proc = list_entry(list, PROC);
|
|
+ if (nl++) putchar(' ');
|
|
+ printf("%ld", (long int)proc->pid);
|
|
+ }
|
|
+ if (nl) putchar('\n');
|
|
+ }
|
|
|
|
exit(LSB_OK);
|
|
|