libexplain  1.4.D001
libexplain/lsof.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 3 of the
00009  * License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/ctype.h>
00021 #include <libexplain/ac/limits.h> /* for PATH_MAX on Solaris */
00022 #include <libexplain/ac/stdio.h>
00023 #include <libexplain/ac/stdlib.h>
00024 #include <libexplain/ac/sys/param.h> /* for PATH_MAX except Solaris */
00025 
00026 #include <libexplain/lsof.h>
00027 #include <libexplain/option.h>
00028 
00029 
00030 void
00031 explain_lsof(const char *lsof_options, explain_lsof_t *context)
00032 {
00033     FILE            *fp;
00034     char            command[200];
00035 
00036     if (!lsof_options)
00037         lsof_options = "";
00038     snprintf
00039     (
00040         command,
00041         sizeof(command),
00042         "lsof -Ffnp0 %s %s %s",
00043         (lsof_options[0] ? "-a" : ""),
00044         lsof_options,
00045         (explain_option_debug() >= 2 ? "" : "2> /dev/null")
00046     );
00047     fp = popen(command, "r");
00048     if (!fp)
00049         return;
00050     context->pid = 0;
00051     context->fildes = -1;
00052     for (;;)
00053     {
00054         char            line[PATH_MAX + 2];
00055         char            *lp;
00056 
00057         lp = line;
00058         for (;;)
00059         {
00060             int             c;
00061 
00062             c = getc(fp);
00063             if (c == EOF)
00064             {
00065                 *lp++ = '\0';
00066                 break;
00067             }
00068             if (c == '\0')
00069             {
00070                 *lp++ = '\0';
00071                 /*
00072                  * The lsof(1) man page says that -F0 NUL terminates the
00073                  * lines, but it actually terminates them with "\0\n"
00074                  * instead, except when it uses just "\0".  Sheesh.
00075                  */
00076                 c = getc(fp);
00077                 if (c != EOF && c != '\n')
00078                     ungetc(c, fp);
00079                 break;
00080             }
00081             if (lp < line + sizeof(line) - 1)
00082                 *lp++ = c;
00083         }
00084         switch (line[0])
00085         {
00086         case '\0':
00087             pclose(fp);
00088             return;
00089 
00090         case 'p':
00091             context->pid = atoi(line + 1);
00092             context->fildes = -1;
00093             break;
00094 
00095         case 'f':
00096             context->fildes = atoi(line + 1);
00097             if (context->fildes == 0)
00098             {
00099                 if (isalpha((unsigned char)line[1]))
00100                     context->fildes = -line[1];
00101             }
00102             break;
00103 
00104         case 'n':
00105             if (context->n_callback)
00106                 (*context->n_callback)(context, line + 1);
00107             break;
00108 
00109         default:
00110             /* ignore everything else */
00111             break;
00112         }
00113     }
00114 }
00115 
00116 
00117 /* vim: set ts=8 sw=4 et : */