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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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