os161-1.99
 All Data Structures
ls.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <stdio.h>
00033 #include <unistd.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <err.h>
00037 
00038 /*
00039  * ls - list files.
00040  * Usage: ls [-adlRs] [files]
00041  *    -a   Show files whose names begin with a dot.
00042  *    -d   Don't list contents of directories specified on the command line.
00043  *    -l   Long format listing.
00044  *    -R   Recurse into subdirectories found.
00045  *    -s   (with -l) Show block counts.
00046  */
00047 
00048 /* Flags for which options we're using. */
00049 static int aopt=0;
00050 static int dopt=0;
00051 static int lopt=0;
00052 static int Ropt=0;
00053 static int sopt=0;
00054 
00055 /* Process an option character. */
00056 static
00057 void
00058 option(int ch)
00059 {
00060         switch (ch) {
00061                 case 'a': aopt=1; break;
00062                 case 'd': dopt=1; break;
00063                 case 'l': lopt=1; break;
00064                 case 'R': Ropt=1; break;
00065                 case 's': sopt=1; break;
00066                 default:
00067                         errx(1, "Unknown option -%c", ch);
00068         }
00069 }
00070 
00071 /*
00072  * Utility function to find the non-directory part of a pathname.
00073  */
00074 static
00075 const char *
00076 basename(const char *path)
00077 {
00078         const char *s;
00079 
00080         s = strrchr(path, '/');
00081         if (s) {
00082                 return s+1;
00083         }
00084         return path;
00085 }
00086 
00087 /*
00088  * Utility function to check if a name refers to a directory.
00089  */
00090 static
00091 int
00092 isdir(const char *path)
00093 {
00094         struct stat buf;
00095         int fd;
00096 
00097         /* Assume stat() may not be implemented; use fstat */
00098         fd = open(path, O_RDONLY);
00099         if (fd<0) {
00100                 err(1, "%s", path);
00101         }
00102         if (fstat(fd, &buf)<0) {
00103                 err(1, "%s: fstat", path);
00104         }
00105         close(fd);
00106 
00107         return S_ISDIR(buf.st_mode);
00108 }
00109 
00110 /*
00111  * When listing one of several subdirectories, show the name of the
00112  * directory.
00113  */
00114 static
00115 void
00116 printheader(const char *file)
00117 {
00118         /* No blank line before the first header */
00119         static int first=1;
00120         if (first) {
00121                 first = 0;
00122         }
00123         else {
00124                 printf("\n");
00125         }
00126         printf("%s:\n", file);
00127 }
00128 
00129 /*
00130  * Show a single file.
00131  * We don't do the neat multicolumn listing that Unix ls does.
00132  */
00133 static
00134 void
00135 print(const char *path)
00136 {
00137         struct stat statbuf;
00138         const char *file;
00139         int typech;
00140 
00141         if (lopt || sopt) {
00142                 int fd;
00143 
00144                 fd = open(path, O_RDONLY);
00145                 if (fd<0) {
00146                         err(1, "%s", path);
00147                 }
00148                 if (fstat(fd, &statbuf)<0) {
00149                         err(1, "%s: fstat", path);
00150                 }
00151                 close(fd);
00152         }
00153 
00154         file = basename(path);
00155 
00156         if (sopt) {
00157                 printf("%3d ", statbuf.st_blocks);
00158         }
00159 
00160         if (lopt) {
00161                 if (S_ISREG(statbuf.st_mode)) {
00162                         typech = '-';
00163                 }
00164                 else if (S_ISDIR(statbuf.st_mode)) {
00165                         typech = 'd';
00166                 }
00167                 else if (S_ISLNK(statbuf.st_mode)) {
00168                         typech = 'l';
00169                 }
00170                 else if (S_ISCHR(statbuf.st_mode)) {
00171                         typech = 'c';
00172                 }
00173                 else if (S_ISBLK(statbuf.st_mode)) {
00174                         typech = 'b';
00175                 }
00176                 else {
00177                         typech = '?';
00178                 }
00179 
00180                 printf("%crwx------ %2d root  %-8llu",
00181                        typech,
00182                        statbuf.st_nlink,
00183                        statbuf.st_size);
00184         }
00185         printf("%s\n", file);
00186 }
00187 
00188 /*
00189  * List a directory.
00190  */
00191 static
00192 void
00193 listdir(const char *path, int showheader)
00194 {
00195         int fd;
00196         char buf[1024];
00197         char newpath[1024];
00198         int len;
00199 
00200         if (showheader) {
00201                 printheader(path);
00202         }
00203 
00204         /*
00205          * Open it.
00206          */
00207         fd = open(path, O_RDONLY);
00208         if (fd<0) {
00209                 err(1, "%s", path);
00210         }
00211 
00212         /*
00213          * List the directory.
00214          */
00215         while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) {
00216                 buf[len] = 0;
00217 
00218                 /* Assemble the full name of the new item */
00219                 snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
00220 
00221                 if (aopt || buf[0]!='.') {
00222                         /* Print it */
00223                         print(newpath);
00224                 }
00225         }
00226         if (len<0) {
00227                 err(1, "%s: getdirentry", path);
00228         }
00229 
00230         /* Done */
00231         close(fd);
00232 }
00233 
00234 static
00235 void
00236 recursedir(const char *path)
00237 {
00238         int fd;
00239         char buf[1024];
00240         char newpath[1024];
00241         int len;
00242 
00243         /*
00244          * Open it.
00245          */
00246         fd = open(path, O_RDONLY);
00247         if (fd<0) {
00248                 err(1, "%s", path);
00249         }
00250 
00251         /*
00252          * List the directory.
00253          */
00254         while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) {
00255                 buf[len] = 0;
00256 
00257                 /* Assemble the full name of the new item */
00258                 snprintf(newpath, sizeof(newpath), "%s/%s", path, buf);
00259 
00260                 if (!aopt && buf[0]=='.') {
00261                         /* skip this one */
00262                         continue;
00263                 }
00264 
00265                 if (!strcmp(buf, ".") || !strcmp(buf, "..")) {
00266                         /* always skip these */
00267                         continue;
00268                 }
00269 
00270                 if (!isdir(newpath)) {
00271                         continue;
00272                 }
00273 
00274                 listdir(newpath, 1 /*showheader*/);
00275                 if (Ropt) {
00276                         recursedir(newpath);
00277                 }
00278         }
00279         if (len<0) {
00280                 err(1, "%s", path);
00281         }
00282 
00283         close(fd);
00284 }
00285 
00286 static
00287 void
00288 listitem(const char *path, int showheader)
00289 {
00290         if (!dopt && isdir(path)) {
00291                 listdir(path, showheader || Ropt);
00292                 if (Ropt) {
00293                         recursedir(path);
00294                 }
00295         }
00296         else {
00297                 print(path);
00298         }
00299 }
00300 
00301 int
00302 main(int argc, char *argv[])
00303 {
00304         int i,j, items=0;
00305 
00306         /*
00307          * Go through the arguments and count how many non-option args.
00308          */
00309         for (i=1; i<argc; i++) {
00310                 if (argv[i][0]!='-') {
00311                         items++;
00312                 }
00313         }
00314 
00315         /*
00316          * Now go through the options for real, processing them.
00317          */
00318         for (i=1; i<argc; i++) {
00319                 if (argv[i][0]=='-') {
00320                         /*
00321                          * This word is an option.
00322                          * Process all the option characters in it.
00323                          */
00324                         for (j=1; argv[i][j]; j++) {
00325                                 option(argv[i][j]);
00326                         }
00327                 }
00328                 else {
00329                         /*
00330                          * This word isn't an option; list it.
00331                          */
00332                         listitem(argv[i], items>1);
00333                 }
00334         }
00335 
00336         /*
00337          * If no filenames were specified to list, list the current
00338          * directory.
00339          */
00340         if (items==0) {
00341                 listitem(".", 0);
00342         }
00343 
00344         return 0;
00345 }
 All Data Structures