1 #define EX_UTILS_NO_USE_OPEN 1
2 #define EX_UTILS_NO_USE_LIMIT 1
3 #define EX_UTILS_NO_USE_GET 1
4 #include "ex_utils.h"
5
6 #include <sys/types.h>
7 #include <dirent.h>
8
app_netstr_cstr(Vstr_base * s1,const char * val)9 static void app_netstr_cstr(Vstr_base *s1, const char *val)
10 {
11 size_t nb = vstr_add_netstr_beg(s1, s1->len);
12 vstr_add_cstr_buf(s1, s1->len, val);
13 vstr_add_netstr_end(s1, nb, s1->len);
14 }
app_netstr_uintmax(Vstr_base * s1,VSTR_AUTOCONF_uintmax_t val)15 static void app_netstr_uintmax(Vstr_base *s1, VSTR_AUTOCONF_uintmax_t val)
16 {
17 char buf[sizeof(val) * 8];
18 size_t nb = vstr_add_netstr_beg(s1, s1->len);
19 size_t len = vstr_sc_conv_num10_uintmax(buf, sizeof(buf), val);
20 vstr_add_buf(s1, s1->len, buf, len);
21 vstr_add_netstr_end(s1, nb, s1->len);
22 }
23
stat_from(struct stat64 * buf,const char * from,const char * name,Vstr_base * tmp)24 static int stat_from(struct stat64 *buf, const char *from, const char *name,
25 Vstr_base *tmp)
26 {
27 const char *full_name = NULL;
28
29 vstr_del(tmp, 1, tmp->len);
30 vstr_add_fmt(tmp, tmp->len, "%s/%s", from, name);
31
32 if (!(full_name = vstr_export_cstr_ptr(tmp, 1, tmp->len)) ||
33 stat64(full_name, buf))
34 {
35 warn("stat(%s)", name);
36 return (FALSE);
37 }
38
39 vstr_del(tmp, 1, tmp->len);
40 return (TRUE);
41 }
42
43 /* This is "dir_list", without any command line options */
main(int argc,char * argv[])44 int main(int argc, char *argv[])
45 {
46 Vstr_base *tmp = NULL;
47 Vstr_base *s1 = ex_init(&tmp); /* init the library etc. */
48 int count = 1; /* skip the program name */
49 DIR *dir = NULL;
50 struct dirent *ent = NULL;
51 int sizes = FALSE;
52 int follow = FALSE;
53
54 /* parse command line arguments... */
55 while (count < argc)
56 { /* quick hack getopt_long */
57 if (!strcmp("--", argv[count]))
58 {
59 ++count;
60 break;
61 }
62 else if (!strcmp("--size", argv[count]))
63 sizes = !sizes;
64 else if (!strcmp("--follow", argv[count]))
65 follow = !follow;
66 else if (!strcmp("--version", argv[count]))
67 { /* print version and exit */
68 vstr_add_fmt(s1, 0, "%s", "\
69 jdir_list 1.0.0\n\
70 Written by James Antill\n\
71 \n\
72 Uses Vstr string library.\n\
73 ");
74 goto out;
75 }
76 else if (!strcmp("--help", argv[count]))
77 { /* print version and exit */
78 vstr_add_fmt(s1, 0, "%s", "\
79 Usage: jdir_list <DIRECTORY>...\n\
80 or: jdir_list OPTION\n\
81 Output filenames.\n\
82 \n\
83 --help Display this help and exit\n\
84 --version Output version information and exit\n\
85 --size Stat files to output size information\n\
86 --follow Stat symlinks to get type information\n\
87 -- Treat rest of cmd line as input filenames\n\
88 \n\
89 Report bugs to James Antill <james@and.org>.\n\
90 ");
91 goto out;
92 }
93 else
94 break;
95 ++count;
96 }
97
98 /* if no arguments are given just do stdin to stdout */
99 if (count >= argc)
100 errx(EXIT_FAILURE, "No directory given");
101
102 if (!(dir = opendir(argv[count])))
103 err(EXIT_FAILURE, "opendir(%s)", argv[count]);
104
105 {
106 size_t nb = vstr_add_netstr_beg(s1, s1->len);
107
108 app_netstr_cstr(s1, "version");
109 app_netstr_cstr(s1, "1");
110
111 vstr_add_netstr_end(s1, nb, s1->len);
112 }
113
114 /* readdir() == blocking, dirfd() for poll() ? */
115 while (!s1->conf->malloc_bad && (ent = readdir(dir)))
116 {
117 size_t nb = vstr_add_netstr_beg(s1, s1->len);
118 struct stat64 buf;
119 int use_stat = FALSE;
120
121 app_netstr_cstr(s1, "name");
122 app_netstr_cstr(s1, ent->d_name);
123
124 if (sizes &&
125 ((ent->d_type == DT_REG) || (ent->d_type == DT_UNKNOWN)))
126 use_stat = TRUE;
127
128 if (follow &&
129 ((ent->d_type == DT_LNK) || (ent->d_type == DT_UNKNOWN)))
130 use_stat = TRUE;
131
132 if (use_stat && stat_from(&buf, argv[count], ent->d_name, tmp))
133 {
134 app_netstr_cstr(s1, "inode");
135 app_netstr_uintmax(s1, buf.st_ino);
136
137 if ((ent->d_type != DT_UNKNOWN) && !follow)
138 {
139 app_netstr_cstr(s1, "type");
140 app_netstr_uintmax(s1, DTTOIF(ent->d_type));
141 }
142 else
143 {
144 app_netstr_cstr(s1, "type");
145 app_netstr_uintmax(s1, buf.st_mode);
146 }
147
148 app_netstr_cstr(s1, "size");
149 app_netstr_uintmax(s1, buf.st_size);
150 }
151 else
152 {
153 app_netstr_cstr(s1, "inode");
154 app_netstr_uintmax(s1, ent->d_ino);
155
156 if (ent->d_type != DT_UNKNOWN)
157 {
158 app_netstr_cstr(s1, "type");
159 app_netstr_uintmax(s1, DTTOIF(ent->d_type));
160 }
161 }
162
163 vstr_add_netstr_end(s1, nb, s1->len);
164 }
165
166 if (s1->conf->malloc_bad)
167 errno = ENOMEM, err(EXIT_FAILURE, "readdir(%s)", argv[count]);
168
169 out:
170 io_put_all(s1, STDOUT_FILENO);
171
172 exit (ex_exit(s1, tmp));
173 }
174