]>
Commit | Line | Data |
---|---|---|
3a29e909 | 1 | /* |
3a29e909 OO |
2 | * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com> |
3 | * | |
4 | * This file may be redistributed under the terms of the | |
5 | * GNU Lesser General Public License. | |
6 | */ | |
3a29e909 OO |
7 | #include <stdlib.h> |
8 | #include <unistd.h> | |
9 | #include <string.h> | |
3a29e909 | 10 | #include <errno.h> |
d9554c97 KZ |
11 | #include <sys/types.h> |
12 | #include <sys/stat.h> | |
13 | #include <dirent.h> | |
14 | #include <getopt.h> | |
3a29e909 OO |
15 | |
16 | #include "c.h" | |
17 | #include "nls.h" | |
d9554c97 | 18 | #include "strutils.h" |
3a29e909 OO |
19 | |
20 | #include "libsmartcols.h" | |
21 | ||
d9554c97 KZ |
22 | static int add_children(struct libscols_table *tb, |
23 | struct libscols_line *ln, int fd); | |
24 | ||
25 | ||
26 | enum { COL_MODE, COL_SIZE, COL_NAME }; | |
27 | ||
f92b26c1 KZ |
28 | /* add columns to the @tb */ |
29 | static void setup_columns(struct libscols_table *tb, int notree) | |
d9554c97 KZ |
30 | { |
31 | if (!scols_table_new_column(tb, "MODE", 0.3, 0)) | |
32 | goto fail; | |
33 | if (!scols_table_new_column(tb, "SIZE", 5, SCOLS_FL_RIGHT)) | |
34 | goto fail; | |
35 | if (!scols_table_new_column(tb, "NAME", 0.5, | |
36 | (notree ? 0 : SCOLS_FL_TREE) | SCOLS_FL_NOEXTREMES)) | |
37 | goto fail; | |
38 | ||
39 | return; | |
40 | fail: | |
41 | scols_unref_table(tb); | |
9e930041 | 42 | err(EXIT_FAILURE, "failed to create output columns"); |
d9554c97 KZ |
43 | } |
44 | ||
f92b26c1 | 45 | /* add a new line to @tb, the content is based on @st */ |
d9554c97 KZ |
46 | static int add_line_from_stat(struct libscols_table *tb, |
47 | struct libscols_line *parent, | |
48 | int parent_fd, | |
49 | struct stat *st, | |
50 | const char *name) | |
51 | { | |
52 | struct libscols_line *ln; | |
53 | char modbuf[11], *p; | |
54 | mode_t mode = st->st_mode; | |
55 | int rc = 0; | |
56 | ||
57 | ln = scols_table_new_line(tb, parent); | |
58 | if (!ln) | |
59 | err(EXIT_FAILURE, "failed to create output line"); | |
60 | ||
61 | /* MODE; local buffer, use scols_line_set_data() that calls strdup() */ | |
b0b24b11 | 62 | xstrmode(mode, modbuf); |
d9554c97 KZ |
63 | if (scols_line_set_data(ln, COL_MODE, modbuf)) |
64 | goto fail; | |
65 | ||
66 | /* SIZE; already allocated string, use scols_line_refer_data() */ | |
67 | p = size_to_human_string(0, st->st_size); | |
68 | if (!p || scols_line_refer_data(ln, COL_SIZE, p)) | |
69 | goto fail; | |
70 | ||
71 | /* NAME */ | |
72 | if (scols_line_set_data(ln, COL_NAME, name)) | |
73 | goto fail; | |
74 | ||
75 | /* colors */ | |
76 | if (scols_table_colors_wanted(tb)) { | |
77 | struct libscols_cell *ce = scols_line_get_cell(ln, COL_NAME); | |
78 | ||
79 | if (S_ISDIR(mode)) | |
80 | scols_cell_set_color(ce, "blue"); | |
81 | else if (S_ISLNK(mode)) | |
82 | scols_cell_set_color(ce, "cyan"); | |
83 | else if (S_ISBLK(mode)) | |
84 | scols_cell_set_color(ce, "magenta"); | |
85 | else if ((mode & S_IXOTH) || (mode & S_IXGRP) || (mode & S_IXUSR)) | |
86 | scols_cell_set_color(ce, "green"); | |
87 | } | |
88 | ||
89 | if (S_ISDIR(st->st_mode)) { | |
90 | int fd; | |
91 | ||
92 | if (parent_fd >= 0) | |
93 | fd = openat(parent_fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); | |
94 | else | |
95 | fd = open(name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); | |
96 | if (fd >= 0) { | |
97 | rc = add_children(tb, ln, fd); | |
98 | close(fd); | |
99 | } | |
100 | } | |
101 | return rc; | |
102 | fail: | |
103 | err(EXIT_FAILURE, "failed to create cell data"); | |
104 | return -1; | |
105 | } | |
106 | ||
9e930041 | 107 | /* read all entries from directory addressed by @fd */ |
d9554c97 KZ |
108 | static int add_children(struct libscols_table *tb, |
109 | struct libscols_line *ln, | |
110 | int fd) | |
111 | { | |
112 | DIR *dir; | |
113 | struct dirent *d; | |
114 | ||
115 | dir = fdopendir(fd); | |
116 | if (!dir) | |
117 | return -errno; | |
118 | ||
119 | while ((d = readdir(dir))) { | |
120 | struct stat st; | |
121 | ||
122 | if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) | |
123 | continue; | |
124 | if (fstatat(fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) | |
125 | continue; | |
126 | add_line_from_stat(tb, ln, fd, &st, d->d_name); | |
127 | } | |
128 | closedir(dir); | |
129 | return 0; | |
130 | } | |
131 | ||
132 | static void add_lines(struct libscols_table *tb, const char *dirname) | |
133 | { | |
134 | struct stat st; | |
135 | ||
136 | if (lstat(dirname, &st)) | |
137 | err(EXIT_FAILURE, "%s", dirname); | |
138 | ||
139 | add_line_from_stat(tb, NULL, -1, &st, dirname); | |
140 | } | |
141 | ||
142 | static void __attribute__((__noreturn__)) usage(FILE *out) | |
143 | { | |
f92b26c1 | 144 | fprintf(out, " %s [options] [<dir> ...]\n\n", program_invocation_short_name); |
2a750b4c KZ |
145 | fputs(" -c, --csv display a csv-like output\n", out); |
146 | fputs(" -i, --ascii use ascii characters only\n", out); | |
147 | fputs(" -l, --list use list format output\n", out); | |
148 | fputs(" -n, --noheadings don't print headings\n", out); | |
149 | fputs(" -p, --pairs use key=\"value\" output format\n", out); | |
150 | fputs(" -J, --json use JSON output format\n", out); | |
151 | fputs(" -r, --raw use raw output format\n", out); | |
152 | fputs(" -S, --range-start <n> first line to print\n", out); | |
153 | fputs(" -E, --range-end <n> last line to print\n", out); | |
d9554c97 KZ |
154 | |
155 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
156 | } | |
3a29e909 OO |
157 | |
158 | int main(int argc, char *argv[]) | |
159 | { | |
160 | struct libscols_table *tb; | |
2a750b4c KZ |
161 | int c, notree = 0, nstart = -1, nend = -1; |
162 | ||
d9554c97 KZ |
163 | |
164 | static const struct option longopts[] = { | |
d9554c97 | 165 | { "ascii", 0, 0, 'i' }, |
d1b4d14f | 166 | { "csv", 0, 0, 'c' }, |
f92b26c1 KZ |
167 | { "list", 0, 0, 'l' }, |
168 | { "noheadings", 0, 0, 'n' }, | |
169 | { "pairs", 0, 0, 'p' }, | |
6f273796 KZ |
170 | { "json", 0, 0, 'J' }, |
171 | { "raw", 0, 0, 'r' }, | |
2a750b4c KZ |
172 | { "range-start",1, 0, 'S' }, |
173 | { "range-end", 1, 0, 'E' }, | |
d9554c97 KZ |
174 | { NULL, 0, 0, 0 }, |
175 | }; | |
8a38a8d3 | 176 | |
f92b26c1 | 177 | setlocale(LC_ALL, ""); /* just to have enable UTF8 chars */ |
71dbc865 | 178 | |
4418714f KZ |
179 | scols_init_debug(0); |
180 | ||
71dbc865 | 181 | tb = scols_new_table(); |
8a38a8d3 | 182 | if (!tb) |
9e930041 | 183 | err(EXIT_FAILURE, "failed to create output table"); |
d9554c97 | 184 | |
2a750b4c | 185 | while((c = getopt_long(argc, argv, "ciJlnprS:E:", longopts, NULL)) != -1) { |
d9554c97 | 186 | switch(c) { |
f92b26c1 KZ |
187 | case 'c': |
188 | scols_table_set_column_separator(tb, ","); | |
189 | scols_table_enable_raw(tb, 1); | |
190 | notree = 1; | |
191 | break; | |
192 | case 'i': | |
193 | scols_table_enable_ascii(tb, 1); | |
d9554c97 | 194 | break; |
6f273796 KZ |
195 | case 'J': |
196 | scols_table_set_name(tb, "scolstest"); | |
197 | scols_table_enable_json(tb, 1); | |
198 | break; | |
d9554c97 KZ |
199 | case 'l': |
200 | notree = 1; | |
201 | break; | |
202 | case 'n': | |
203 | scols_table_enable_noheadings(tb, 1); | |
204 | break; | |
205 | case 'p': | |
206 | scols_table_enable_export(tb, 1); | |
207 | notree = 1; | |
208 | break; | |
d9554c97 KZ |
209 | case 'r': |
210 | scols_table_enable_raw(tb, 1); | |
211 | notree = 1; | |
212 | break; | |
2a750b4c KZ |
213 | case 'S': |
214 | nstart = strtos32_or_err(optarg, "failed to parse range start") - 1; | |
215 | break; | |
216 | case 'E': | |
217 | nend = strtos32_or_err(optarg, "failed to parse range end") - 1; | |
218 | break; | |
d9554c97 KZ |
219 | default: |
220 | usage(stderr); | |
221 | } | |
3a29e909 OO |
222 | } |
223 | ||
d9554c97 | 224 | scols_table_enable_colors(tb, 1); |
f92b26c1 | 225 | setup_columns(tb, notree); |
3a29e909 | 226 | |
2f09ae9d KZ |
227 | if (optind == argc) |
228 | add_lines(tb, "."); | |
229 | else while (optind < argc) | |
d9554c97 | 230 | add_lines(tb, argv[optind++]); |
3a29e909 | 231 | |
2a750b4c KZ |
232 | if (nstart >= 0 || nend >= 0) { |
233 | /* print subset */ | |
234 | struct libscols_line *start = NULL, *end = NULL; | |
235 | ||
236 | if (nstart >= 0) | |
237 | start = scols_table_get_line(tb, nstart); | |
238 | if (nend >= 0) | |
239 | end = scols_table_get_line(tb, nend); | |
3a29e909 | 240 | |
2a750b4c KZ |
241 | if (start || end) |
242 | scols_table_print_range(tb, start, end); | |
243 | } else | |
244 | /* print all table */ | |
245 | scols_print_table(tb); | |
246 | ||
247 | scols_unref_table(tb); | |
3a29e909 OO |
248 | return EXIT_SUCCESS; |
249 | } |