1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of KTH nor the names of its contributors may be
18b528cefcSMark Murray * used to endorse or promote products derived from this software without
19b528cefcSMark Murray * specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22b528cefcSMark Murray * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24b528cefcSMark Murray * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25b528cefcSMark Murray * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26b528cefcSMark Murray * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27b528cefcSMark Murray * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28b528cefcSMark Murray * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29b528cefcSMark Murray * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30b528cefcSMark Murray * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31b528cefcSMark Murray * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32b528cefcSMark Murray
335e9cd1aeSAssar Westerlund #ifndef TEST
34b528cefcSMark Murray #include "ftpd_locl.h"
35b528cefcSMark Murray
36*ae771770SStanislav Sedov RCSID("$Id$");
375e9cd1aeSAssar Westerlund
385e9cd1aeSAssar Westerlund #else
395e9cd1aeSAssar Westerlund #include <stdio.h>
405e9cd1aeSAssar Westerlund #include <string.h>
415e9cd1aeSAssar Westerlund #include <stdlib.h>
425e9cd1aeSAssar Westerlund #include <time.h>
435e9cd1aeSAssar Westerlund #include <dirent.h>
445e9cd1aeSAssar Westerlund #include <sys/stat.h>
455e9cd1aeSAssar Westerlund #include <unistd.h>
465e9cd1aeSAssar Westerlund #include <pwd.h>
475e9cd1aeSAssar Westerlund #include <grp.h>
485e9cd1aeSAssar Westerlund #include <errno.h>
495e9cd1aeSAssar Westerlund
505e9cd1aeSAssar Westerlund #define sec_fprintf2 fprintf
515e9cd1aeSAssar Westerlund #define sec_fflush fflush
524137ff4cSJacques Vidrine static void list_files(FILE *out, const char **files, int n_files, int flags);
534137ff4cSJacques Vidrine static int parse_flags(const char *options);
544137ff4cSJacques Vidrine
555e9cd1aeSAssar Westerlund int
main(int argc,char ** argv)565e9cd1aeSAssar Westerlund main(int argc, char **argv)
575e9cd1aeSAssar Westerlund {
584137ff4cSJacques Vidrine int i = 1;
594137ff4cSJacques Vidrine int flags;
604137ff4cSJacques Vidrine if(argc > 1 && argv[1][0] == '-') {
614137ff4cSJacques Vidrine flags = parse_flags(argv[1]);
624137ff4cSJacques Vidrine i = 2;
634137ff4cSJacques Vidrine } else
644137ff4cSJacques Vidrine flags = parse_flags(NULL);
654137ff4cSJacques Vidrine
664137ff4cSJacques Vidrine list_files(stdout, (const char **)argv + i, argc - i, flags);
675e9cd1aeSAssar Westerlund return 0;
685e9cd1aeSAssar Westerlund }
695e9cd1aeSAssar Westerlund #endif
70b528cefcSMark Murray
71b528cefcSMark Murray struct fileinfo {
72b528cefcSMark Murray struct stat st;
73b528cefcSMark Murray int inode;
74b528cefcSMark Murray int bsize;
75b528cefcSMark Murray char mode[11];
76b528cefcSMark Murray int n_link;
77b528cefcSMark Murray char *user;
78b528cefcSMark Murray char *group;
79b528cefcSMark Murray char *size;
80b528cefcSMark Murray char *major;
81b528cefcSMark Murray char *minor;
82b528cefcSMark Murray char *date;
83b528cefcSMark Murray char *filename;
84b528cefcSMark Murray char *link;
85b528cefcSMark Murray };
86b528cefcSMark Murray
87b528cefcSMark Murray static void
free_fileinfo(struct fileinfo * f)88b528cefcSMark Murray free_fileinfo(struct fileinfo *f)
89b528cefcSMark Murray {
90b528cefcSMark Murray free(f->user);
91b528cefcSMark Murray free(f->group);
92b528cefcSMark Murray free(f->size);
93b528cefcSMark Murray free(f->major);
94b528cefcSMark Murray free(f->minor);
95b528cefcSMark Murray free(f->date);
96b528cefcSMark Murray free(f->filename);
97b528cefcSMark Murray free(f->link);
98b528cefcSMark Murray }
99b528cefcSMark Murray
1005e9cd1aeSAssar Westerlund #define LS_DIRS (1 << 0)
1015e9cd1aeSAssar Westerlund #define LS_IGNORE_DOT (1 << 1)
1025e9cd1aeSAssar Westerlund #define LS_SORT_MODE (3 << 2)
103b528cefcSMark Murray #define SORT_MODE(f) ((f) & LS_SORT_MODE)
1045e9cd1aeSAssar Westerlund #define LS_SORT_NAME (1 << 2)
1055e9cd1aeSAssar Westerlund #define LS_SORT_MTIME (2 << 2)
1065e9cd1aeSAssar Westerlund #define LS_SORT_SIZE (3 << 2)
1075e9cd1aeSAssar Westerlund #define LS_SORT_REVERSE (1 << 4)
108b528cefcSMark Murray
1095e9cd1aeSAssar Westerlund #define LS_SIZE (1 << 5)
1105e9cd1aeSAssar Westerlund #define LS_INODE (1 << 6)
1115e9cd1aeSAssar Westerlund #define LS_TYPE (1 << 7)
1125e9cd1aeSAssar Westerlund #define LS_DISP_MODE (3 << 8)
1135e9cd1aeSAssar Westerlund #define DISP_MODE(f) ((f) & LS_DISP_MODE)
1145e9cd1aeSAssar Westerlund #define LS_DISP_LONG (1 << 8)
1155e9cd1aeSAssar Westerlund #define LS_DISP_COLUMN (2 << 8)
1165e9cd1aeSAssar Westerlund #define LS_DISP_CROSS (3 << 8)
1174137ff4cSJacques Vidrine #define LS_SHOW_ALL (1 << 10)
1184137ff4cSJacques Vidrine #define LS_RECURSIVE (1 << 11)
1194137ff4cSJacques Vidrine #define LS_EXTRA_BLANK (1 << 12)
1204137ff4cSJacques Vidrine #define LS_SHOW_DIRNAME (1 << 13)
1214137ff4cSJacques Vidrine #define LS_DIR_FLAG (1 << 14) /* these files come via list_dir */
122b528cefcSMark Murray
123b528cefcSMark Murray #ifndef S_ISTXT
124b528cefcSMark Murray #define S_ISTXT S_ISVTX
125b528cefcSMark Murray #endif
126b528cefcSMark Murray
1278373020dSJacques Vidrine #if !defined(_S_IFMT) && defined(S_IFMT)
1288373020dSJacques Vidrine #define _S_IFMT S_IFMT
1298373020dSJacques Vidrine #endif
1308373020dSJacques Vidrine
131b528cefcSMark Murray #ifndef S_ISSOCK
132b528cefcSMark Murray #define S_ISSOCK(mode) (((mode) & _S_IFMT) == S_IFSOCK)
133b528cefcSMark Murray #endif
134b528cefcSMark Murray
135b528cefcSMark Murray #ifndef S_ISLNK
136b528cefcSMark Murray #define S_ISLNK(mode) (((mode) & _S_IFMT) == S_IFLNK)
137b528cefcSMark Murray #endif
138b528cefcSMark Murray
1394137ff4cSJacques Vidrine static size_t
block_convert(size_t blocks)1404137ff4cSJacques Vidrine block_convert(size_t blocks)
1414137ff4cSJacques Vidrine {
1424137ff4cSJacques Vidrine #ifdef S_BLKSIZE
1434137ff4cSJacques Vidrine return blocks * S_BLKSIZE / 1024;
1444137ff4cSJacques Vidrine #else
1454137ff4cSJacques Vidrine return blocks * 512 / 1024;
1464137ff4cSJacques Vidrine #endif
1474137ff4cSJacques Vidrine }
1484137ff4cSJacques Vidrine
149c19800e8SDoug Rabson static int
make_fileinfo(FILE * out,const char * filename,struct fileinfo * file,int flags)1504137ff4cSJacques Vidrine make_fileinfo(FILE *out, const char *filename, struct fileinfo *file, int flags)
151b528cefcSMark Murray {
152b528cefcSMark Murray char buf[128];
1535e9cd1aeSAssar Westerlund int file_type = 0;
154b528cefcSMark Murray struct stat *st = &file->st;
155b528cefcSMark Murray
156b528cefcSMark Murray file->inode = st->st_ino;
1574137ff4cSJacques Vidrine file->bsize = block_convert(st->st_blocks);
158b528cefcSMark Murray
1595e9cd1aeSAssar Westerlund if(S_ISDIR(st->st_mode)) {
160b528cefcSMark Murray file->mode[0] = 'd';
1615e9cd1aeSAssar Westerlund file_type = '/';
1625e9cd1aeSAssar Westerlund }
163b528cefcSMark Murray else if(S_ISCHR(st->st_mode))
164b528cefcSMark Murray file->mode[0] = 'c';
165b528cefcSMark Murray else if(S_ISBLK(st->st_mode))
166b528cefcSMark Murray file->mode[0] = 'b';
1675e9cd1aeSAssar Westerlund else if(S_ISREG(st->st_mode)) {
168b528cefcSMark Murray file->mode[0] = '-';
1695e9cd1aeSAssar Westerlund if(st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
1705e9cd1aeSAssar Westerlund file_type = '*';
1715e9cd1aeSAssar Westerlund }
1725e9cd1aeSAssar Westerlund else if(S_ISFIFO(st->st_mode)) {
173b528cefcSMark Murray file->mode[0] = 'p';
1745e9cd1aeSAssar Westerlund file_type = '|';
1755e9cd1aeSAssar Westerlund }
1765e9cd1aeSAssar Westerlund else if(S_ISLNK(st->st_mode)) {
177b528cefcSMark Murray file->mode[0] = 'l';
1785e9cd1aeSAssar Westerlund file_type = '@';
1795e9cd1aeSAssar Westerlund }
1805e9cd1aeSAssar Westerlund else if(S_ISSOCK(st->st_mode)) {
181b528cefcSMark Murray file->mode[0] = 's';
1825e9cd1aeSAssar Westerlund file_type = '=';
1835e9cd1aeSAssar Westerlund }
184b528cefcSMark Murray #ifdef S_ISWHT
1855e9cd1aeSAssar Westerlund else if(S_ISWHT(st->st_mode)) {
186b528cefcSMark Murray file->mode[0] = 'w';
1875e9cd1aeSAssar Westerlund file_type = '%';
1885e9cd1aeSAssar Westerlund }
189b528cefcSMark Murray #endif
190b528cefcSMark Murray else
191b528cefcSMark Murray file->mode[0] = '?';
192b528cefcSMark Murray {
193b528cefcSMark Murray char *x[] = { "---", "--x", "-w-", "-wx",
194b528cefcSMark Murray "r--", "r-x", "rw-", "rwx" };
195b528cefcSMark Murray strcpy(file->mode + 1, x[(st->st_mode & S_IRWXU) >> 6]);
196b528cefcSMark Murray strcpy(file->mode + 4, x[(st->st_mode & S_IRWXG) >> 3]);
197b528cefcSMark Murray strcpy(file->mode + 7, x[(st->st_mode & S_IRWXO) >> 0]);
198b528cefcSMark Murray if((st->st_mode & S_ISUID)) {
199b528cefcSMark Murray if((st->st_mode & S_IXUSR))
200b528cefcSMark Murray file->mode[3] = 's';
201b528cefcSMark Murray else
202b528cefcSMark Murray file->mode[3] = 'S';
203b528cefcSMark Murray }
204b528cefcSMark Murray if((st->st_mode & S_ISGID)) {
205b528cefcSMark Murray if((st->st_mode & S_IXGRP))
206b528cefcSMark Murray file->mode[6] = 's';
207b528cefcSMark Murray else
208b528cefcSMark Murray file->mode[6] = 'S';
209b528cefcSMark Murray }
210b528cefcSMark Murray if((st->st_mode & S_ISTXT)) {
211b528cefcSMark Murray if((st->st_mode & S_IXOTH))
212b528cefcSMark Murray file->mode[9] = 't';
213b528cefcSMark Murray else
214b528cefcSMark Murray file->mode[9] = 'T';
215b528cefcSMark Murray }
216b528cefcSMark Murray }
217b528cefcSMark Murray file->n_link = st->st_nlink;
218b528cefcSMark Murray {
219b528cefcSMark Murray struct passwd *pwd;
220b528cefcSMark Murray pwd = getpwuid(st->st_uid);
221c19800e8SDoug Rabson if(pwd == NULL) {
222c19800e8SDoug Rabson if (asprintf(&file->user, "%u", (unsigned)st->st_uid) == -1)
223c19800e8SDoug Rabson file->user = NULL;
224c19800e8SDoug Rabson } else
225b528cefcSMark Murray file->user = strdup(pwd->pw_name);
226c19800e8SDoug Rabson if (file->user == NULL) {
227c19800e8SDoug Rabson syslog(LOG_ERR, "out of memory");
228c19800e8SDoug Rabson return -1;
229c19800e8SDoug Rabson }
230b528cefcSMark Murray }
231b528cefcSMark Murray {
232b528cefcSMark Murray struct group *grp;
233b528cefcSMark Murray grp = getgrgid(st->st_gid);
234c19800e8SDoug Rabson if(grp == NULL) {
235c19800e8SDoug Rabson if (asprintf(&file->group, "%u", (unsigned)st->st_gid) == -1)
236c19800e8SDoug Rabson file->group = NULL;
237c19800e8SDoug Rabson } else
238b528cefcSMark Murray file->group = strdup(grp->gr_name);
239c19800e8SDoug Rabson if (file->group == NULL) {
240c19800e8SDoug Rabson syslog(LOG_ERR, "out of memory");
241c19800e8SDoug Rabson return -1;
242c19800e8SDoug Rabson }
243b528cefcSMark Murray }
244b528cefcSMark Murray
245b528cefcSMark Murray if(S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
246b528cefcSMark Murray #if defined(major) && defined(minor)
247c19800e8SDoug Rabson if (asprintf(&file->major, "%u", (unsigned)major(st->st_rdev)) == -1)
248c19800e8SDoug Rabson file->major = NULL;
249c19800e8SDoug Rabson if (asprintf(&file->minor, "%u", (unsigned)minor(st->st_rdev)) == -1)
250c19800e8SDoug Rabson file->minor = NULL;
251b528cefcSMark Murray #else
252b528cefcSMark Murray /* Don't want to use the DDI/DKI crap. */
253c19800e8SDoug Rabson if (asprintf(&file->major, "%u", (unsigned)st->st_rdev) == -1)
254c19800e8SDoug Rabson file->major = NULL;
255c19800e8SDoug Rabson if (asprintf(&file->minor, "%u", 0) == -1)
256c19800e8SDoug Rabson file->minor = NULL;
257b528cefcSMark Murray #endif
258c19800e8SDoug Rabson if (file->major == NULL || file->minor == NULL) {
259c19800e8SDoug Rabson syslog(LOG_ERR, "out of memory");
260c19800e8SDoug Rabson return -1;
261c19800e8SDoug Rabson }
262c19800e8SDoug Rabson } else {
263c19800e8SDoug Rabson if (asprintf(&file->size, "%lu", (unsigned long)st->st_size) == -1)
264c19800e8SDoug Rabson file->size = NULL;
265c19800e8SDoug Rabson }
266b528cefcSMark Murray
267b528cefcSMark Murray {
268b528cefcSMark Murray time_t t = time(NULL);
2695e9cd1aeSAssar Westerlund time_t mtime = st->st_mtime;
2705e9cd1aeSAssar Westerlund struct tm *tm = localtime(&mtime);
2715e9cd1aeSAssar Westerlund if((t - mtime > 6*30*24*60*60) ||
2725e9cd1aeSAssar Westerlund (mtime - t > 6*30*24*60*60))
273b528cefcSMark Murray strftime(buf, sizeof(buf), "%b %e %Y", tm);
274b528cefcSMark Murray else
275b528cefcSMark Murray strftime(buf, sizeof(buf), "%b %e %H:%M", tm);
276b528cefcSMark Murray file->date = strdup(buf);
277c19800e8SDoug Rabson if (file->date == NULL) {
278c19800e8SDoug Rabson syslog(LOG_ERR, "out of memory");
279c19800e8SDoug Rabson return -1;
280c19800e8SDoug Rabson }
281b528cefcSMark Murray }
282b528cefcSMark Murray {
283b528cefcSMark Murray const char *p = strrchr(filename, '/');
284b528cefcSMark Murray if(p)
285b528cefcSMark Murray p++;
286b528cefcSMark Murray else
287b528cefcSMark Murray p = filename;
288c19800e8SDoug Rabson if((flags & LS_TYPE) && file_type != 0) {
289c19800e8SDoug Rabson if (asprintf(&file->filename, "%s%c", p, file_type) == -1)
290c19800e8SDoug Rabson file->filename = NULL;
291c19800e8SDoug Rabson } else
292b528cefcSMark Murray file->filename = strdup(p);
293c19800e8SDoug Rabson if (file->filename == NULL) {
294c19800e8SDoug Rabson syslog(LOG_ERR, "out of memory");
295c19800e8SDoug Rabson return -1;
296c19800e8SDoug Rabson }
297b528cefcSMark Murray }
298b528cefcSMark Murray if(S_ISLNK(st->st_mode)) {
299b528cefcSMark Murray int n;
300bbd80c28SJacques Vidrine n = readlink((char *)filename, buf, sizeof(buf) - 1);
301b528cefcSMark Murray if(n >= 0) {
302b528cefcSMark Murray buf[n] = '\0';
303b528cefcSMark Murray file->link = strdup(buf);
304c19800e8SDoug Rabson if (file->link == NULL) {
305c19800e8SDoug Rabson syslog(LOG_ERR, "out of memory");
306c19800e8SDoug Rabson return -1;
307c19800e8SDoug Rabson }
308b528cefcSMark Murray } else
3094137ff4cSJacques Vidrine sec_fprintf2(out, "readlink(%s): %s", filename, strerror(errno));
310b528cefcSMark Murray }
311c19800e8SDoug Rabson return 0;
312b528cefcSMark Murray }
313b528cefcSMark Murray
314b528cefcSMark Murray static void
print_file(FILE * out,int flags,struct fileinfo * f,int max_inode,int max_bsize,int max_n_link,int max_user,int max_group,int max_size,int max_major,int max_minor,int max_date)315b528cefcSMark Murray print_file(FILE *out,
316b528cefcSMark Murray int flags,
317b528cefcSMark Murray struct fileinfo *f,
318b528cefcSMark Murray int max_inode,
319b528cefcSMark Murray int max_bsize,
320b528cefcSMark Murray int max_n_link,
321b528cefcSMark Murray int max_user,
322b528cefcSMark Murray int max_group,
323b528cefcSMark Murray int max_size,
324b528cefcSMark Murray int max_major,
325b528cefcSMark Murray int max_minor,
326b528cefcSMark Murray int max_date)
327b528cefcSMark Murray {
328b528cefcSMark Murray if(f->filename == NULL)
329b528cefcSMark Murray return;
330b528cefcSMark Murray
331b528cefcSMark Murray if(flags & LS_INODE) {
332b528cefcSMark Murray sec_fprintf2(out, "%*d", max_inode, f->inode);
333b528cefcSMark Murray sec_fprintf2(out, " ");
334b528cefcSMark Murray }
335b528cefcSMark Murray if(flags & LS_SIZE) {
336b528cefcSMark Murray sec_fprintf2(out, "%*d", max_bsize, f->bsize);
337b528cefcSMark Murray sec_fprintf2(out, " ");
338b528cefcSMark Murray }
339b528cefcSMark Murray sec_fprintf2(out, "%s", f->mode);
340b528cefcSMark Murray sec_fprintf2(out, " ");
341b528cefcSMark Murray sec_fprintf2(out, "%*d", max_n_link, f->n_link);
342b528cefcSMark Murray sec_fprintf2(out, " ");
343b528cefcSMark Murray sec_fprintf2(out, "%-*s", max_user, f->user);
344b528cefcSMark Murray sec_fprintf2(out, " ");
345b528cefcSMark Murray sec_fprintf2(out, "%-*s", max_group, f->group);
346b528cefcSMark Murray sec_fprintf2(out, " ");
347b528cefcSMark Murray if(f->major != NULL && f->minor != NULL)
348b528cefcSMark Murray sec_fprintf2(out, "%*s, %*s", max_major, f->major, max_minor, f->minor);
349b528cefcSMark Murray else
350b528cefcSMark Murray sec_fprintf2(out, "%*s", max_size, f->size);
351b528cefcSMark Murray sec_fprintf2(out, " ");
352b528cefcSMark Murray sec_fprintf2(out, "%*s", max_date, f->date);
353b528cefcSMark Murray sec_fprintf2(out, " ");
354b528cefcSMark Murray sec_fprintf2(out, "%s", f->filename);
355b528cefcSMark Murray if(f->link)
356b528cefcSMark Murray sec_fprintf2(out, " -> %s", f->link);
357b528cefcSMark Murray sec_fprintf2(out, "\r\n");
358b528cefcSMark Murray }
359b528cefcSMark Murray
360b528cefcSMark Murray static int
compare_filename(struct fileinfo * a,struct fileinfo * b)361b528cefcSMark Murray compare_filename(struct fileinfo *a, struct fileinfo *b)
362b528cefcSMark Murray {
363b528cefcSMark Murray if(a->filename == NULL)
364b528cefcSMark Murray return 1;
365b528cefcSMark Murray if(b->filename == NULL)
366b528cefcSMark Murray return -1;
367b528cefcSMark Murray return strcmp(a->filename, b->filename);
368b528cefcSMark Murray }
369b528cefcSMark Murray
370b528cefcSMark Murray static int
compare_mtime(struct fileinfo * a,struct fileinfo * b)371b528cefcSMark Murray compare_mtime(struct fileinfo *a, struct fileinfo *b)
372b528cefcSMark Murray {
373b528cefcSMark Murray if(a->filename == NULL)
374b528cefcSMark Murray return 1;
375b528cefcSMark Murray if(b->filename == NULL)
376b528cefcSMark Murray return -1;
3775e9cd1aeSAssar Westerlund return b->st.st_mtime - a->st.st_mtime;
378b528cefcSMark Murray }
379b528cefcSMark Murray
380b528cefcSMark Murray static int
compare_size(struct fileinfo * a,struct fileinfo * b)381b528cefcSMark Murray compare_size(struct fileinfo *a, struct fileinfo *b)
382b528cefcSMark Murray {
383b528cefcSMark Murray if(a->filename == NULL)
384b528cefcSMark Murray return 1;
385b528cefcSMark Murray if(b->filename == NULL)
386b528cefcSMark Murray return -1;
3875e9cd1aeSAssar Westerlund return b->st.st_size - a->st.st_size;
388b528cefcSMark Murray }
389b528cefcSMark Murray
3908373020dSJacques Vidrine static int list_dir(FILE*, const char*, int);
391b528cefcSMark Murray
392b528cefcSMark Murray static int
find_log10(int num)393c19800e8SDoug Rabson find_log10(int num)
394b528cefcSMark Murray {
395b528cefcSMark Murray int i = 1;
396b528cefcSMark Murray while(num > 10) {
397b528cefcSMark Murray i++;
398b528cefcSMark Murray num /= 10;
399b528cefcSMark Murray }
400b528cefcSMark Murray return i;
401b528cefcSMark Murray }
402b528cefcSMark Murray
403b528cefcSMark Murray /*
404b528cefcSMark Murray * Operate as lstat but fake up entries for AFS mount points so we don't
405b528cefcSMark Murray * have to fetch them.
406b528cefcSMark Murray */
407b528cefcSMark Murray
408*ae771770SStanislav Sedov #ifdef KRB5
4095e9cd1aeSAssar Westerlund static int do_the_afs_dance = 1;
4105e9cd1aeSAssar Westerlund #endif
4115e9cd1aeSAssar Westerlund
412b528cefcSMark Murray static int
lstat_file(const char * file,struct stat * sb)413b528cefcSMark Murray lstat_file (const char *file, struct stat *sb)
414b528cefcSMark Murray {
415*ae771770SStanislav Sedov #ifdef KRB5
4165e9cd1aeSAssar Westerlund if (do_the_afs_dance &&
4175e9cd1aeSAssar Westerlund k_hasafs()
418b528cefcSMark Murray && strcmp(file, ".")
4195e9cd1aeSAssar Westerlund && strcmp(file, "..")
4205e9cd1aeSAssar Westerlund && strcmp(file, "/"))
421b528cefcSMark Murray {
422b528cefcSMark Murray struct ViceIoctl a_params;
4235e9cd1aeSAssar Westerlund char *dir, *last;
424b528cefcSMark Murray char *path_bkp;
425b528cefcSMark Murray static ino_t ino_counter = 0, ino_last = 0;
426b528cefcSMark Murray int ret;
427b528cefcSMark Murray const int maxsize = 2048;
428b528cefcSMark Murray
429b528cefcSMark Murray path_bkp = strdup (file);
430b528cefcSMark Murray if (path_bkp == NULL)
431b528cefcSMark Murray return -1;
432b528cefcSMark Murray
433b528cefcSMark Murray a_params.out = malloc (maxsize);
434b528cefcSMark Murray if (a_params.out == NULL) {
435b528cefcSMark Murray free (path_bkp);
436b528cefcSMark Murray return -1;
437b528cefcSMark Murray }
438b528cefcSMark Murray
439b528cefcSMark Murray /* If path contains more than the filename alone - split it */
440b528cefcSMark Murray
441b528cefcSMark Murray last = strrchr (path_bkp, '/');
442b528cefcSMark Murray if (last != NULL) {
4435e9cd1aeSAssar Westerlund if(last[1] == '\0')
4445e9cd1aeSAssar Westerlund /* if path ended in /, replace with `.' */
4455e9cd1aeSAssar Westerlund a_params.in = ".";
4465e9cd1aeSAssar Westerlund else
447b528cefcSMark Murray a_params.in = last + 1;
4485e9cd1aeSAssar Westerlund while(last > path_bkp && *--last == '/');
4495e9cd1aeSAssar Westerlund if(*last != '/' || last != path_bkp) {
4505e9cd1aeSAssar Westerlund *++last = '\0';
4515e9cd1aeSAssar Westerlund dir = path_bkp;
452b528cefcSMark Murray } else
4535e9cd1aeSAssar Westerlund /* we got to the start, so this must be the root dir */
4545e9cd1aeSAssar Westerlund dir = "/";
4555e9cd1aeSAssar Westerlund } else {
4565e9cd1aeSAssar Westerlund /* file is relative to cdir */
4575e9cd1aeSAssar Westerlund dir = ".";
4585e9cd1aeSAssar Westerlund a_params.in = path_bkp;
4595e9cd1aeSAssar Westerlund }
460b528cefcSMark Murray
461b528cefcSMark Murray a_params.in_size = strlen (a_params.in) + 1;
462b528cefcSMark Murray a_params.out_size = maxsize;
463b528cefcSMark Murray
4645e9cd1aeSAssar Westerlund ret = k_pioctl (dir, VIOC_AFS_STAT_MT_PT, &a_params, 0);
465b528cefcSMark Murray free (a_params.out);
466b528cefcSMark Murray if (ret < 0) {
467b528cefcSMark Murray free (path_bkp);
468b528cefcSMark Murray
469b528cefcSMark Murray if (errno != EINVAL)
470b528cefcSMark Murray return ret;
471b528cefcSMark Murray else
472b528cefcSMark Murray /* if we get EINVAL this is probably not a mountpoint */
473b528cefcSMark Murray return lstat (file, sb);
474b528cefcSMark Murray }
475b528cefcSMark Murray
476b528cefcSMark Murray /*
477b528cefcSMark Murray * wow this was a mountpoint, lets cook the struct stat
478b528cefcSMark Murray * use . as a prototype
479b528cefcSMark Murray */
480b528cefcSMark Murray
4815e9cd1aeSAssar Westerlund ret = lstat (dir, sb);
482b528cefcSMark Murray free (path_bkp);
483b528cefcSMark Murray if (ret < 0)
484b528cefcSMark Murray return ret;
485b528cefcSMark Murray
486b528cefcSMark Murray if (ino_last == sb->st_ino)
487b528cefcSMark Murray ino_counter++;
488b528cefcSMark Murray else {
489b528cefcSMark Murray ino_last = sb->st_ino;
490b528cefcSMark Murray ino_counter = 0;
491b528cefcSMark Murray }
492b528cefcSMark Murray sb->st_ino += ino_counter;
493b528cefcSMark Murray sb->st_nlink = 3;
494b528cefcSMark Murray
495b528cefcSMark Murray return 0;
496b528cefcSMark Murray }
497*ae771770SStanislav Sedov #endif /* KRB5 */
498b528cefcSMark Murray return lstat (file, sb);
499b528cefcSMark Murray }
500b528cefcSMark Murray
5014137ff4cSJacques Vidrine #define IS_DOT_DOTDOT(X) ((X)[0] == '.' && ((X)[1] == '\0' || \
5024137ff4cSJacques Vidrine ((X)[1] == '.' && (X)[2] == '\0')))
5034137ff4cSJacques Vidrine
5048373020dSJacques Vidrine static int
list_files(FILE * out,const char ** files,int n_files,int flags)505b528cefcSMark Murray list_files(FILE *out, const char **files, int n_files, int flags)
506b528cefcSMark Murray {
507b528cefcSMark Murray struct fileinfo *fi;
508b528cefcSMark Murray int i;
5094137ff4cSJacques Vidrine int *dirs = NULL;
5104137ff4cSJacques Vidrine size_t total_blocks = 0;
5114137ff4cSJacques Vidrine int n_print = 0;
5128373020dSJacques Vidrine int ret = 0;
5138373020dSJacques Vidrine
5148373020dSJacques Vidrine if(n_files == 0)
5158373020dSJacques Vidrine return 0;
5164137ff4cSJacques Vidrine
5174137ff4cSJacques Vidrine if(n_files > 1)
5184137ff4cSJacques Vidrine flags |= LS_SHOW_DIRNAME;
519b528cefcSMark Murray
520b528cefcSMark Murray fi = calloc(n_files, sizeof(*fi));
521b528cefcSMark Murray if (fi == NULL) {
5228373020dSJacques Vidrine syslog(LOG_ERR, "out of memory");
5238373020dSJacques Vidrine return -1;
524b528cefcSMark Murray }
525b528cefcSMark Murray for(i = 0; i < n_files; i++) {
526b528cefcSMark Murray if(lstat_file(files[i], &fi[i].st) < 0) {
527b528cefcSMark Murray sec_fprintf2(out, "%s: %s\r\n", files[i], strerror(errno));
528b528cefcSMark Murray fi[i].filename = NULL;
529b528cefcSMark Murray } else {
5304137ff4cSJacques Vidrine int include_in_list = 1;
5314137ff4cSJacques Vidrine total_blocks += block_convert(fi[i].st.st_blocks);
5324137ff4cSJacques Vidrine if(S_ISDIR(fi[i].st.st_mode)) {
5334137ff4cSJacques Vidrine if(dirs == NULL)
5344137ff4cSJacques Vidrine dirs = calloc(n_files, sizeof(*dirs));
5354137ff4cSJacques Vidrine if(dirs == NULL) {
5368373020dSJacques Vidrine syslog(LOG_ERR, "%s: %m", files[i]);
5378373020dSJacques Vidrine ret = -1;
5384137ff4cSJacques Vidrine goto out;
5394137ff4cSJacques Vidrine }
5404137ff4cSJacques Vidrine dirs[i] = 1;
5414137ff4cSJacques Vidrine if((flags & LS_DIRS) == 0)
5424137ff4cSJacques Vidrine include_in_list = 0;
5434137ff4cSJacques Vidrine }
5444137ff4cSJacques Vidrine if(include_in_list) {
545c19800e8SDoug Rabson ret = make_fileinfo(out, files[i], &fi[i], flags);
546c19800e8SDoug Rabson if (ret)
547c19800e8SDoug Rabson goto out;
5484137ff4cSJacques Vidrine n_print++;
549b528cefcSMark Murray }
550b528cefcSMark Murray }
551b528cefcSMark Murray }
552b528cefcSMark Murray switch(SORT_MODE(flags)) {
553b528cefcSMark Murray case LS_SORT_NAME:
554b528cefcSMark Murray qsort(fi, n_files, sizeof(*fi),
555b528cefcSMark Murray (int (*)(const void*, const void*))compare_filename);
556b528cefcSMark Murray break;
557b528cefcSMark Murray case LS_SORT_MTIME:
558b528cefcSMark Murray qsort(fi, n_files, sizeof(*fi),
559b528cefcSMark Murray (int (*)(const void*, const void*))compare_mtime);
560b528cefcSMark Murray break;
561b528cefcSMark Murray case LS_SORT_SIZE:
562b528cefcSMark Murray qsort(fi, n_files, sizeof(*fi),
563b528cefcSMark Murray (int (*)(const void*, const void*))compare_size);
564b528cefcSMark Murray break;
565b528cefcSMark Murray }
5665e9cd1aeSAssar Westerlund if(DISP_MODE(flags) == LS_DISP_LONG) {
567b528cefcSMark Murray int max_inode = 0;
568b528cefcSMark Murray int max_bsize = 0;
569b528cefcSMark Murray int max_n_link = 0;
570b528cefcSMark Murray int max_user = 0;
571b528cefcSMark Murray int max_group = 0;
572b528cefcSMark Murray int max_size = 0;
573b528cefcSMark Murray int max_major = 0;
574b528cefcSMark Murray int max_minor = 0;
575b528cefcSMark Murray int max_date = 0;
576b528cefcSMark Murray for(i = 0; i < n_files; i++) {
577b528cefcSMark Murray if(fi[i].filename == NULL)
578b528cefcSMark Murray continue;
579b528cefcSMark Murray if(fi[i].inode > max_inode)
580b528cefcSMark Murray max_inode = fi[i].inode;
581b528cefcSMark Murray if(fi[i].bsize > max_bsize)
582b528cefcSMark Murray max_bsize = fi[i].bsize;
583b528cefcSMark Murray if(fi[i].n_link > max_n_link)
584b528cefcSMark Murray max_n_link = fi[i].n_link;
585b528cefcSMark Murray if(strlen(fi[i].user) > max_user)
586b528cefcSMark Murray max_user = strlen(fi[i].user);
587b528cefcSMark Murray if(strlen(fi[i].group) > max_group)
588b528cefcSMark Murray max_group = strlen(fi[i].group);
589b528cefcSMark Murray if(fi[i].major != NULL && strlen(fi[i].major) > max_major)
590b528cefcSMark Murray max_major = strlen(fi[i].major);
591b528cefcSMark Murray if(fi[i].minor != NULL && strlen(fi[i].minor) > max_minor)
592b528cefcSMark Murray max_minor = strlen(fi[i].minor);
593b528cefcSMark Murray if(fi[i].size != NULL && strlen(fi[i].size) > max_size)
594b528cefcSMark Murray max_size = strlen(fi[i].size);
595b528cefcSMark Murray if(strlen(fi[i].date) > max_date)
596b528cefcSMark Murray max_date = strlen(fi[i].date);
597b528cefcSMark Murray }
598b528cefcSMark Murray if(max_size < max_major + max_minor + 2)
599b528cefcSMark Murray max_size = max_major + max_minor + 2;
600b528cefcSMark Murray else if(max_size - max_minor - 2 > max_major)
601b528cefcSMark Murray max_major = max_size - max_minor - 2;
602c19800e8SDoug Rabson max_inode = find_log10(max_inode);
603c19800e8SDoug Rabson max_bsize = find_log10(max_bsize);
604c19800e8SDoug Rabson max_n_link = find_log10(max_n_link);
605b528cefcSMark Murray
6064137ff4cSJacques Vidrine if(n_print > 0)
6074137ff4cSJacques Vidrine sec_fprintf2(out, "total %lu\r\n", (unsigned long)total_blocks);
608b528cefcSMark Murray if(flags & LS_SORT_REVERSE)
609b528cefcSMark Murray for(i = n_files - 1; i >= 0; i--)
610b528cefcSMark Murray print_file(out,
611b528cefcSMark Murray flags,
612b528cefcSMark Murray &fi[i],
613b528cefcSMark Murray max_inode,
614b528cefcSMark Murray max_bsize,
615b528cefcSMark Murray max_n_link,
616b528cefcSMark Murray max_user,
617b528cefcSMark Murray max_group,
618b528cefcSMark Murray max_size,
619b528cefcSMark Murray max_major,
620b528cefcSMark Murray max_minor,
621b528cefcSMark Murray max_date);
622b528cefcSMark Murray else
623b528cefcSMark Murray for(i = 0; i < n_files; i++)
624b528cefcSMark Murray print_file(out,
625b528cefcSMark Murray flags,
626b528cefcSMark Murray &fi[i],
627b528cefcSMark Murray max_inode,
628b528cefcSMark Murray max_bsize,
629b528cefcSMark Murray max_n_link,
630b528cefcSMark Murray max_user,
631b528cefcSMark Murray max_group,
632b528cefcSMark Murray max_size,
633b528cefcSMark Murray max_major,
634b528cefcSMark Murray max_minor,
635b528cefcSMark Murray max_date);
6365e9cd1aeSAssar Westerlund } else if(DISP_MODE(flags) == LS_DISP_COLUMN ||
6375e9cd1aeSAssar Westerlund DISP_MODE(flags) == LS_DISP_CROSS) {
6385e9cd1aeSAssar Westerlund int max_len = 0;
6394137ff4cSJacques Vidrine int size_len = 0;
6405e9cd1aeSAssar Westerlund int num_files = n_files;
6415e9cd1aeSAssar Westerlund int columns;
6425e9cd1aeSAssar Westerlund int j;
6435e9cd1aeSAssar Westerlund for(i = 0; i < n_files; i++) {
6445e9cd1aeSAssar Westerlund if(fi[i].filename == NULL) {
6455e9cd1aeSAssar Westerlund num_files--;
6465e9cd1aeSAssar Westerlund continue;
6475e9cd1aeSAssar Westerlund }
6485e9cd1aeSAssar Westerlund if(strlen(fi[i].filename) > max_len)
6495e9cd1aeSAssar Westerlund max_len = strlen(fi[i].filename);
650c19800e8SDoug Rabson if(find_log10(fi[i].bsize) > size_len)
651c19800e8SDoug Rabson size_len = find_log10(fi[i].bsize);
6525e9cd1aeSAssar Westerlund }
6534137ff4cSJacques Vidrine if(num_files == 0)
6544137ff4cSJacques Vidrine goto next;
6554137ff4cSJacques Vidrine if(flags & LS_SIZE) {
6564137ff4cSJacques Vidrine columns = 80 / (size_len + 1 + max_len + 1);
6574137ff4cSJacques Vidrine max_len = 80 / columns - size_len - 1;
6584137ff4cSJacques Vidrine } else {
6595e9cd1aeSAssar Westerlund columns = 80 / (max_len + 1); /* get space between columns */
6605e9cd1aeSAssar Westerlund max_len = 80 / columns;
6614137ff4cSJacques Vidrine }
6624137ff4cSJacques Vidrine if(flags & LS_SIZE)
6634137ff4cSJacques Vidrine sec_fprintf2(out, "total %lu\r\n",
6644137ff4cSJacques Vidrine (unsigned long)total_blocks);
6655e9cd1aeSAssar Westerlund if(DISP_MODE(flags) == LS_DISP_CROSS) {
6665e9cd1aeSAssar Westerlund for(i = 0, j = 0; i < n_files; i++) {
6675e9cd1aeSAssar Westerlund if(fi[i].filename == NULL)
6685e9cd1aeSAssar Westerlund continue;
6694137ff4cSJacques Vidrine if(flags & LS_SIZE)
6704137ff4cSJacques Vidrine sec_fprintf2(out, "%*u %-*s", size_len, fi[i].bsize,
6714137ff4cSJacques Vidrine max_len, fi[i].filename);
6724137ff4cSJacques Vidrine else
6735e9cd1aeSAssar Westerlund sec_fprintf2(out, "%-*s", max_len, fi[i].filename);
6745e9cd1aeSAssar Westerlund j++;
6755e9cd1aeSAssar Westerlund if(j == columns) {
6765e9cd1aeSAssar Westerlund sec_fprintf2(out, "\r\n");
6775e9cd1aeSAssar Westerlund j = 0;
6785e9cd1aeSAssar Westerlund }
6795e9cd1aeSAssar Westerlund }
6805e9cd1aeSAssar Westerlund if(j > 0)
6815e9cd1aeSAssar Westerlund sec_fprintf2(out, "\r\n");
6825e9cd1aeSAssar Westerlund } else {
6835e9cd1aeSAssar Westerlund int skip = (num_files + columns - 1) / columns;
684*ae771770SStanislav Sedov
6855e9cd1aeSAssar Westerlund for(i = 0; i < skip; i++) {
6865e9cd1aeSAssar Westerlund for(j = i; j < n_files;) {
6875e9cd1aeSAssar Westerlund while(j < n_files && fi[j].filename == NULL)
6885e9cd1aeSAssar Westerlund j++;
6894137ff4cSJacques Vidrine if(flags & LS_SIZE)
6904137ff4cSJacques Vidrine sec_fprintf2(out, "%*u %-*s", size_len, fi[j].bsize,
6914137ff4cSJacques Vidrine max_len, fi[j].filename);
6924137ff4cSJacques Vidrine else
6935e9cd1aeSAssar Westerlund sec_fprintf2(out, "%-*s", max_len, fi[j].filename);
6945e9cd1aeSAssar Westerlund j += skip;
6955e9cd1aeSAssar Westerlund }
6965e9cd1aeSAssar Westerlund sec_fprintf2(out, "\r\n");
6975e9cd1aeSAssar Westerlund }
6985e9cd1aeSAssar Westerlund }
6995e9cd1aeSAssar Westerlund } else {
7005e9cd1aeSAssar Westerlund for(i = 0; i < n_files; i++) {
7015e9cd1aeSAssar Westerlund if(fi[i].filename == NULL)
7025e9cd1aeSAssar Westerlund continue;
7035e9cd1aeSAssar Westerlund sec_fprintf2(out, "%s\r\n", fi[i].filename);
7045e9cd1aeSAssar Westerlund }
7055e9cd1aeSAssar Westerlund }
7064137ff4cSJacques Vidrine next:
7074137ff4cSJacques Vidrine if(((flags & LS_DIRS) == 0 || (flags & LS_RECURSIVE)) && dirs != NULL) {
7084137ff4cSJacques Vidrine for(i = 0; i < n_files; i++) {
7094137ff4cSJacques Vidrine if(dirs[i]) {
7104137ff4cSJacques Vidrine const char *p = strrchr(files[i], '/');
7114137ff4cSJacques Vidrine if(p == NULL)
7124137ff4cSJacques Vidrine p = files[i];
7134137ff4cSJacques Vidrine else
7144137ff4cSJacques Vidrine p++;
7154137ff4cSJacques Vidrine if(!(flags & LS_DIR_FLAG) || !IS_DOT_DOTDOT(p)) {
7164137ff4cSJacques Vidrine if((flags & LS_SHOW_DIRNAME)) {
7174137ff4cSJacques Vidrine if ((flags & LS_EXTRA_BLANK))
7184137ff4cSJacques Vidrine sec_fprintf2(out, "\r\n");
7194137ff4cSJacques Vidrine sec_fprintf2(out, "%s:\r\n", files[i]);
7204137ff4cSJacques Vidrine }
7214137ff4cSJacques Vidrine list_dir(out, files[i], flags | LS_DIRS | LS_EXTRA_BLANK);
7224137ff4cSJacques Vidrine }
7234137ff4cSJacques Vidrine }
7244137ff4cSJacques Vidrine }
7254137ff4cSJacques Vidrine }
7264137ff4cSJacques Vidrine out:
727b528cefcSMark Murray for(i = 0; i < n_files; i++)
728b528cefcSMark Murray free_fileinfo(&fi[i]);
729b528cefcSMark Murray free(fi);
7304137ff4cSJacques Vidrine if(dirs != NULL)
7314137ff4cSJacques Vidrine free(dirs);
7328373020dSJacques Vidrine return ret;
733b528cefcSMark Murray }
734b528cefcSMark Murray
735b528cefcSMark Murray static void
free_files(char ** files,int n)736b528cefcSMark Murray free_files (char **files, int n)
737b528cefcSMark Murray {
738b528cefcSMark Murray int i;
739b528cefcSMark Murray
740b528cefcSMark Murray for (i = 0; i < n; ++i)
741b528cefcSMark Murray free (files[i]);
742b528cefcSMark Murray free (files);
743b528cefcSMark Murray }
744b528cefcSMark Murray
7454137ff4cSJacques Vidrine static int
hide_file(const char * filename,int flags)7464137ff4cSJacques Vidrine hide_file(const char *filename, int flags)
7474137ff4cSJacques Vidrine {
7484137ff4cSJacques Vidrine if(filename[0] != '.')
7494137ff4cSJacques Vidrine return 0;
7504137ff4cSJacques Vidrine if((flags & LS_IGNORE_DOT))
7514137ff4cSJacques Vidrine return 1;
7524137ff4cSJacques Vidrine if(filename[1] == '\0' || (filename[1] == '.' && filename[2] == '\0')) {
7534137ff4cSJacques Vidrine if((flags & LS_SHOW_ALL))
7544137ff4cSJacques Vidrine return 0;
7554137ff4cSJacques Vidrine else
7564137ff4cSJacques Vidrine return 1;
7574137ff4cSJacques Vidrine }
7584137ff4cSJacques Vidrine return 0;
7594137ff4cSJacques Vidrine }
7604137ff4cSJacques Vidrine
7618373020dSJacques Vidrine static int
list_dir(FILE * out,const char * directory,int flags)762b528cefcSMark Murray list_dir(FILE *out, const char *directory, int flags)
763b528cefcSMark Murray {
764b528cefcSMark Murray DIR *d = opendir(directory);
765b528cefcSMark Murray struct dirent *ent;
766b528cefcSMark Murray char **files = NULL;
767b528cefcSMark Murray int n_files = 0;
768c19800e8SDoug Rabson int ret;
769b528cefcSMark Murray
770b528cefcSMark Murray if(d == NULL) {
7718373020dSJacques Vidrine syslog(LOG_ERR, "%s: %m", directory);
7728373020dSJacques Vidrine return -1;
773b528cefcSMark Murray }
774b528cefcSMark Murray while((ent = readdir(d)) != NULL) {
775b528cefcSMark Murray void *tmp;
776b528cefcSMark Murray
7774137ff4cSJacques Vidrine if(hide_file(ent->d_name, flags))
778b528cefcSMark Murray continue;
779b528cefcSMark Murray tmp = realloc(files, (n_files + 1) * sizeof(*files));
780b528cefcSMark Murray if (tmp == NULL) {
7818373020dSJacques Vidrine syslog(LOG_ERR, "%s: out of memory", directory);
782b528cefcSMark Murray free_files (files, n_files);
783b528cefcSMark Murray closedir (d);
7848373020dSJacques Vidrine return -1;
785b528cefcSMark Murray }
786b528cefcSMark Murray files = tmp;
787c19800e8SDoug Rabson ret = asprintf(&files[n_files], "%s/%s", directory, ent->d_name);
788c19800e8SDoug Rabson if (ret == -1) {
7898373020dSJacques Vidrine syslog(LOG_ERR, "%s: out of memory", directory);
790b528cefcSMark Murray free_files (files, n_files);
791b528cefcSMark Murray closedir (d);
7928373020dSJacques Vidrine return -1;
793b528cefcSMark Murray }
794b528cefcSMark Murray ++n_files;
795b528cefcSMark Murray }
796b528cefcSMark Murray closedir(d);
7978373020dSJacques Vidrine return list_files(out, (const char**)files, n_files, flags | LS_DIR_FLAG);
798b528cefcSMark Murray }
799b528cefcSMark Murray
8004137ff4cSJacques Vidrine static int
parse_flags(const char * options)8014137ff4cSJacques Vidrine parse_flags(const char *options)
802b528cefcSMark Murray {
8034137ff4cSJacques Vidrine #ifdef TEST
8044137ff4cSJacques Vidrine int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_COLUMN;
8054137ff4cSJacques Vidrine #else
8065e9cd1aeSAssar Westerlund int flags = LS_SORT_NAME | LS_IGNORE_DOT | LS_DISP_LONG;
8074137ff4cSJacques Vidrine #endif
808b528cefcSMark Murray
809b528cefcSMark Murray const char *p;
8104137ff4cSJacques Vidrine if(options == NULL || *options != '-')
8114137ff4cSJacques Vidrine return flags;
8124137ff4cSJacques Vidrine for(p = options + 1; *p; p++) {
813b528cefcSMark Murray switch(*p) {
8145e9cd1aeSAssar Westerlund case '1':
8155e9cd1aeSAssar Westerlund flags = (flags & ~LS_DISP_MODE);
8165e9cd1aeSAssar Westerlund break;
817b528cefcSMark Murray case 'a':
8184137ff4cSJacques Vidrine flags |= LS_SHOW_ALL;
8194137ff4cSJacques Vidrine /*FALLTHROUGH*/
820b528cefcSMark Murray case 'A':
821b528cefcSMark Murray flags &= ~LS_IGNORE_DOT;
822b528cefcSMark Murray break;
823b528cefcSMark Murray case 'C':
8245e9cd1aeSAssar Westerlund flags = (flags & ~LS_DISP_MODE) | LS_DISP_COLUMN;
825b528cefcSMark Murray break;
826b528cefcSMark Murray case 'd':
827b528cefcSMark Murray flags |= LS_DIRS;
828b528cefcSMark Murray break;
829b528cefcSMark Murray case 'f':
830b528cefcSMark Murray flags = (flags & ~LS_SORT_MODE);
831b528cefcSMark Murray break;
8325e9cd1aeSAssar Westerlund case 'F':
8335e9cd1aeSAssar Westerlund flags |= LS_TYPE;
8345e9cd1aeSAssar Westerlund break;
835b528cefcSMark Murray case 'i':
8365e9cd1aeSAssar Westerlund flags |= LS_INODE;
837b528cefcSMark Murray break;
838b528cefcSMark Murray case 'l':
8395e9cd1aeSAssar Westerlund flags = (flags & ~LS_DISP_MODE) | LS_DISP_LONG;
840b528cefcSMark Murray break;
8414137ff4cSJacques Vidrine case 'r':
8424137ff4cSJacques Vidrine flags |= LS_SORT_REVERSE;
8434137ff4cSJacques Vidrine break;
8444137ff4cSJacques Vidrine case 'R':
8454137ff4cSJacques Vidrine flags |= LS_RECURSIVE;
846b528cefcSMark Murray break;
847b528cefcSMark Murray case 's':
848b528cefcSMark Murray flags |= LS_SIZE;
849b528cefcSMark Murray break;
850b528cefcSMark Murray case 'S':
851b528cefcSMark Murray flags = (flags & ~LS_SORT_MODE) | LS_SORT_SIZE;
852b528cefcSMark Murray break;
8534137ff4cSJacques Vidrine case 't':
8544137ff4cSJacques Vidrine flags = (flags & ~LS_SORT_MODE) | LS_SORT_MTIME;
855b528cefcSMark Murray break;
8565e9cd1aeSAssar Westerlund case 'x':
8575e9cd1aeSAssar Westerlund flags = (flags & ~LS_DISP_MODE) | LS_DISP_CROSS;
8585e9cd1aeSAssar Westerlund break;
8594137ff4cSJacques Vidrine /* these are a bunch of unimplemented flags from BSD ls */
8604137ff4cSJacques Vidrine case 'k': /* display sizes in kB */
8614137ff4cSJacques Vidrine case 'c': /* last change time */
8624137ff4cSJacques Vidrine case 'L': /* list symlink target */
8634137ff4cSJacques Vidrine case 'm': /* stream output */
8644137ff4cSJacques Vidrine case 'o': /* BSD file flags */
8654137ff4cSJacques Vidrine case 'p': /* display / after directories */
8664137ff4cSJacques Vidrine case 'q': /* print non-graphic characters */
8674137ff4cSJacques Vidrine case 'u': /* use last access time */
8684137ff4cSJacques Vidrine case 'T': /* display complete time */
8694137ff4cSJacques Vidrine case 'W': /* include whiteouts */
8704137ff4cSJacques Vidrine break;
871b528cefcSMark Murray }
872b528cefcSMark Murray }
8734137ff4cSJacques Vidrine return flags;
8744137ff4cSJacques Vidrine }
8754137ff4cSJacques Vidrine
8768373020dSJacques Vidrine int
builtin_ls(FILE * out,const char * file)8774137ff4cSJacques Vidrine builtin_ls(FILE *out, const char *file)
8784137ff4cSJacques Vidrine {
8794137ff4cSJacques Vidrine int flags;
8808373020dSJacques Vidrine int ret;
8814137ff4cSJacques Vidrine
8824137ff4cSJacques Vidrine if(*file == '-') {
8834137ff4cSJacques Vidrine flags = parse_flags(file);
884b528cefcSMark Murray file = ".";
8854137ff4cSJacques Vidrine } else
8864137ff4cSJacques Vidrine flags = parse_flags("");
8874137ff4cSJacques Vidrine
8888373020dSJacques Vidrine ret = list_files(out, &file, 1, flags);
889b528cefcSMark Murray sec_fflush(out);
8908373020dSJacques Vidrine return ret;
891b528cefcSMark Murray }
892