Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/procps/fuser.c


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/procps/fuser.c

    r2859 r3232  
    88 */
    99
     10//usage:#define fuser_trivial_usage
     11//usage:       "[OPTIONS] FILE or PORT/PROTO"
     12//usage:#define fuser_full_usage "\n\n"
     13//usage:       "Find processes which use FILEs or PORTs\n"
     14//usage:     "\n    -m  Find processes which use same fs as FILEs"
     15//usage:     "\n    -4,-6   Search only IPv4/IPv6 space"
     16//usage:     "\n    -s  Don't display PIDs"
     17//usage:     "\n    -k  Kill found processes"
     18//usage:     "\n    -SIGNAL Signal to send (default: KILL)"
     19
    1020#include "libbb.h"
    1121
     
    2737} inode_list;
    2838
    29 typedef struct pid_list {
    30     struct pid_list *next;
    31     pid_t pid;
    32 } pid_list;
    33 
    34 
    3539struct globals {
    36     pid_list *pid_list_head;
     40    int recursion_depth;
     41    pid_t mypid;
    3742    inode_list *inode_list_head;
    38 };
     43    smallint kill_failed;
     44    int killsig;
     45} FIX_ALIASING;
    3946#define G (*(struct globals*)&bb_common_bufsiz1)
    40 #define INIT_G() do { } while (0)
    41 
    42 
    43 static void add_pid(const pid_t pid)
    44 {
    45     pid_list **curr = &G.pid_list_head;
    46 
    47     while (*curr) {
    48         if ((*curr)->pid == pid)
    49             return;
    50         curr = &(*curr)->next;
    51     }
    52 
    53     *curr = xzalloc(sizeof(pid_list));
    54     (*curr)->pid = pid;
    55 }
     47#define INIT_G() do { \
     48    G.mypid = getpid(); \
     49    G.killsig = SIGKILL; \
     50} while (0)
    5651
    5752static void add_inode(const struct stat *st)
     
    7368}
    7469
    75 static void scan_proc_net(const char *path, unsigned port)
    76 {
    77     char line[MAX_LINE + 1];
    78     long long uint64_inode;
    79     unsigned tmp_port;
    80     FILE *f;
    81     struct stat st;
    82     int fd;
    83 
    84     /* find socket dev */
    85     st.st_dev = 0;
    86     fd = socket(AF_INET, SOCK_DGRAM, 0);
    87     if (fd >= 0) {
    88         fstat(fd, &st);
    89         close(fd);
    90     }
    91 
    92     f = fopen_for_read(path);
    93     if (!f)
    94         return;
    95 
    96     while (fgets(line, MAX_LINE, f)) {
    97         char addr[68];
    98         if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x "
    99                 "%*x:%*x %*x %*d %*d %llu",
    100                 addr, &tmp_port, &uint64_inode) == 3
    101         ) {
    102             int len = strlen(addr);
    103             if (len == 8 && (option_mask32 & OPT_IP6))
    104                 continue;
    105             if (len > 8 && (option_mask32 & OPT_IP4))
    106                 continue;
    107             if (tmp_port == port) {
    108                 st.st_ino = uint64_inode;
    109                 add_inode(&st);
    110             }
    111         }
    112     }
    113     fclose(f);
    114 }
    115 
    116 static int search_dev_inode(const struct stat *st)
     70static smallint search_dev_inode(const struct stat *st)
    11771{
    11872    inode_list *ilist = G.inode_list_head;
     
    13084}
    13185
    132 static void scan_pid_maps(const char *fname, pid_t pid)
    133 {
    134     FILE *file;
    135     char line[MAX_LINE + 1];
    136     int major, minor;
     86enum {
     87    PROC_NET = 0,
     88    PROC_DIR,
     89    PROC_DIR_LINKS,
     90    PROC_SUBDIR_LINKS,
     91};
     92
     93static smallint scan_proc_net_or_maps(const char *path, unsigned port)
     94{
     95    FILE *f;
     96    char line[MAX_LINE + 1], addr[68];
     97    int major, minor, r;
    13798    long long uint64_inode;
    138     struct stat st;
    139 
    140     file = fopen_for_read(fname);
    141     if (!file)
    142         return;
    143 
    144     while (fgets(line, MAX_LINE, file)) {
    145         if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3)
     99    unsigned tmp_port;
     100    smallint retval;
     101    struct stat statbuf;
     102    const char *fmt;
     103    void *fag, *sag;
     104
     105    f = fopen_for_read(path);
     106    if (!f)
     107        return 0;
     108
     109    if (G.recursion_depth == PROC_NET) {
     110        int fd;
     111
     112        /* find socket dev */
     113        statbuf.st_dev = 0;
     114        fd = socket(AF_INET, SOCK_DGRAM, 0);
     115        if (fd >= 0) {
     116            fstat(fd, &statbuf);
     117            close(fd);
     118        }
     119
     120        fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
     121            "%*x:%*x %*x:%*x %*x %*d %*d %llu";
     122        fag = addr;
     123        sag = &tmp_port;
     124    } else {
     125        fmt = "%*s %*s %*s %x:%x %llu";
     126        fag = &major;
     127        sag = &minor;
     128    }
     129
     130    retval = 0;
     131    while (fgets(line, MAX_LINE, f)) {
     132        r = sscanf(line, fmt, fag, sag, &uint64_inode);
     133        if (r != 3)
    146134            continue;
    147         st.st_ino = uint64_inode;
    148         if (major == 0 && minor == 0 && st.st_ino == 0)
    149             continue;
    150         st.st_dev = makedev(major, minor);
    151         if (search_dev_inode(&st))
    152             add_pid(pid);
    153     }
    154     fclose(file);
    155 }
    156 
    157 static void scan_link(const char *lname, pid_t pid)
    158 {
    159     struct stat st;
    160 
    161     if (stat(lname, &st) >= 0) {
    162         if (search_dev_inode(&st))
    163             add_pid(pid);
    164     }
    165 }
    166 
    167 static void scan_dir_links(const char *dname, pid_t pid)
     135
     136        statbuf.st_ino = uint64_inode;
     137        if (G.recursion_depth == PROC_NET) {
     138            r = strlen(addr);
     139            if (r == 8 && (option_mask32 & OPT_IP6))
     140                continue;
     141            if (r > 8 && (option_mask32 & OPT_IP4))
     142                continue;
     143            if (tmp_port == port)
     144                add_inode(&statbuf);
     145        } else {
     146            if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
     147                statbuf.st_dev = makedev(major, minor);
     148                retval = search_dev_inode(&statbuf);
     149                if (retval)
     150                    break;
     151            }
     152        }
     153    }
     154    fclose(f);
     155
     156    return retval;
     157}
     158
     159static smallint scan_recursive(const char *path)
    168160{
    169161    DIR *d;
    170     struct dirent *de;
    171     char *lname;
    172 
    173     d = opendir(dname);
    174     if (!d)
    175         return;
    176 
    177     while ((de = readdir(d)) != NULL) {
    178         lname = concat_subpath_file(dname, de->d_name);
    179         if (lname == NULL)
    180             continue;
    181         scan_link(lname, pid);
    182         free(lname);
     162    struct dirent *d_ent;
     163    smallint stop_scan;
     164    smallint retval;
     165
     166    d = opendir(path);
     167    if (d == NULL)
     168        return 0;
     169
     170    G.recursion_depth++;
     171    retval = 0;
     172    stop_scan = 0;
     173    while (!stop_scan && (d_ent = readdir(d)) != NULL) {
     174        struct stat statbuf;
     175        pid_t pid;
     176        char *subpath;
     177
     178        subpath = concat_subpath_file(path, d_ent->d_name);
     179        if (subpath == NULL)
     180            continue; /* . or .. */
     181
     182        switch (G.recursion_depth) {
     183        case PROC_DIR:
     184            pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
     185            if (errno != 0
     186             || pid == G.mypid
     187            /* "this PID doesn't use specified FILEs or PORT/PROTO": */
     188             || scan_recursive(subpath) == 0
     189            ) {
     190                break;
     191            }
     192            if (option_mask32 & OPT_KILL) {
     193                if (kill(pid, G.killsig) != 0) {
     194                    bb_perror_msg("kill pid %s", d_ent->d_name);
     195                    G.kill_failed = 1;
     196                }
     197            }
     198            if (!(option_mask32 & OPT_SILENT))
     199                printf("%s ", d_ent->d_name);
     200            retval = 1;
     201            break;
     202
     203        case PROC_DIR_LINKS:
     204            switch (
     205                index_in_substrings(
     206                    "cwd"  "\0" "exe"  "\0"
     207                    "root" "\0" "fd"   "\0"
     208                    "lib"  "\0" "mmap" "\0"
     209                    "maps" "\0",
     210                    d_ent->d_name
     211                )
     212            ) {
     213            enum {
     214                CWD_LINK,
     215                EXE_LINK,
     216                ROOT_LINK,
     217                FD_DIR_LINKS,
     218                LIB_DIR_LINKS,
     219                MMAP_DIR_LINKS,
     220                MAPS,
     221            };
     222            case CWD_LINK:
     223            case EXE_LINK:
     224            case ROOT_LINK:
     225                goto scan_link;
     226            case FD_DIR_LINKS:
     227            case LIB_DIR_LINKS:
     228            case MMAP_DIR_LINKS:
     229                stop_scan = scan_recursive(subpath);
     230                if (stop_scan)
     231                    retval = stop_scan;
     232                break;
     233            case MAPS:
     234                stop_scan = scan_proc_net_or_maps(subpath, 0);
     235                if (stop_scan)
     236                    retval = stop_scan;
     237            default:
     238                break;
     239            }
     240            break;
     241        case PROC_SUBDIR_LINKS:
     242  scan_link:
     243            if (stat(subpath, &statbuf) < 0)
     244                break;
     245            stop_scan = search_dev_inode(&statbuf);
     246            if (stop_scan)
     247                retval = stop_scan;
     248        default:
     249            break;
     250        }
     251        free(subpath);
    183252    }
    184253    closedir(d);
    185 }
    186 
    187 /* NB: does chdir internally */
    188 static void scan_proc_pids(void)
    189 {
    190     DIR *d;
    191     struct dirent *de;
    192     pid_t pid;
    193 
    194     xchdir("/proc");
    195     d = opendir("/proc");
    196     if (!d)
    197         return;
    198 
    199     while ((de = readdir(d)) != NULL) {
    200         pid = (pid_t)bb_strtou(de->d_name, NULL, 10);
    201         if (errno)
    202             continue;
    203         if (chdir(de->d_name) < 0)
    204             continue;
    205         scan_link("cwd", pid);
    206         scan_link("exe", pid);
    207         scan_link("root", pid);
    208 
    209         scan_dir_links("fd", pid);
    210         scan_dir_links("lib", pid);
    211         scan_dir_links("mmap", pid);
    212 
    213         scan_pid_maps("maps", pid);
    214         xchdir("/proc");
    215     }
    216     closedir(d);
     254    G.recursion_depth--;
     255    return retval;
    217256}
    218257
     
    220259int fuser_main(int argc UNUSED_PARAM, char **argv)
    221260{
    222     pid_list *plist;
    223     pid_t mypid;
    224261    char **pp;
    225     struct stat st;
    226     unsigned port;
    227     int opt;
    228     int exitcode;
    229     int killsig;
    230 /*
    231 fuser [OPTIONS] FILE or PORT/PROTO
    232 Find processes which use FILEs or PORTs
    233         -m      Find processes which use same fs as FILEs
    234         -4      Search only IPv4 space
    235         -6      Search only IPv6 space
    236         -s      Don't display PIDs
    237         -k      Kill found processes
    238         -SIGNAL Signal to send (default: KILL)
    239 */
     262
     263    INIT_G();
     264
    240265    /* Handle -SIGNAL. Oh my... */
    241     killsig = SIGKILL; /* yes, the default is not SIGTERM */
    242266    pp = argv;
    243267    while (*++pp) {
     268        int sig;
    244269        char *arg = *pp;
     270
    245271        if (arg[0] != '-')
    246272            continue;
     
    249275        if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
    250276            continue; /* it's "-4" or "-6" */
    251         opt = get_signum(&arg[1]);
    252         if (opt < 0)
     277        sig = get_signum(&arg[1]);
     278        if (sig < 0)
    253279            continue;
    254280        /* "-SIGNAL" option found. Remove it and bail out */
    255         killsig = opt;
     281        G.killsig = sig;
    256282        do {
    257283            pp[0] = arg = pp[1];
     
    262288
    263289    opt_complementary = "-1"; /* at least one param */
    264     opt = getopt32(argv, OPTION_STRING);
     290    getopt32(argv, OPTION_STRING);
    265291    argv += optind;
    266292
     
    268294    while (*pp) {
    269295        /* parse net arg */
    270         char path[20], tproto[5];
    271         if (sscanf(*pp, "%u/%4s", &port, tproto) != 2)
    272             goto file;
    273         sprintf(path, "/proc/net/%s", tproto);
    274         if (access(path, R_OK) == 0) { /* PORT/PROTO */
    275             scan_proc_net(path, port);
    276         } else { /* FILE */
    277  file:
    278             xstat(*pp, &st);
    279             add_inode(&st);
     296        unsigned port;
     297        char path[sizeof("/proc/net/TCP6")];
     298
     299        strcpy(path, "/proc/net/");
     300        if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
     301         && access(path, R_OK) == 0
     302        ) {
     303            /* PORT/PROTO */
     304            scan_proc_net_or_maps(path, port);
     305        } else {
     306            /* FILE */
     307            struct stat statbuf;
     308            xstat(*pp, &statbuf);
     309            add_inode(&statbuf);
    280310        }
    281311        pp++;
    282312    }
    283313
    284     scan_proc_pids(); /* changes dir to "/proc" */
    285 
    286     mypid = getpid();
    287     plist = G.pid_list_head;
    288     while (1) {
    289         if (!plist)
    290             return EXIT_FAILURE;
    291         if (plist->pid != mypid)
    292             break;
    293         plist = plist->next;
    294     }
    295 
    296     exitcode = EXIT_SUCCESS;
    297     do {
    298         if (plist->pid != mypid) {
    299             if (opt & OPT_KILL) {
    300                 if (kill(plist->pid, killsig) != 0) {
    301                     bb_perror_msg("kill pid %u", (unsigned)plist->pid);
    302                     exitcode = EXIT_FAILURE;
    303                 }
    304             }
    305             if (!(opt & OPT_SILENT)) {
    306                 printf("%u ", (unsigned)plist->pid);
    307             }
    308         }
    309         plist = plist->next;
    310     } while (plist);
    311 
    312     if (!(opt & (OPT_SILENT))) {
    313         bb_putchar('\n');
    314     }
    315 
    316     return exitcode;
    317 }
     314    if (scan_recursive("/proc")) {
     315        if (!(option_mask32 & OPT_SILENT))
     316            bb_putchar('\n');
     317        return G.kill_failed;
     318    }
     319
     320    return EXIT_FAILURE;
     321}
Note: See TracChangeset for help on using the changeset viewer.