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

Attachment: pgpjsLBoppTTC.pgp
Description: PGP signature

_______________________________________________
Frugalware-devel mailing list
[email protected]
http://frugalware.org/mailman/listinfo/frugalware-devel

Reply via email to