ls.c revision 40106
1130803Smarcel/*
2130803Smarcel * $Id: ls.c,v 1.4 1998/10/07 02:38:26 msmith Exp $
3130803Smarcel * From: $NetBSD: ls.c,v 1.3 1997/06/13 13:48:47 drochner Exp $
4130803Smarcel */
598944Sobrien
698944Sobrien/*
798944Sobrien * Copyright (c) 1993
898944Sobrien *	The Regents of the University of California.  All rights reserved.
998944Sobrien * Copyright (c) 1996
1098944Sobrien *	Matthias Drochner.  All rights reserved.
1198944Sobrien *
1298944Sobrien * Redistribution and use in source and binary forms, with or without
1398944Sobrien * modification, are permitted provided that the following conditions
1498944Sobrien * are met:
1598944Sobrien * 1. Redistributions of source code must retain the above copyright
1698944Sobrien *    notice, this list of conditions and the following disclaimer.
1798944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1898944Sobrien *    notice, this list of conditions and the following disclaimer in the
1998944Sobrien *    documentation and/or other materials provided with the distribution.
2098944Sobrien * 3. All advertising materials mentioning features or use of this software
2198944Sobrien *    must display the following acknowledgement:
2298944Sobrien *	This product includes software developed by the University of
2398944Sobrien *	California, Berkeley and its contributors.
2498944Sobrien * 4. Neither the name of the University nor the names of its contributors
2598944Sobrien *    may be used to endorse or promote products derived from this software
2698944Sobrien *    without specific prior written permission.
2798944Sobrien *
2898944Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2998944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3098944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3198944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3298944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3398944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3498944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3598944Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3698944Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3798944Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3898944Sobrien * SUCH DAMAGE.
3998944Sobrien */
4098944Sobrien
4198944Sobrien
4298944Sobrien#include <sys/param.h>
4398944Sobrien#include <ufs/ufs/dinode.h>
4498944Sobrien#include <ufs/ufs/dir.h>
4598944Sobrien
4698944Sobrien#include <stand.h>
4798944Sobrien#include <string.h>
4898944Sobrien
4998944Sobrien#include "bootstrap.h"
5098944Sobrien
51130803Smarcelstatic char typestr[] = "?fc?d?b? ?l?s?w";
52130803Smarcel
53130803Smarcelstatic int	ls_getdir(char **pathp);
54130803Smarcel
55130803SmarcelCOMMAND_SET(ls, "ls", "list files", command_ls);
56130803Smarcel
5798944Sobrienstatic int
5898944Sobriencommand_ls(int argc, char *argv[])
5998944Sobrien{
6098944Sobrien    int		fd;
6198944Sobrien    size_t	size;
6298944Sobrien    struct stat	sb;
6398944Sobrien    static char	dirbuf[DIRBLKSIZ];
6498944Sobrien    char	*buf, *path;
6598944Sobrien    char	lbuf[128];		/* one line */
6698944Sobrien    int		result, ch;
6798944Sobrien    int		verbose;
6898944Sobrien
6998944Sobrien    result = CMD_OK;
7098944Sobrien    fd = -1;
7198944Sobrien    verbose = 0;
7298944Sobrien    optind = 1;
7398944Sobrien    while ((ch = getopt(argc, argv, "l")) != -1) {
7498944Sobrien	switch(ch) {
75130803Smarcel	case 'l':
76130803Smarcel	    verbose = 1;
77130803Smarcel	    break;
78130803Smarcel	case '?':
7998944Sobrien	default:
8098944Sobrien	    /* getopt has already reported an error */
8198944Sobrien	    return(CMD_OK);
8298944Sobrien	}
8398944Sobrien    }
8498944Sobrien    argv += (optind - 1);
8598944Sobrien    argc -= (optind - 1);
8698944Sobrien
8798944Sobrien    if (argc < 2) {
8898944Sobrien	path = "";
89130803Smarcel    } else {
9098944Sobrien	path = argv[1];
91130803Smarcel    }
9298944Sobrien
9398944Sobrien    fd = ls_getdir(&path);
9498944Sobrien    if (fd == -1) {
9598944Sobrien	result = CMD_ERROR;
9698944Sobrien	goto out;
97130803Smarcel    }
9898944Sobrien    pager_open();
9998944Sobrien    pager_output(path);
10098944Sobrien    pager_output("\n");
10198944Sobrien
10298944Sobrien
10398944Sobrien    while ((size = read(fd, dirbuf, DIRBLKSIZ)) == DIRBLKSIZ) {
10498944Sobrien	struct direct  *dp, *edp;
10598944Sobrien
10698944Sobrien	dp = (struct direct *) dirbuf;
10798944Sobrien	edp = (struct direct *) (dirbuf + size);
10898944Sobrien
10998944Sobrien	while (dp < edp) {
11098944Sobrien	    if (dp->d_ino != (ino_t) 0) {
11198944Sobrien
11298944Sobrien		if ((dp->d_namlen > MAXNAMLEN + 1) || (dp->d_type > sizeof(typestr))) {
11398944Sobrien		    /*
11498944Sobrien		     * This does not handle "old"
11598944Sobrien		     * filesystems properly. On little
11698944Sobrien		     * endian machines, we get a bogus
117130803Smarcel		     * type name if the namlen matches a
118130803Smarcel		     * valid type identifier. We could
119130803Smarcel		     * check if we read namlen "0" and
120130803Smarcel		     * handle this case specially, if
121130803Smarcel		     * there were a pressing need...
122130803Smarcel		     */
123130803Smarcel		    command_errmsg = "bad dir entry";
124130803Smarcel		    result = CMD_ERROR;
12598944Sobrien		    goto out;
126130803Smarcel		}
127130803Smarcel
128130803Smarcel		if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
129130803Smarcel		    if (verbose) {
130130803Smarcel			/* stat the file, if possible */
131130803Smarcel			sb.st_size = 0;
132130803Smarcel			buf = malloc(strlen(path) + strlen(dp->d_name) + 2);
133130803Smarcel			sprintf(buf, "%s/%s", path, dp->d_name);
134130803Smarcel			/* ignore return, could be symlink, etc. */
135130803Smarcel			if (stat(buf, &sb))
136130803Smarcel			    sb.st_size = 0;
13798944Sobrien			free(buf);
13898944Sobrien			sprintf(lbuf, " %c %8d %s\n", typestr[dp->d_type], (int)sb.st_size, dp->d_name);
13998944Sobrien		    } else
14098944Sobrien			sprintf(lbuf, " %c  %s\n", typestr[dp->d_type], dp->d_name);
14198944Sobrien		    if (pager_output(lbuf))
14298944Sobrien			goto out;
14398944Sobrien		}
14498944Sobrien	    }
14598944Sobrien	    dp = (struct direct *) ((char *) dp + dp->d_reclen);
14698944Sobrien	}
14798944Sobrien    }
148130803Smarcel out:
149130803Smarcel    pager_close();
150130803Smarcel    if (fd != -1)
151130803Smarcel	close(fd);
15298944Sobrien    if (path != NULL)
153	free(path);
154    return(result);
155}
156
157/*
158 * Given (path) containing a vaguely reasonable path specification, return an fd
159 * on the directory, and an allocated copy of the path to the directory.
160 */
161static int
162ls_getdir(char **pathp)
163{
164    struct stat	sb;
165    int		fd;
166    char	*cp;
167    char	*path, *tail;
168
169    tail = NULL;
170    fd = -1;
171
172    /* one extra byte for a possible trailing slash required */
173    path = malloc(strlen(*pathp) + 2);
174    strcpy(path, *pathp);
175
176    /* Make sure the path is respectable to begin with */
177    if (archsw.arch_getdev(NULL, path, &cp)) {
178	sprintf(command_errbuf, "bad path '%s'", path);
179	goto out;
180    }
181
182    /* If there's no path on the device, assume '/' */
183    if (*cp == 0)
184	strcat(path, "/");
185
186    fd = open(path, O_RDONLY);
187    if (fd < 0) {
188	sprintf(command_errbuf, "open '%s' failed: %s", path, strerror(errno));
189	goto out;
190    }
191    if (fstat(fd, &sb) < 0) {
192	sprintf(command_errbuf, "stat failed: %s", strerror(errno));
193	goto out;
194    }
195    if (!S_ISDIR(sb.st_mode)) {
196	sprintf(command_errbuf, "%s: %s", path, strerror(ENOTDIR));
197	goto out;
198    }
199
200    *pathp = path;
201    return(fd);
202
203 out:
204    free(path);
205    *pathp = NULL;
206    if (fd != -1)
207	close(fd);
208    return(-1);
209}
210