--- 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 #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 and . + * + * 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 , 2011 + */ + +#ifndef _LISTS_H +#define _LISTS_H + +#include +#include + +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 \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 #include #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 --- 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 , 2011 + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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);