root/user/bin/ls/ls.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. option
  2. basename
  3. isdir
  4. printheader
  5. print
  6. listdir
  7. recursedir
  8. listitem
  9. main

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 #include <sys/types.h>
  31 #include <sys/stat.h>
  32 #include <stdio.h>
  33 #include <unistd.h>
  34 #include <string.h>
  35 #include <errno.h>
  36 #include <err.h>
  37 
  38 /*
  39  * ls - list files.
  40  * Usage: ls [-adlRs] [files]
  41  *    -a   Show files whose names begin with a dot.
  42  *    -d   Don't list contents of directories specified on the command line.
  43  *    -l   Long format listing.
  44  *    -R   Recurse into subdirectories found.
  45  *    -s   (with -l) Show block counts.
  46  */
  47 
  48 /* Flags for which options we're using. */
  49 static int aopt=0;
  50 static int dopt=0;
  51 static int lopt=0;
  52 static int Ropt=0;
  53 static int sopt=0;
  54 
  55 /* Process an option character. */
  56 static
  57 void
  58 option(int ch)
  59 {
  60         switch (ch) {
  61                 case 'a': aopt=1; break;
  62                 case 'd': dopt=1; break;
  63                 case 'l': lopt=1; break;
  64                 case 'R': Ropt=1; break;
  65                 case 's': sopt=1; break;
  66                 default:
  67                         errx(1, "Unknown option -%c", ch);
  68         }
  69 }
  70 
  71 /*
  72  * Utility function to find the non-directory part of a pathname.
  73  */
  74 static
  75 const char *
  76 basename(const char *path)
  77 {
  78         const char *s;
  79 
  80         s = strrchr(path, '/');
  81         if (s) {
  82                 return s+1;
  83         }
  84         return path;
  85 }
  86 
  87 /*
  88  * Utility function to check if a name refers to a directory.
  89  */
  90 static
  91 int
  92 isdir(const char *path)
  93 {
  94         struct stat buf;
  95         int fd;
  96 
  97         /* Assume stat() may not be implemented; use fstat */
  98         fd = open(path, O_RDONLY);
  99         if (fd<0) {
 100                 err(1, "%s", path);
 101         }
 102         if (fstat(fd, &buf)<0) {
 103                 err(1, "%s: fstat", path);
 104         }
 105         close(fd);
 106 
 107         return S_ISDIR(buf.st_mode);
 108 }
 109 
 110 /*
 111  * When listing one of several subdirectories, show the name of the
 112  * directory.
 113  */
 114 static
 115 void
 116 printheader(const char *file)
 117 {
 118         /* No blank line before the first header */
 119         static int first=1;
 120         if (first) {
 121                 first = 0;
 122         }
 123         else {
 124                 printf("\n");
 125         }
 126         printf("%s:\n", file);
 127 }
 128 
 129 /*
 130  * Show a single file.
 131  * We don't do the neat multicolumn listing that Unix ls does.
 132  */
 133 static
 134 void
 135 print(const char *path)
 136 {
 137         struct stat statbuf;
 138         const char *file;
 139         int typech;
 140 
 141         if (lopt || sopt) {
 142                 int fd;
 143 
 144                 fd = open(path, O_RDONLY);
 145                 if (fd<0) {
 146                         err(1, "%s", path);
 147                 }
 148                 if (fstat(fd, &statbuf)<0) {
 149                         err(1, "%s: fstat", path);
 150                 }
 151                 close(fd);
 152         }
 153 
 154         file = basename(path);
 155 
 156         if (sopt) {
 157                 printf("%3d ", statbuf.st_blocks);
 158         }
 159 
 160         if (lopt) {
 161                 if (S_ISREG(statbuf.st_mode)) {
 162                         typech = '-';
 163                 }
 164                 else if (S_ISDIR(statbuf.st_mode)) {
 165                         typech = 'd';
 166                 }
 167                 else if (S_ISLNK(statbuf.st_mode)) {
 168                         typech = 'l';
 169                 }
 170                 else if (S_ISCHR(statbuf.st_mode)) {
 171                         typech = 'c';
 172                 }
 173                 else if (S_ISBLK(statbuf.st_mode)) {
 174                         typech = 'b';
 175                 }
 176                 else {
 177                         typech = '?';
 178                 }
 179 
 180                 printf("%crwx------ %2d root  %-8llu",
 181                        typech,
 182                        statbuf.st_nlink,
 183                        statbuf.st_size);
 184         }
 185         printf("%s\n", file);
 186 }
 187 
 188 /*
 189  * List a directory.
 190  */
 191 static
 192 void
 193 listdir(const char *path, int showheader)
 194 {
 195         int fd;
 196         char buf[1024];
 197         char newpath[1024];
 198         int len;
 199 
 200         if (showheader) {
 201                 printheader(path);
 202         }
 203 
 204         /*
 205          * Open it.
 206          */
 207         fd = open(path, O_RDONLY);
 208         if (fd<0) {
 209                 err(1, "%s", path);
 210         }
 211 
 212         /*
 213          * List the directory.
 214          */
 215         while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) {
 216                 buf[len] = 0;
 217 
 218                 /* Assemble the full name of the new item */
 219                 snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
 220 
 221                 if (aopt || buf[0]!='.') {
 222                         /* Print it */
 223                         print(newpath);
 224                 }
 225         }
 226         if (len<0) {
 227                 err(1, "%s: getdirentry", path);
 228         }
 229 
 230         /* Done */
 231         close(fd);
 232 }
 233 
 234 static
 235 void
 236 recursedir(const char *path)
 237 {
 238         int fd;
 239         char buf[1024];
 240         char newpath[1024];
 241         int len;
 242 
 243         /*
 244          * Open it.
 245          */
 246         fd = open(path, O_RDONLY);
 247         if (fd<0) {
 248                 err(1, "%s", path);
 249         }
 250 
 251         /*
 252          * List the directory.
 253          */
 254         while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) {
 255                 buf[len] = 0;
 256 
 257                 /* Assemble the full name of the new item */
 258                 snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
 259 
 260                 if (!aopt && buf[0]=='.') {
 261                         /* skip this one */
 262                         continue;
 263                 }
 264 
 265                 if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
 266                         /* always skip these */
 267                         continue;
 268                 }
 269 
 270                 if (!isdir(newpath)) {
 271                         continue;
 272                 }
 273 
 274                 listdir(newpath, 1 /*showheader*/);
 275                 if (Ropt) {
 276                         recursedir(newpath);
 277                 }
 278         }
 279         if (len<0) {
 280                 err(1, "%s", path);
 281         }
 282 
 283         close(fd);
 284 }
 285 
 286 static
 287 void
 288 listitem(const char *path, int showheader)
 289 {
 290         if (!dopt && isdir(path)) {
 291                 listdir(path, showheader || Ropt);
 292                 if (Ropt) {
 293                         recursedir(path);
 294                 }
 295         }
 296         else {
 297                 print(path);
 298         }
 299 }
 300 
 301 int
 302 main(int argc, char *argv[])
 303 {
 304         int i,j, items=0;
 305 
 306         /*
 307          * Go through the arguments and count how many non-option args.
 308          */
 309         for (i=1; i<argc; i++) {
 310                 if (argv[i][0]!='-') {
 311                         items++;
 312                 }
 313         }
 314 
 315         /*
 316          * Now go through the options for real, processing them.
 317          */
 318         for (i=1; i<argc; i++) {
 319                 if (argv[i][0]=='-') {
 320                         /*
 321                          * This word is an option.
 322                          * Process all the option characters in it.
 323                          */
 324                         for (j=1; argv[i][j]; j++) {
 325                                 option(argv[i][j]);
 326                         }
 327                 }
 328                 else {
 329                         /*
 330                          * This word isn't an option; list it.
 331                          */
 332                         listitem(argv[i], items>1);
 333                 }
 334         }
 335 
 336         /*
 337          * If no filenames were specified to list, list the current
 338          * directory.
 339          */
 340         if (items==0) {
 341                 listitem(".", 0);
 342         }
 343 
 344         return 0;
 345 }

/* [<][>][^][v][top][bottom][index][help] */