Start 1.33.0 development cycle
[oweals/busybox.git] / miscutils / lsscsi.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * lsscsi implementation for busybox
4  *
5  * Copyright (C) 2017 Markus Gothe <nietzsche@lysator.liu.se>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8  */
9 //config:config LSSCSI
10 //config:       bool "lsscsi (2.5 kb)"
11 //config:       default y
12 //config:       #select PLATFORM_LINUX
13 //config:       help
14 //config:       lsscsi is a utility for displaying information about SCSI buses in the
15 //config:       system and devices connected to them.
16 //config:
17 //config:       This version uses sysfs (/sys/bus/scsi/devices) only.
18
19 //applet:IF_LSSCSI(APPLET_NOEXEC(lsscsi, lsscsi, BB_DIR_USR_BIN, BB_SUID_DROP, lsscsi))
20
21 //kbuild:lib-$(CONFIG_LSSCSI) += lsscsi.o
22
23 //usage:#define lsscsi_trivial_usage NOUSAGE_STR
24 //usage:#define lsscsi_full_usage ""
25
26 #include "libbb.h"
27
28 static const char scsi_dir[] ALIGN1 = "/sys/bus/scsi/devices";
29
30 static char *get_line(const char *filename, char *buf, unsigned *bufsize_p)
31 {
32         unsigned bufsize = *bufsize_p;
33         ssize_t sz;
34
35         if ((int)(bufsize - 2) <= 0)
36                 return buf;
37
38         sz = open_read_close(filename, buf, bufsize - 2);
39         if (sz < 0)
40                 sz = 0;
41         buf[sz] = '\0';
42
43         sz = (trim(buf) - buf) + 1;
44         bufsize -= sz;
45         buf += sz;
46         buf[0] = '\0';
47
48         *bufsize_p = bufsize;
49         return buf;
50 }
51
52 int lsscsi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
53 int lsscsi_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
54 {
55         struct dirent *de;
56         DIR *dir;
57
58         xchdir(scsi_dir);
59
60         dir = xopendir(".");
61         while ((de = readdir(dir)) != NULL) {
62                 char buf[256];
63                 char *ptr;
64                 unsigned bufsize;
65                 const char *vendor;
66                 const char *type_str;
67                 const char *type_name;
68                 const char *model;
69                 const char *rev;
70                 unsigned type;
71
72                 if (!isdigit(de->d_name[0]))
73                         continue;
74                 if (!strchr(de->d_name, ':'))
75                         continue;
76                 if (chdir(de->d_name) != 0)
77                         continue;
78
79                 bufsize = sizeof(buf);
80                 vendor = buf;
81                 ptr = get_line("vendor", buf, &bufsize);
82                 type_str = ptr;
83                 ptr = get_line("type", ptr, &bufsize);
84                 model = ptr;
85                 ptr = get_line("model", ptr, &bufsize);
86                 rev = ptr;
87                 ptr = get_line("rev", ptr, &bufsize);
88
89                 printf("[%s]\t", de->d_name);
90
91 #define scsi_device_types \
92         "disk\0"    "tape\0"    "printer\0" "process\0" \
93         "worm\0"    "\0"        "scanner\0" "optical\0" \
94         "mediumx\0" "comms\0"   "\0"        "\0"        \
95         "storage\0" "enclosu\0" "sim dsk\0" "opti rd\0" \
96         "bridge\0"  "osd\0"     "adi\0"     "\0"        \
97         "\0"        "\0"        "\0"        "\0"        \
98         "\0"        "\0"        "\0"        "\0"        \
99         "\0"        "\0"        "wlun\0"    "no dev"
100                 type = bb_strtou(type_str, NULL, 10);
101                 if (errno
102                  || type >= 0x20
103                  || (type_name = nth_string(scsi_device_types, type))[0] == '\0'
104                 ) {
105                         printf("(%s)\t", type_str);
106                 } else {
107                         printf("%s\t", type_name);
108                 }
109
110                 printf("%s\t""%s\t""%s\n",
111                         vendor,
112                         model,
113                         rev
114                 );
115                 /* TODO: also output device column, e.g. "/dev/sdX" */
116
117                 /* chdir("..") may not work as expected,
118                  * since we might have followed a symlink.
119                  */
120                 xchdir(scsi_dir);
121         }
122
123         if (ENABLE_FEATURE_CLEAN_UP)
124                 closedir(dir);
125
126         return EXIT_SUCCESS;
127 }