Hi, This came up on IRC yesterday - the idea is to know what running processes are using deleted files. For example if you remove python and an old python instance is still running, it will output:
$ ./pacman-g2 -P User : vmiklos PID : 9216 Command : python2.7 Files : /usr/bin/python2.7 (deleted) Michel, could you proof-read the patch, just in case you catch any typos? Others, do you like this feature? I didn't want to push this directly, in case it turns out it's only me who thinks this is cool to have. Thanks.
From 980faa23d1a80e42611cf25b0db6bee014ee55ef Mon Sep 17 00:00:00 2001 From: Miklos Vajna <[email protected]> Date: Mon, 9 May 2011 02:23:08 +0200 Subject: [PATCH] Let pacman-g2 -P display processes using deleted files Inspired by 'zypper ps'. --- doc/pacman-g2.txt | 3 + src/pacman-g2/Makefile.am | 2 +- src/pacman-g2/pacman-g2.c | 14 +++- src/pacman-g2/ps.c | 166 +++++++++++++++++++++++++++++++++++++++++++++ src/pacman-g2/ps.h | 35 ++++++++++ 5 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 src/pacman-g2/ps.c create mode 100644 src/pacman-g2/ps.h diff --git a/doc/pacman-g2.txt b/doc/pacman-g2.txt index 87ea8d6..66d47f3 100644 --- a/doc/pacman-g2.txt +++ b/doc/pacman-g2.txt @@ -49,6 +49,9 @@ pacman-g2 packages are in a bzipped tar format. HANDLING CONFIG FILES for an explanation on how pacman-g2 takes care of config files. +-P, --ps:: + Display processes using deleted files. + -V, --version:: Display version and exit. diff --git a/src/pacman-g2/Makefile.am b/src/pacman-g2/Makefile.am index aaf9c7e..a949e04 100644 --- a/src/pacman-g2/Makefile.am +++ b/src/pacman-g2/Makefile.am @@ -13,7 +13,7 @@ AM_CFLAGS = -D_GNU_SOURCE \ -I$(top_srcdir)/lib/libpacman pacman_g2_SOURCES = util.c log.c list.c package.c download.c trans.c add.c \ - remove.c upgrade.c query.c sync.c conf.c deptest.c pacman-g2.c + remove.c upgrade.c query.c sync.c ps.c conf.c deptest.c pacman-g2.c pacman_g2_static_SOURCES = $(pacman_g2_SOURCES) diff --git a/src/pacman-g2/pacman-g2.c b/src/pacman-g2/pacman-g2.c index 1e12616..c2634d6 100644 --- a/src/pacman-g2/pacman-g2.c +++ b/src/pacman-g2/pacman-g2.c @@ -56,6 +56,7 @@ #include "query.h" #include "sync.h" #include "deptest.h" +#include "ps.h" #define PACCONF "/etc/pacman-g2.conf" @@ -71,7 +72,8 @@ enum { PM_OP_UPGRADE, PM_OP_QUERY, PM_OP_SYNC, - PM_OP_DEPTEST + PM_OP_DEPTEST, + PM_OP_PS }; /* Long operations */ @@ -115,6 +117,7 @@ static void usage(int op, char *myname) printf(_(" %s {-F --freshen} [options] <file>\n"), myname); printf(_(" %s {-Q --query} [options] [package]\n"), myname); printf(_(" %s {-S --sync} [options] [package]\n"), myname); + printf(_(" %s {-P --ps} [options] [package]\n"), myname); printf(_("\nuse '%s --help' with other options for more syntax\n"), myname); } else { if(op == PM_OP_ADD) { @@ -261,6 +264,7 @@ static int parseargs(int argc, char *argv[]) {"query", no_argument, 0, 'Q'}, {"remove", no_argument, 0, 'R'}, {"sync", no_argument, 0, 'S'}, + {"ps", no_argument, 0, 'P'}, {"deptest", no_argument, 0, 'T'}, /* used by makepkg */ {"upgrade", no_argument, 0, 'U'}, {"version", no_argument, 0, 'V'}, @@ -306,7 +310,7 @@ static int parseargs(int argc, char *argv[]) }; char root[PATH_MAX]; - while((opt = getopt_long(argc, argv, "ARUFQSTDYr:b:vkhscVfmnoldepituwyg", opts, &option_index))) { + while((opt = getopt_long(argc, argv, "ARUFQSPTDYr:b:vkhscVfmnoldepituwyg", opts, &option_index))) { if(opt < 0) { break; } @@ -344,6 +348,7 @@ static int parseargs(int argc, char *argv[]) case 'Q': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; case 'R': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; case 'S': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; + case 'P': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_PS); break; case 'T': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); break; case 'U': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); break; case 'V': config->version = 1; break; @@ -503,7 +508,7 @@ int main(int argc, char *argv[]) /* check if we have sufficient permission for the requested operation */ if(myuid > 0) { - if(config->op != PM_OP_MAIN && config->op != PM_OP_QUERY && config->op != PM_OP_DEPTEST) { + if(config->op != PM_OP_MAIN && config->op != PM_OP_QUERY && config->op != PM_OP_DEPTEST && config->op != PM_OP_PS) { if((config->op == PM_OP_SYNC && !config->op_s_sync && (config->op_s_search || config->group || config->op_q_list || config->op_q_info || (config->flags & PM_TRANS_FLAG_PRINTURIS))) @@ -637,7 +642,7 @@ int main(int argc, char *argv[]) if(list_count(pm_targets) == 0 && !(config->op == PM_OP_QUERY || (config->op == PM_OP_SYNC && (config->op_s_sync || config->op_s_upgrade || config->op_s_clean || config->group - || config->op_q_list)))) { + || config->op_q_list)) || config->op == PM_OP_PS)) { ERR(NL, _("no targets specified (use -h for help)\n")); cleanup(1); } @@ -649,6 +654,7 @@ int main(int argc, char *argv[]) case PM_OP_UPGRADE: ret = upgradepkg(pm_targets); break; case PM_OP_QUERY: ret = querypkg(pm_targets); break; case PM_OP_SYNC: ret = syncpkg(pm_targets); break; + case PM_OP_PS: ret = pspkg(pm_targets); break; case PM_OP_DEPTEST: ret = deptestpkg(pm_targets); break; default: ERR(NL, _("no operation specified (use -h for help)\n")); diff --git a/src/pacman-g2/ps.c b/src/pacman-g2/ps.c new file mode 100644 index 0000000..f250b28 --- /dev/null +++ b/src/pacman-g2/ps.c @@ -0,0 +1,166 @@ +/* + * ps.c + * + * Copyright (c) 2011 by Miklos Vajna <[email protected]> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <libintl.h> +#include <sys/wait.h> + +/* pacman-g2 */ +#include "util.h" +#include "log.h" +#include "ps.h" + +static int start_lsof(FILE** childout, int* childpid) +{ + char *args[] = { "lsof", "-n", "-FLpcn0", NULL }; + int pout[2]; + pid_t pid; + + if (pipe(pout) == -1) { + perror("pipe"); + return -1; + } + pid = fork(); + if (pid == -1) { + perror("fork"); + return -1; + } + if (pid == 0) { + /* we are "in" the child */ + dup2(pout[1], STDOUT_FILENO); + close(pout[1]); + close(pout[0]); + execvp(args[0], args); + /* on sucess, execv never returns */ + ERR(NL, _("failed to execute \"lsof\".\n")); + return -1; + } + close(pout[1]); + *childout = fdopen(pout[0], "r"); + *childpid = pid; + return 0; +} + +static int end_lsof(FILE* out, int pid) +{ + int status; + + fclose(out); + waitpid(pid, &status, 0); + return status == 0 ? 0 : -1; +} + +static ps_t* ps_new() +{ + ps_t *ps; + + MALLOC(ps, sizeof(ps_t)); + + memset(ps, 0, sizeof(ps_t)); + + return ps; +} + +static int ps_free(ps_t *ps) +{ + if (ps == NULL) + return -1; + + FREE(ps->cmd); + FREE(ps->user); + FREELIST(ps->files); + return 0; +} + +static list_t* add_or_free(list_t* l, ps_t* ps) +{ + if (ps) { + if (list_count(ps->files) > 0) { + l = list_add(l, ps); + } else + ps_free(ps); + } + return l; +} + +list_t* ps_parse(FILE *fp) +{ + char buf[PATH_MAX+1], *ptr; + ps_t* ps = NULL; + list_t* ret = list_new(); + + while(!feof(fp)) { + if(fgets(buf, PATH_MAX, fp) == NULL) + break; + + if (buf[0] == 'p') { + ret = add_or_free(ret, ps); + ps = ps_new(); + + ps->pid = atoi(buf+1); + ptr = buf+strlen(buf)+1; + ps->cmd = strdup(ptr+1); + ptr = ptr + strlen(ptr)+1; + ps->user = strdup(ptr+1); + } else if (buf[0] == 'n') { + ptr = buf+1; + if (!strcmp(ptr + strlen(ptr) - 10, " (deleted)")) { + ps->files = list_add(ps->files, strdup(ptr)); + } + } + } + + ret = add_or_free(ret, ps); + return ret; +} + +int pspkg() +{ + FILE *fpout = NULL; + pid_t pid; + list_t* i; + + if (start_lsof(&fpout, &pid) < 0) + return -1; + + list_t* ret = ps_parse(fpout); + + for (i = ret; i; i = i->next) { + ps_t *ps = i->data; + printf( _("User : %s\n"), ps->user); + printf( _("PID : %d\n"), ps->pid); + printf( _("Command : %s\n"), ps->cmd); + list_display(_("Files :"), ps->files); + ps_free(ps); + printf("\n"); + } + FREELISTPTR(ret); + + end_lsof(fpout, pid); + + return 0; +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman-g2/ps.h b/src/pacman-g2/ps.h new file mode 100644 index 0000000..e6cda2d --- /dev/null +++ b/src/pacman-g2/ps.h @@ -0,0 +1,35 @@ +/* + * ps.h + * + * Copyright (c) 2011 by Miklos Vajna <[email protected]> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#ifndef _PM_PS_H +#define _PM_PS_H + +typedef struct __ps_t { + int pid; + char *cmd; + char *user; + list_t *files; +} ps_t; + +int pspkg(); + +#endif /* _PM_PS_H */ + +/* vim: set ts=2 sw=2 noet: */ -- 1.7.5.1
pgpjsLBoppTTC.pgp
Description: PGP signature
_______________________________________________ Frugalware-devel mailing list [email protected] http://frugalware.org/mailman/listinfo/frugalware-devel
