summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCraig Small <csmall@users.sourceforge.net>2012-07-28 19:00:56 +1000
committerCraig Small <csmall@users.sourceforge.net>2012-07-28 19:00:56 +1000
commit2d7933d23257becad992f86c95fc22c7862e7d35 (patch)
treeb385f04ca0ef5ce5336b0ad26df3474f18382653 /src
parent09362d5554e1c6e523dd02d1a6863242dd0ba6e6 (diff)
parent7afa9fa7eb16cc5f53e38bda80e475985a372b6b (diff)
Merge branch 'master' of ssh://psmisc.git.sourceforge.net/gitroot/psmisc/psmisc
Conflicts: doc/killall.1 doc/pstree.1
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/fuser.c19
-rw-r--r--src/fuser.h2
-rw-r--r--src/killall.c85
-rw-r--r--src/lists.h2
-rw-r--r--src/pstree.c124
-rw-r--r--src/timeout.c267
-rw-r--r--src/timeout.h36
8 files changed, 415 insertions, 125 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1d400b5..9d6f777 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -27,6 +27,9 @@ if WANT_PEEKFD_MIPS
endif
fuser_SOURCES = fuser.c comm.h signals.c signals.h i18n.h fuser.h lists.h
+if WANT_TIMEOUT_STAT
+ fuser_SOURCES += timeout.c timeout.h
+endif
fuser_LDADD = @LIBINTL@
@@ -54,7 +57,7 @@ signames.h: signames.c Makefile
export LC_ALL=C ; \
@CPP@ -dM $< |\
tr -s '\t ' ' ' | sort -n -k 3 | sed \
- 's:#define SIG\([A-Z]\+[0-9]*\) \([0-9]\+\) *\(\|/\*.*\)$$:{\ \2,"\1" },:p;d' | \
+ 's:#define SIG\([A-Z][A-Z]*[0-9]*\) \([0-9][0-9]*\).*$\:{\ \2,"\1" },:p;d' | \
grep -v '[0-9][0-9][0-9]' >signames.h || \
{ rm -f signames.h; exit 1; }
grep '^{ 1,"HUP" },$$' signames.h >/dev/null || \
diff --git a/src/fuser.c b/src/fuser.c
index 2d70b46..e29a345 100644
--- a/src/fuser.c
+++ b/src/fuser.c
@@ -111,9 +111,13 @@ static dev_t device(const char *path);
#endif
static char *expandpath(const char *path);
-typedef int (*stat_t)(const char*, struct stat*);
#ifdef WITH_TIMEOUT_STAT
+# if (WITH_TIMEOUT_STAT == 2)
+# include "timeout.h"
+# else
+typedef int (*stat_t)(const char*, struct stat*);
static int timeout(stat_t func, const char *path, struct stat *buf, unsigned int seconds);
+# endif
#else
#define timeout(func,path,buf,dummy) (func)((path),(buf))
#endif /* WITH_TIMEOUT_STAT */
@@ -125,7 +129,7 @@ static void usage(const char *errormsg)
fprintf(stderr,
_
- ("Usage: fuser [-fMuv] [-a|-s] [-4|-6] [-c|-m|-n SPACE] [-k [-i] [-SIGNAL]] NAME...\n"
+ ("Usage: fuser [-fMuvw] [-a|-s] [-4|-6] [-c|-m|-n SPACE] [-k [-i] [-SIGNAL]] NAME...\n"
" fuser -l\n" " fuser -V\n"
"Show which processes use the named files, sockets, or filesystems.\n\n"
" -a,--all display unused files too\n"
@@ -261,7 +265,7 @@ scan_procs(struct names *names_head, struct inode_list *ino_head,
if (root_stat) free(root_stat);
if (cwd_stat) free(cwd_stat);
if (exe_stat) free(exe_stat);
-#ifndef __linux__
+#if !defined (__linux__) && !defined (__CYGWIN__)
check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP,
sockets, netdev);
check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP,
@@ -928,7 +932,9 @@ int main(int argc, char *argv[])
#endif
netdev = find_net_dev();
+#ifndef __CYGWIN__ /* Cygwin doesn't support /proc/net/unix */
fill_unix_cache(&unixsockets);
+#endif
for (argc_cnt = 1; argc_cnt < argc; argc_cnt++) {
current_argv = argv[argc_cnt];
@@ -1371,7 +1377,7 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head,
st.st_ino = 0;
if ((thedev = device(filepath)) < 0)
#else
- if (!st.st_ino && timeout(stat, filepath, &st, 5) != 0)
+ if (timeout(stat, filepath, &st, 5) != 0)
#endif
{
if (errno != ENOENT) {
@@ -1379,6 +1385,9 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head,
filepath, strerror(errno));
}
} else {
+#ifndef _LISTS_H
+ thedev = st.st_dev;
+#endif
if (thedev == netdev) {
for (sock_tmp = sockets; sock_tmp != NULL;
sock_tmp = sock_tmp->next) {
@@ -1783,7 +1792,7 @@ scan_swaps(struct names *names_head, struct inode_list *ino_head,
* Execute stat(2) system call with timeout to avoid deadlock
* on network based file systems.
*/
-#ifdef WITH_TIMEOUT_STAT
+#if defined(WITH_TIMEOUT_STAT) && (WITH_TIMEOUT_STAT == 1)
static sigjmp_buf jenv;
diff --git a/src/fuser.h b/src/fuser.h
index 21eb720..242ce19 100644
--- a/src/fuser.h
+++ b/src/fuser.h
@@ -86,7 +86,7 @@ struct mount_list {
struct mount_list *next;
};
-#if defined (__GNUC__) && defined(__OPTIMIZE__)
+#if defined (__GNUC__) && defined(__OPTIMIZE__) && !defined (__CYGWIN__)
# include "lists.h"
typedef struct mntinfo_s {
list_t this;
diff --git a/src/killall.c b/src/killall.c
index 8145535..a26c458 100644
--- a/src/killall.c
+++ b/src/killall.c
@@ -2,7 +2,7 @@
* killall.c - kill processes by name or list PIDs
*
* Copyright (C) 1993-2002 Werner Almesberger
- * Copyright (C) 2002-2007 Craig Small
+ * Copyright (C) 2002-2012 Craig Small
*
* 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
@@ -80,11 +80,9 @@
#define ER_UNKWN -3
#define ER_OOFRA -4
-#define NOT_PIDOF_OPTION if (pidof) usage(NULL)
-
static int verbose = 0, exact = 0, interactive = 0, reg = 0,
quiet = 0, wait_until_dead = 0, process_group = 0,
- ignore_case = 0, pidof;
+ ignore_case = 0;
static long younger_than = 0, older_than = 0;
static int
@@ -130,7 +128,7 @@ uptime()
char buf[2048];
FILE* file;
if (!(file=fopen( PROC_BASE "/uptime", "r"))) {
- fprintf(stderr, "error opening uptime file\n");
+ fprintf(stderr, "killall: error opening uptime file\n");
exit(1);
}
savelocale = setlocale(LC_NUMERIC, NULL);
@@ -206,7 +204,7 @@ match_process_uid(pid_t pid, uid_t uid)
fclose(f);
if (re==-1)
{
- fprintf(stderr, _("Cannot get UID from process status\n"));
+ fprintf(stderr, _("killall: Cannot get UID from process status\n"));
exit(1);
}
return re;
@@ -232,7 +230,7 @@ build_regexp_list(int names, char **namelist)
{
if (regcomp(&reglist[i], namelist[i], flag) != 0)
{
- fprintf(stderr, _("Bad regular expression: %s\n"), namelist[i]);
+ fprintf(stderr, _("killall: Bad regular expression: %s\n"), namelist[i]);
exit (1);
}
}
@@ -383,7 +381,7 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent)
continue;
}
process_age_sec = process_age(proc_stt_jf);
- assert(process_age_sec > 0);
+ assert(process_age_sec >= 0L);
}
(void) fclose (file);
@@ -443,8 +441,8 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent)
if (exact && !okay)
{
if (verbose)
- fprintf (stderr, _("skipping partial match %s(%d)\n"), comm,
- pid_table[i]);
+ fprintf (stderr, _("killall: skipping partial match %s(%d)\n"),
+ comm, pid_table[i]);
continue;
}
got_long = okay;
@@ -544,8 +542,8 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent)
pgids[i] = id;
if (id < 0)
{
- fprintf (stderr, "getpgid(%d): %s\n", pid_table[i],
- strerror (errno));
+ fprintf (stderr, "killall: getpgid(%d): %s\n",
+ pid_table[i], strerror (errno));
}
for (j = 0; j < i; j++)
if (pgids[j] == id)
@@ -555,14 +553,7 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent)
}
if (interactive && !ask (comm, id, signal))
continue;
- if (pidof)
- {
- if (found)
- putchar (' ');
- printf ("%d", id);
- found |= 1 << (found_name >= 0 ? found_name : 0);
- }
- else if (kill (process_group ? -id : id, signal) >= 0)
+ if (kill (process_group ? -id : id, signal) >= 0)
{
if (verbose)
fprintf (stderr, _("Killed %s(%s%d) with signal %d\n"), got_long ? command :
@@ -576,12 +567,10 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent)
fprintf (stderr, "%s(%d): %s\n", got_long ? command :
comm, id, strerror (errno));
}
- if (!quiet && !pidof)
+ if (!quiet)
for (i = 0; i < names; i++)
if (!(found & (1 << i)))
fprintf (stderr, _("%s: no process found\n"), namelist[i]);
- if (pidof)
- putchar ('\n');
if (names)
/* killall returns a zero return code if at least one process has
* been killed for each listed command. */
@@ -614,20 +603,7 @@ kill_all (int signal, int names, char **namelist, struct passwd *pwent)
static void
-usage_pidof (void)
-{
- fprintf (stderr, _(
- "Usage: pidof [ -eg ] NAME...\n"
- " pidof -V\n\n"
- " -e require exact match for very long names;\n"
- " skip if the command line is unavailable\n"
- " -g show process group ID instead of process ID\n"
- " -V display version information\n\n"));
-}
-
-
-static void
-usage_killall (const char *msg)
+usage (const char *msg)
{
if (msg != NULL)
fprintf(stderr, "%s\n", msg);
@@ -661,24 +637,15 @@ usage_killall (const char *msg)
" (must precede other arguments)\n"));
#endif /*WITH_SELINUX*/
fputc('\n', stderr);
+ exit(1);
}
-static void
-usage (const char *msg)
-{
- if (pidof)
- usage_pidof ();
- else
- usage_killall (msg);
- exit (1);
-}
-
void print_version()
{
- fprintf(stderr, "%s (PSmisc) %s\n", pidof ? "pidof" : "killall", VERSION);
+ fprintf(stderr, "killall (PSmisc) %s\n", VERSION);
fprintf(stderr, _(
- "Copyright (C) 1993-2005 Werner Almesberger and Craig Small\n\n"));
+ "Copyright (C) 1993-2012 Werner Almesberger and Craig Small\n\n"));
fprintf(stderr, _(
"PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
"This is free software, and you are welcome to redistribute it under\n"
@@ -748,7 +715,6 @@ main (int argc, char **argv)
name++;
else
name = *argv;
- pidof = strcmp (name, "killall");
sig_num = SIGTERM;
@@ -766,52 +732,43 @@ main (int argc, char **argv)
process_group = 1;
break;
case 'y':
- NOT_PIDOF_OPTION;
strncpy(yt, optarg, 16);
yt[15] = '\0';
if ( 0 >= (younger_than = parse_time_units(yt) ) )
usage(_("Invalid time format"));
break;
case 'o':
- NOT_PIDOF_OPTION;
strncpy(ot, optarg, 16);
ot[15] = '\0';
if ( 0 >= (older_than = parse_time_units(ot) ) )
usage(_("Invalid time format"));
break;
case 'i':
- NOT_PIDOF_OPTION;
interactive = 1;
break;
case 'l':
- NOT_PIDOF_OPTION;
list_signals();
return 0;
break;
case 'q':
- NOT_PIDOF_OPTION;
quiet = 1;
break;
case 'r':
- NOT_PIDOF_OPTION;
reg = 1;
break;
case 's':
sig_num = get_signal (optarg, "killall");
break;
case 'u':
- NOT_PIDOF_OPTION;
if (!(pwent = getpwnam(optarg))) {
fprintf (stderr, _("Cannot find user %s\n"), optarg);
exit (1);
}
break;
case 'v':
- NOT_PIDOF_OPTION;
verbose = 1;
break;
case 'w':
- NOT_PIDOF_OPTION;
wait_until_dead = 1;
break;
case 'I':
@@ -819,7 +776,6 @@ main (int argc, char **argv)
if (strcmp(argv[optind-1],"-I") == 0 || strncmp(argv[optind-1],"--",2) == 0) {
ignore_case = 1;
} else {
- NOT_PIDOF_OPTION;
sig_num = get_signal (argv[optind]+1, "killall");
}
break;
@@ -829,7 +785,6 @@ main (int argc, char **argv)
print_version();
return 0;
}
- NOT_PIDOF_OPTION;
sig_num = get_signal (argv[optind]+1, "killall");
break;
#ifdef WITH_SELINUX
@@ -868,12 +823,14 @@ main (int argc, char **argv)
#endif
usage(NULL);
- if (argc - myoptind > MAX_NAMES + 1) {
- fprintf (stderr, _("Maximum number of names is %d\n"), MAX_NAMES);
+ if (argc - myoptind > MAX_NAMES) {
+ fprintf (stderr, _("killall: Maximum number of names is %d\n"),
+ MAX_NAMES);
exit (1);
}
if (!have_proc_self_stat()) {
- fprintf (stderr, _("%s lacks process entries (not mounted ?)\n"), PROC_BASE);
+ fprintf (stderr, _("killall: %s lacks process entries (not mounted ?)\n"),
+ PROC_BASE);
exit (1);
}
argv = argv + myoptind;
diff --git a/src/lists.h b/src/lists.h
index 4ca8cb7..ae8929e 100644
--- a/src/lists.h
+++ b/src/lists.h
@@ -68,7 +68,7 @@ extern inline void attribute((used,__gnu_inline__,always_inline,__artificial__))
asm volatile ("lfetch [%0]" :: "r" (x))
#elif defined(__powerpc64__)
asm volatile ("dcbt 0,%0" :: "r" (x))
-#elif !defined(__CYGWIN__) && defined(__i386__)
+#elif !defined(__CYGWIN__) && !defined(__PIC__) && defined(__i386__)
asm volatile ("661:\n\t"
".byte 0x8d,0x74,0x26,0x00\n"
"\n662:\n"
diff --git a/src/pstree.c b/src/pstree.c
index 80cfcec..9d9e8d5 100644
--- a/src/pstree.c
+++ b/src/pstree.c
@@ -2,7 +2,7 @@
* pstree.c - display process tree
*
* Copyright (C) 1993-2002 Werner Almesberger
- * Copyright (C) 2002-2009 Craig Small
+ * Copyright (C) 2002-2012 Craig Small
*
* 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
@@ -73,6 +73,7 @@ typedef struct _proc {
char **argv; /* only used : argv[0] is 1st arg; undef if argc < 1 */
int argc; /* with -a : number of arguments, -1 if swapped */
pid_t pid;
+ pid_t pgid;
uid_t uid;
#ifdef WITH_SELINUX
security_context_t scontext;
@@ -122,7 +123,7 @@ static int capacity = 0;
static int *width = NULL;
static int *more = NULL;
-static int print_args = 0, compact = 1, user_change = 0, pids = 0,
+static int print_args = 0, compact = 1, user_change = 0, pids = 0, pgids = 0,
show_parents = 0, by_pid = 0, trunc = 1, wait_end = 0;
#ifdef WITH_SELINUX
static int show_scontext = 0;
@@ -265,7 +266,7 @@ static PROC *new_proc(const char *comm, pid_t pid, uid_t uid)
exit(1);
}
strncpy(new->comm, comm, COMM_LEN+2);
- new->comm[COMM_LEN+1]='\0'; /* make sure nul terminated*/
+ new->comm[COMM_LEN+1] = '\0'; /* make sure nul terminated*/
new->pid = pid;
new->uid = uid;
new->flags = 0;
@@ -295,8 +296,8 @@ static void add_child(PROC * parent, PROC * child)
if (by_pid) {
if ((*walk)->child->pid > child->pid)
break;
- } else if ((cmp = strcmp((*walk)->child->comm, child->comm)) > 0)
- break;
+ } else if ((cmp = strcmp((*walk)->child->comm, child->comm)) > 0) {
+ break; }
else if (!cmp && (*walk)->child->uid > child->uid)
break;
new->next = *walk;
@@ -334,13 +335,35 @@ static void set_args(PROC * this, const char *args, int size)
this->argv[i] = start = strchr(start, 0) + 1;
}
+static void
+rename_proc(PROC *this, const char *comm, uid_t uid)
+{
+ PROC *tmp_child, *parent;
+ CHILD **walk;
+
+ strncpy(this->comm, comm, COMM_LEN+2);
+ this->comm[COMM_LEN+1] = '\0';
+ this->uid = uid;
+
+ /* Re-sort children in parent, now we have a name */
+ if (!by_pid && this->parent) {
+ parent = this->parent;
+ for (walk = &parent->children; *walk; walk = &(*walk)->next) {
+ if ( ((*walk)->next != NULL) && strcmp((*walk)->child->comm, (*walk)->next->child->comm) > 0 ) {
+ tmp_child = (*walk)->child;
+ (*walk)->child = (*walk)->next->child;
+ (*walk)->next->child = tmp_child;
+ }
+ }
+ }
+}
#ifdef WITH_SELINUX
static void
-add_proc(const char *comm, pid_t pid, pid_t ppid, uid_t uid,
+add_proc(const char *comm, pid_t pid, pid_t ppid, pid_t pgid, uid_t uid,
const char *args, int size, char isthread, security_context_t scontext)
#else /*WITH_SELINUX */
static void
-add_proc(const char *comm, pid_t pid, pid_t ppid, uid_t uid,
+add_proc(const char *comm, pid_t pid, pid_t ppid, pid_t pgid, uid_t uid,
const char *args, int size, char isthread)
#endif /*WITH_SELINUX */
{
@@ -353,22 +376,36 @@ add_proc(const char *comm, pid_t pid, pid_t ppid, uid_t uid,
this = new_proc(comm, pid, uid);
#endif /*WITH_SELINUX */
else {
- strncpy(this->comm, comm, COMM_LEN+2);
- this->comm[COMM_LEN+1];
- this->uid = uid;
+ rename_proc(this, comm, uid);
}
if (args)
set_args(this, args, size);
if (pid == ppid)
ppid = 0;
+ this->pgid = pgid;
if (isthread)
this->flags |= PFLAG_THREAD;
- if (!(parent = find_proc(ppid)))
+ if (!(parent = find_proc(ppid))) {
#ifdef WITH_SELINUX
parent = new_proc("?", ppid, 0, scontext);
#else /*WITH_SELINUX */
parent = new_proc("?", ppid, 0);
#endif /*WITH_SELINUX */
+ /* When using kernel 3.3 with hidepid feature enabled on /proc
+ * then we need fake root pid */
+ if (!isthread && pid != 1) {
+ PROC *root;
+ if (!(root = find_proc(1))) {
+#ifdef WITH_SELINUX
+ root = new_proc("?", 1, 0, scontext);
+#else /*WITH_SELINUX */
+ root = new_proc("?", 1, 0);
+#endif
+ }
+ add_child(root, parent);
+ parent->parent = root;
+ }
+ }
add_child(parent, this);
this->parent = parent;
}
@@ -451,6 +488,10 @@ dump_tree(PROC * current, int level, int rep, int leaf, int last,
out_char(info++ ? ',' : '(');
(void) out_int(current->pid);
}
+ if (pgids) {
+ out_char(info++ ? ',' : '(');
+ (void) out_int(current->pgid);
+ }
if (user_change && prev_uid != current->uid) {
out_char(info++ ? ',' : '(');
if ((pw = getpwuid(current->uid)))
@@ -614,7 +655,7 @@ static void read_proc(void)
size_t buffer_size;
char readbuf[BUFSIZ + 1];
char *tmpptr;
- pid_t pid, ppid;
+ pid_t pid, ppid, pgid;
int fd, size;
int empty;
#ifdef WITH_SELINUX
@@ -669,7 +710,7 @@ static void read_proc(void)
/* We now have readbuf with pid and cmd, and tmpptr+2
* with the rest */
/*printf("tmpptr: %s\n", tmpptr+2); */
- if (sscanf(tmpptr + 2, "%*c %d", &ppid) == 1) {
+ if (sscanf(tmpptr + 2, "%*c %d %d", &ppid, &pgid) == 2) {
DIR *taskdir;
struct dirent *dt;
char *taskpath;
@@ -691,17 +732,17 @@ static void read_proc(void)
if (thread != pid) {
#ifdef WITH_SELINUX
if (print_args)
- add_proc(threadname, thread, pid, st.st_uid,
+ add_proc(threadname, thread, pid, pgid, st.st_uid,
threadname, strlen (threadname) + 1, 1,scontext);
else
- add_proc(threadname, thread, pid, st.st_uid,
+ add_proc(threadname, thread, pid, pgid, st.st_uid,
NULL, 0, 1, scontext);
#else /*WITH_SELINUX */
if (print_args)
- add_proc(threadname, thread, pid, st.st_uid,
+ add_proc(threadname, thread, pid, pgid, st.st_uid,
threadname, strlen (threadname) + 1, 1);
else
- add_proc(threadname, thread, pid, st.st_uid,
+ add_proc(threadname, thread, pid, pgid, st.st_uid,
NULL, 0, 1);
#endif /*WITH_SELINUX */
}
@@ -713,9 +754,9 @@ static void read_proc(void)
free(taskpath);
if (!print_args)
#ifdef WITH_SELINUX
- add_proc(comm, pid, ppid, st.st_uid, NULL, 0, 0, scontext);
+ add_proc(comm, pid, ppid, pgid, st.st_uid, NULL, 0, 0, scontext);
#else /*WITH_SELINUX */
- add_proc(comm, pid, ppid, st.st_uid, NULL, 0, 0);
+ add_proc(comm, pid, ppid, pgid, st.st_uid, NULL, 0, 0);
#endif /*WITH_SELINUX */
else {
sprintf(path, "%s/%d/cmdline", PROC_BASE, pid);
@@ -734,10 +775,10 @@ static void read_proc(void)
if (size)
buffer[size++] = 0;
#ifdef WITH_SELINUX
- add_proc(comm, pid, ppid, st.st_uid,
+ add_proc(comm, pid, ppid, pgid, st.st_uid,
buffer, size, 0, scontext);
#else /*WITH_SELINUX */
- add_proc(comm, pid, ppid, st.st_uid,
+ add_proc(comm, pid, ppid, pgid, st.st_uid,
buffer, size, 0);
#endif /*WITH_SELINUX */
}
@@ -757,40 +798,11 @@ static void read_proc(void)
}
}
-
-#if 0
-
-/* Could use output of ps achlx | awk '{ print $3,$4,$2,$13 }' */
-
-static void read_stdin(void)
-{
- char comm[PATH_MAX + 1];
- char *cmd;
- int pid, ppid, uid;
-
- while (scanf("%d %d %d %s\n", &pid, &ppid, &uid, comm) == 4) {
- if (cmd = strrchr(comm, '/'))
- cmd++;
- else
- cmd = comm;
- if (*cmd == '-')
- cmd++;
-#ifdef WITH_SELINUX
- add_proc(cmd, pid, ppid, uid, NULL, 0, NULL);
-#else /*WITH_SELINUX */
- add_proc(cmd, pid, ppid, uid, NULL, 0);
-#endif /*WITH_SELINUX */
- }
-}
-
-#endif
-
-
static void usage(void)
{
fprintf(stderr,
_
- ("Usage: pstree [ -a ] [ -c ] [ -h | -H PID ] [ -l ] [ -n ] [ -p ] [ -u ]\n"
+ ("Usage: pstree [ -a ] [ -c ] [ -h | -H PID ] [ -l ] [ -n ] [ -p ] [ -g ] [ -u ]\n"
" [ -A | -G | -U ] [ PID | USER ]\n"
" pstree -V\n" "Display a tree of processes.\n\n"
" -a, --arguments show command line arguments\n"
@@ -799,6 +811,7 @@ static void usage(void)
" -h, --highlight-all highlight current process and its ancestors\n"
" -H PID,\n"
" --highlight-pid=PID highlight this process and its ancestors\n"
+ " -g, --show-pgids show process group ids; implies -c\n"
" -G, --vt100 use VT100 line drawing characters\n"
" -l, --long don't truncate long lines\n"
" -n, --numeric-sort sort output by PID\n"
@@ -850,6 +863,7 @@ int main(int argc, char **argv)
{"long", 0, NULL, 'l'},
{"numeric-sort", 0, NULL, 'n'},
{"show-pids", 0, NULL, 'p'},
+ {"show-pgids", 0, NULL, 'g'},
{"show-parents", 0, NULL, 's'},
{"uid-changes", 0, NULL, 'u'},
{"unicode", 0, NULL, 'U'},
@@ -903,11 +917,11 @@ int main(int argc, char **argv)
#ifdef WITH_SELINUX
while ((c =
- getopt_long(argc, argv, "aAcGhH:nplsuUVZ", options,
+ getopt_long(argc, argv, "aAcGhH:npglsuUVZ", options,
NULL)) != -1)
#else /*WITH_SELINUX */
while ((c =
- getopt_long(argc, argv, "aAcGhH:nplsuUV", options, NULL)) != -1)
+ getopt_long(argc, argv, "aAcGhH:npglsuUV", options, NULL)) != -1)
#endif /*WITH_SELINUX */
switch (c) {
case 'a':
@@ -953,6 +967,10 @@ int main(int argc, char **argv)
pids = 1;
compact = 0;
break;
+ case 'g':
+ pgids = 1;
+ compact = 0;
+ break;
case 's':
show_parents = 1;
break;
diff --git a/src/timeout.c b/src/timeout.c
new file mode 100644
index 0000000..1fe0354
--- /dev/null
+++ b/src/timeout.c
@@ -0,0 +1,267 @@
+/*
+ * timout.c Advanced timeout handling for file system calls
+ * to avoid deadlocks on remote file shares.
+ *
+ * Version: 0.1 07-Sep-2011 Fink
+ *
+ * Copyright 2011 Werner Fink, 2011 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
+
+#ifndef USE_SOCKETPAIR
+# define USE_SOCKETPAIR 1
+#endif
+
+#ifdef _FEATURES_H
+# error Include local config.h before any system header file
+#endif
+#include "config.h" /* For _FILE_OFFSET_BITS */
+
+#include <errno.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#if USE_SOCKETPAIR
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# ifndef SHUT_RD
+# define SHUT_RD 0
+# endif
+# ifndef SHUT_WR
+# define SHUT_WR 1
+# endif
+# undef pipe
+# define pipe(v) (((socketpair(AF_UNIX,SOCK_STREAM,0,v) < 0) || \
+ (shutdown((v)[1],SHUT_RD) < 0) || (shutdown((v)[0],SHUT_WR) < 0)) ? -1 : 0)
+#endif
+#include <wait.h>
+
+#include "timeout.h"
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef destructor
+# define destructor __destructor__
+# endif
+# ifndef constructor
+# define constructor __constructor__
+# endif
+# ifndef packed
+# define packed __packed__
+# endif
+# ifndef inline
+# define inline __inline__
+# endif
+# ifndef unused
+# define unused __unused__
+# endif
+# ifndef volatile
+# define volatile __volatile__
+# endif
+#endif
+#ifndef attribute
+# define attribute(attr) __attribute__(attr)
+#endif
+
+#if defined __GNUC__
+# undef strcpy
+# define strcpy(d,s) __builtin_strcpy((d),(s)) /* Without boundary check please */
+#endif
+
+/*
+ * The structure used for communication between the processes
+ */
+typedef struct _handle {
+ int errcode;
+ struct stat argument;
+ stat_t function;
+ size_t len;
+ char path[0];
+} attribute((packed)) handle_t;
+
+/*
+ * Using a forked process for doing e.g. stat(2) system call as this
+ * allows us to send e.g. SIGKILL to this process if it hangs in `D'
+ * state on a file share due a stalled NFS server. This does not work
+ * with (p)threads as SIGKILL would kill all threads including main.
+ */
+
+static volatile pid_t active;
+static int pipes[4] = {-1, -1, -1, -1};
+static char buf[PATH_MAX + sizeof(handle_t) + 1];
+
+static void sigchild(int sig attribute((unused)))
+{
+ pid_t pid = waitpid(active, NULL, WNOHANG|WUNTRACED);
+ if (pid <= 0)
+ return;
+ if (errno == ECHILD)
+ return;
+ active = 0;
+}
+
+static void attribute((constructor)) start(void)
+{
+ sigset_t sigset, oldset;
+ struct sigaction act;
+ ssize_t in;
+
+ if (pipes[1] >= 0) close(pipes[1]);
+ if (pipes[2] >= 0) close(pipes[2]);
+
+ if (pipe(&pipes[0]))
+ goto error;
+ if (pipe(&pipes[2]))
+ goto error;
+
+ memset(&act, 0, sizeof(act));
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = sigchild;
+ sigaction(SIGCHLD, &act, 0);
+
+ if ((active = fork()) < 0)
+ goto error;
+
+ if (active) {
+ close(pipes[0]);
+ close(pipes[3]);
+ pipes[0] = pipes[3] = -1;
+ return;
+ }
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ sigprocmask(SIG_BLOCK, &sigset, &oldset);
+
+ act.sa_handler = SIG_DFL;
+ sigaction(SIGCHLD, &act, 0);
+
+ close(pipes[1]);
+ close(pipes[2]);
+ dup2(pipes[0], STDIN_FILENO);
+ dup2(pipes[3], STDOUT_FILENO);
+ close(pipes[0]);
+ close(pipes[3]);
+ pipes[1] = pipes[2] = -1;
+ pipes[0] = pipes[3] = -1;
+
+ {
+ handle_t *restrict handle = (void*)&buf[0];
+
+ while ((in = read(STDIN_FILENO, handle, sizeof(buf))) > sizeof(handle_t)) {
+ if (handle->function(handle->path, &handle->argument) < 0)
+ handle->errcode = errno;
+ write(STDOUT_FILENO, &handle->errcode, sizeof(handle->errcode)+sizeof(handle->argument));
+ memset(handle, 0, sizeof(handle_t));
+ }
+ }
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ exit(0);
+error:
+ if (pipes[0] >= 0) close(pipes[0]);
+ if (pipes[1] >= 0) close(pipes[1]);
+ if (pipes[2] >= 0) close(pipes[2]);
+ if (pipes[3] >= 0) close(pipes[3]);
+}
+
+static void /* attribute((destructor)) */ stop(void)
+{
+ if (active && waitpid(active, NULL, WNOHANG|WUNTRACED) == 0)
+ kill(active, SIGKILL);
+}
+
+static sigjmp_buf jenv;
+static void sigjump(int sig attribute((unused)))
+{
+ siglongjmp(jenv, 1);
+}
+
+/*
+ * External routine
+ */
+int timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds)
+{
+ handle_t *restrict handle = (void*)&buf[0];
+ struct sigaction alrm_act, pipe_act, new_act;
+ sigset_t sigset, oldset;
+
+ if (active <= 0) /* Oops, last one failed therefore clear status and restart */
+ start();
+
+ memset(handle, 0, sizeof(handle_t));
+ handle->len = strlen(path) + 1;
+ if (handle->len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ goto error;
+ }
+ handle->errcode = 0;
+ handle->argument = *argument;
+ handle->function = function;
+ strcpy(handle->path, path);
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ sigaddset(&sigset, SIGPIPE);
+ sigprocmask(SIG_UNBLOCK, &sigset, &oldset);
+
+ memset(&new_act, 0, sizeof(new_act));
+ sigemptyset(&new_act.sa_mask);
+ new_act.sa_flags = SA_RESETHAND;
+
+ if (sigsetjmp(jenv, 1))
+ goto timed;
+
+ new_act.sa_handler = sigjump;
+ sigaction(SIGALRM, &new_act, &alrm_act);
+ sigaction(SIGPIPE, &new_act, &pipe_act);
+ alarm(seconds);
+
+ write(pipes[1], handle, sizeof(handle_t)+handle->len);
+ read(pipes[2], &handle->errcode, sizeof(handle->errcode)+sizeof(handle->argument));
+
+ alarm(0);
+ sigaction(SIGPIPE, &pipe_act, NULL);
+ sigaction(SIGALRM, &alrm_act, NULL);
+
+ if (handle->errcode) {
+ errno = handle->errcode;
+ goto error;
+ }
+
+ *argument = handle->argument;
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+
+ return 0;
+timed:
+ (void) alarm(0);
+ sigaction(SIGPIPE, &pipe_act, NULL);
+ sigaction(SIGALRM, &alrm_act, NULL);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ stop();
+ errno = ETIMEDOUT;
+error:
+ return -1;
+}
+
+/*
+ * End of timeout.c
+ */
diff --git a/src/timeout.h b/src/timeout.h
new file mode 100644
index 0000000..546c13b
--- /dev/null
+++ b/src/timeout.h
@@ -0,0 +1,36 @@
+/*
+ * timout.h Advanced timeout handling for file system calls
+ * to avoid deadlocks on remote file shares.
+ *
+ * Version: 0.1 07-Sep-2011 Fink
+ *
+ * Copyright 2011 Werner Fink, 2011 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 _TIMEOUT_H
+#define _TIMEOUT_H
+
+#include "config.h" /* For _FILE_OFFSET_BITS */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <limits.h>
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef restrict
+# define restrict __restrict__
+# endif
+#endif
+
+typedef int (*stat_t)(const char *, struct stat *restrict);
+extern int timeout(stat_t, const char *, struct stat *restrict, time_t);
+
+#endif