print.c revision 61294
167754Smsmith/*
267754Smsmith * Copyright (c) 1989, 1993, 1994
367754Smsmith *	The Regents of the University of California.  All rights reserved.
477424Smsmith *
5114237Snjl * This code is derived from software contributed to Berkeley by
667754Smsmith * Michael Fischbein.
767754Smsmith *
867754Smsmith * Redistribution and use in source and binary forms, with or without
967754Smsmith * modification, are permitted provided that the following conditions
1067754Smsmith * are met:
1167754Smsmith * 1. Redistributions of source code must retain the above copyright
1267754Smsmith *    notice, this list of conditions and the following disclaimer.
13114237Snjl * 2. Redistributions in binary form must reproduce the above copyright
1470243Smsmith *    notice, this list of conditions and the following disclaimer in the
1567754Smsmith *    documentation and/or other materials provided with the distribution.
1667754Smsmith * 3. All advertising materials mentioning features or use of this software
1767754Smsmith *    must display the following acknowledgement:
1867754Smsmith *	This product includes software developed by the University of
1967754Smsmith *	California, Berkeley and its contributors.
2067754Smsmith * 4. Neither the name of the University nor the names of its contributors
2167754Smsmith *    may be used to endorse or promote products derived from this software
2267754Smsmith *    without specific prior written permission.
2367754Smsmith *
2467754Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2567754Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2667754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2767754Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2867754Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2967754Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3067754Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3167754Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3267754Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3367754Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3467754Smsmith * SUCH DAMAGE.
3567754Smsmith */
3667754Smsmith
3767754Smsmith#ifndef lint
3867754Smsmith#if 0
3967754Smsmithstatic char sccsid[] = "@(#)print.c	8.4 (Berkeley) 4/17/94";
4067754Smsmith#else
4167754Smsmithstatic const char rcsid[] =
4267754Smsmith  "$FreeBSD: head/bin/ls/print.c 61294 2000-06-05 20:08:50Z ache $";
4367754Smsmith#endif
4467754Smsmith#endif /* not lint */
4567754Smsmith
4667754Smsmith#include <sys/param.h>
4767754Smsmith#include <sys/stat.h>
4867754Smsmith
4967754Smsmith#include <err.h>
5067754Smsmith#include <errno.h>
5167754Smsmith#include <fts.h>
5267754Smsmith#include <grp.h>
5367754Smsmith#include <pwd.h>
5467754Smsmith#include <stdio.h>
5567754Smsmith#include <stdlib.h>
5667754Smsmith#include <string.h>
5767754Smsmith#include <time.h>
5867754Smsmith#include <unistd.h>
5967754Smsmith#ifdef COLORLS
6067754Smsmith#include <ctype.h>
6167754Smsmith#include <termcap.h>
6267754Smsmith#include <term.h>       /* for tparm */
6367754Smsmith#include <signal.h>
6467754Smsmith#endif
6567754Smsmith
6667754Smsmith#include "ls.h"
6767754Smsmith#include "extern.h"
6867754Smsmith
6967754Smsmithstatic int	printaname __P((FTSENT *, u_long, u_long));
7067754Smsmithstatic void	printlink __P((FTSENT *));
7167754Smsmithstatic void	printtime __P((time_t));
7267754Smsmithstatic int	printtype __P((u_int));
7367754Smsmith
7467754Smsmith#define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
7567754Smsmith
7667754Smsmith#ifdef COLORLS
7767754Smsmith/* Most of these are taken from <sys/stat.h> */
7867754Smsmithtypedef enum Colors {
7967754Smsmith    C_DIR,     /* directory */
8067754Smsmith    C_LNK,     /* symbolic link */
8167754Smsmith    C_SOCK,    /* socket */
8267754Smsmith    C_FIFO,    /* pipe */
8367754Smsmith    C_EXEC,    /* executable */
8467754Smsmith    C_BLK,     /* block special */
8567754Smsmith    C_CHR,     /* character special */
8667754Smsmith    C_SUID,    /* setuid executable */
8767754Smsmith    C_SGID,    /* setgid executable */
8867754Smsmith    C_WSDIR,   /* directory writeble to others, with sticky bit */
8967754Smsmith    C_WDIR,    /* directory writeble to others, without sticky bit */
9067754Smsmith    C_NUMCOLORS        /* just a place-holder */
9167754Smsmith} Colors ;
9267754Smsmith
9367754Smsmithchar *defcolors = "4x5x2x3x1x464301060203";
9467754Smsmith
9567754Smsmithstatic int colors[C_NUMCOLORS][2];
9667754Smsmith#endif
9767754Smsmith
9867754Smsmithvoid
9967754Smsmithprintscol(dp)
10067754Smsmith	DISPLAY *dp;
10167754Smsmith{
10267754Smsmith	FTSENT *p;
10367754Smsmith
10467754Smsmith	for (p = dp->list; p; p = p->fts_link) {
10567754Smsmith		if (IS_NOPRINT(p))
10667754Smsmith			continue;
10767754Smsmith		(void)printaname(p, dp->s_inode, dp->s_block);
10867754Smsmith		(void)putchar('\n');
10967754Smsmith	}
11067754Smsmith}
11167754Smsmith
11267754Smsmithvoid
11367754Smsmithprintlong(dp)
11467754Smsmith	DISPLAY *dp;
11567754Smsmith{
11667754Smsmith	struct stat *sp;
11767754Smsmith	FTSENT *p;
11877424Smsmith	NAMES *np;
11967754Smsmith	char buf[20];
12067754Smsmith#ifdef COLORLS
12167754Smsmith	int color_printed = 0;
12267754Smsmith#endif
12367754Smsmith
12467754Smsmith	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
12567754Smsmith		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
12677424Smsmith
12791116Smsmith	for (p = dp->list; p; p = p->fts_link) {
12867754Smsmith		if (IS_NOPRINT(p))
12967754Smsmith			continue;
13067754Smsmith		sp = p->fts_statp;
13167754Smsmith		if (f_inode)
13277424Smsmith			(void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
13369746Smsmith		if (f_size)
13469746Smsmith			(void)printf("%*qd ",
13569746Smsmith			    dp->s_block, howmany(sp->st_blocks, blocksize));
13669746Smsmith		(void)strmode(sp->st_mode, buf);
13769746Smsmith		np = p->fts_pointer;
13869746Smsmith		(void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
13969746Smsmith		    sp->st_nlink, dp->s_user, np->user, dp->s_group,
14069746Smsmith		    np->group);
14169746Smsmith		if (f_flags)
14269746Smsmith			(void)printf("%-*s ", dp->s_flags, np->flags);
14369746Smsmith		if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
14469746Smsmith			if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
14577424Smsmith				(void)printf("%3d, 0x%08x ",
14669746Smsmith				    major(sp->st_rdev),
14769746Smsmith				    (u_int)minor(sp->st_rdev));
14869746Smsmith			else
14969746Smsmith				(void)printf("%3d, %3d ",
15091116Smsmith				    major(sp->st_rdev), minor(sp->st_rdev));
15169746Smsmith		else if (dp->bcfile)
15283174Smsmith			(void)printf("%*s%*qd ",
15369746Smsmith			    8 - dp->s_size, "", dp->s_size, sp->st_size);
15469746Smsmith		else
15569746Smsmith			(void)printf("%*qd ", dp->s_size, sp->st_size);
15669746Smsmith		if (f_accesstime)
15769746Smsmith			printtime(sp->st_atime);
15869746Smsmith		else if (f_statustime)
15969746Smsmith			printtime(sp->st_ctime);
160107325Siwasaki		else
16199679Siwasaki			printtime(sp->st_mtime);
16299679Siwasaki#ifdef COLORLS
16399679Siwasaki		if (f_color)
16499679Siwasaki			color_printed = colortype(sp->st_mode);
16599679Siwasaki#endif
16699679Siwasaki		if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name);
16799679Siwasaki		else (void)printf("%s", p->fts_name);
16899679Siwasaki#ifdef COLORLS
16999679Siwasaki		if (f_color && color_printed)
17099679Siwasaki			endcolor();
17199679Siwasaki#endif
17299679Siwasaki		if (f_type)
17399679Siwasaki			(void)printtype(sp->st_mode);
17469746Smsmith		if (S_ISLNK(sp->st_mode))
17569746Smsmith			printlink(p);
17699146Siwasaki		(void)putchar('\n');
17782367Smsmith	}
17877424Smsmith}
17977424Smsmith
18069746Smsmithvoid
18169746Smsmithprintcol(dp)
18269746Smsmith	DISPLAY *dp;
18369746Smsmith{
18469746Smsmith	extern int termwidth;
18569746Smsmith	static FTSENT **array;
18669746Smsmith	static int lastentries = -1;
18769746Smsmith	FTSENT *p;
18869746Smsmith	int base, chcnt, cnt, col, colwidth, num;
18969746Smsmith	int endcol, numcols, numrows, row;
19077424Smsmith	int tabwidth;
19167754Smsmith
19291116Smsmith	if (f_notabs)
19391116Smsmith		tabwidth = 1;
19491116Smsmith	else
19599679Siwasaki		tabwidth = 8;
19667754Smsmith
19767754Smsmith	/*
19867754Smsmith	 * Have to do random access in the linked list -- build a table
19991116Smsmith	 * of pointers.
20091116Smsmith	 */
20167754Smsmith	if (dp->entries > lastentries) {
20299679Siwasaki		lastentries = dp->entries;
203102550Siwasaki		if ((array =
204102550Siwasaki		    realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
20599679Siwasaki			warn(NULL);
20667754Smsmith			printscol(dp);
20767754Smsmith		}
20867754Smsmith	}
20967754Smsmith	for (p = dp->list, num = 0; p; p = p->fts_link)
21077424Smsmith		if (p->fts_number != NO_PRINT)
21167754Smsmith			array[num++] = p;
21267754Smsmith
21367754Smsmith	colwidth = dp->maxlen;
21467754Smsmith	if (f_inode)
21567754Smsmith		colwidth += dp->s_inode + 1;
21667754Smsmith	if (f_size)
21767754Smsmith		colwidth += dp->s_block + 1;
21877424Smsmith	if (f_type)
21967754Smsmith		colwidth += 1;
22083174Smsmith
22167754Smsmith	colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
22269746Smsmith	if (termwidth < 2 * colwidth) {
22367754Smsmith		printscol(dp);
22467754Smsmith		return;
22591116Smsmith	}
22667754Smsmith
22767754Smsmith	numcols = termwidth / colwidth;
22867754Smsmith	numrows = num / numcols;
22985756Smsmith	if (num % numcols)
23067754Smsmith		++numrows;
23167754Smsmith
23267754Smsmith	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
23367754Smsmith		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
23467754Smsmith	for (row = 0; row < numrows; ++row) {
23567754Smsmith		endcol = colwidth;
23667754Smsmith		for (base = row, chcnt = col = 0; col < numcols; ++col) {
23783174Smsmith			chcnt += printaname(array[base], dp->s_inode,
23877424Smsmith			    dp->s_block);
23969746Smsmith			if ((base += numrows) >= num)
24069746Smsmith				break;
24167754Smsmith#ifdef COLORLS
24267754Smsmith			/*
24399146Siwasaki			 * some terminals get confused if we mix tabs
24499146Siwasaki			 * with color sequences
24567754Smsmith			 */
24677424Smsmith			if (f_color)
24777424Smsmith				while ((cnt = (chcnt + 1)) <= endcol) {
24867754Smsmith					(void)putchar(' ');
24977424Smsmith					chcnt = cnt;
25077424Smsmith				}
25177424Smsmith			else
25267754Smsmith#endif
25367754Smsmith			while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
25467754Smsmith			    <= endcol){
25567754Smsmith				(void)putchar(f_notabs ? ' ' : '\t');
25667754Smsmith				chcnt = cnt;
25785756Smsmith			}
25877424Smsmith			endcol += colwidth;
25969746Smsmith		}
26069746Smsmith		(void)putchar('\n');
26167754Smsmith	}
26267754Smsmith}
26367754Smsmith
26467754Smsmith/*
26567754Smsmith * print [inode] [size] name
26667754Smsmith * return # of characters printed, no trailing characters.
26767754Smsmith */
26867754Smsmithstatic int
26991116Smsmithprintaname(p, inodefield, sizefield)
27067754Smsmith	FTSENT *p;
27191116Smsmith	u_long sizefield, inodefield;
27291116Smsmith{
27367754Smsmith	struct stat *sp;
27467754Smsmith	int chcnt;
27567754Smsmith#ifdef COLORLS
27691116Smsmith	int color_printed = 0;
27767754Smsmith#endif
27891116Smsmith
27999679Siwasaki	sp = p->fts_statp;
28091116Smsmith	chcnt = 0;
28167754Smsmith	if (f_inode)
28267754Smsmith		chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
28399679Siwasaki	if (f_size)
28467754Smsmith		chcnt += printf("%*qd ",
28567754Smsmith		    (int)sizefield, howmany(sp->st_blocks, blocksize));
28667754Smsmith#ifdef COLORLS
287107325Siwasaki	if (f_color)
28867754Smsmith		color_printed = colortype(sp->st_mode);
28982367Smsmith#endif
29067754Smsmith	chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name)
29169746Smsmith	                                     : printf("%s", p->fts_name);
29269746Smsmith#ifdef COLORLS
29367754Smsmith	if (f_color && color_printed)
29467754Smsmith		endcolor();
295107325Siwasaki#endif
29667754Smsmith	if (f_type)
29767754Smsmith		chcnt += printtype(sp->st_mode);
29867754Smsmith	return (chcnt);
29967754Smsmith}
30067754Smsmith
30185756Smsmithstatic void
30267754Smsmithprinttime(ftime)
30367754Smsmith	time_t ftime;
30467754Smsmith{
30567754Smsmith	int i;
30677424Smsmith	char longstring[80];
30767754Smsmith	static time_t now;
30867754Smsmith
30967754Smsmith	if (now == 0)
31067754Smsmith		now = time(NULL);
311100966Siwasaki
31267754Smsmith	strftime(longstring, sizeof(longstring), "%c", localtime(&ftime));
31367754Smsmith	for (i = 4; i < 11; ++i)
31467754Smsmith		(void)putchar(longstring[i]);
31599146Siwasaki
31682367Smsmith#define	SIXMONTHS	((365 / 2) * 86400)
31767754Smsmith	if (f_sectime)
31867754Smsmith		for (i = 11; i < 24; i++)
31967754Smsmith			(void)putchar(longstring[i]);
32091116Smsmith	else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
32199679Siwasaki		for (i = 11; i < 16; ++i)
32277424Smsmith			(void)putchar(longstring[i]);
32367754Smsmith	else {
32469746Smsmith		(void)putchar(' ');
32567754Smsmith		for (i = 20; i < 24; ++i)
32667754Smsmith			(void)putchar(longstring[i]);
32791116Smsmith	}
32867754Smsmith	(void)putchar(' ');
32991116Smsmith}
33091116Smsmith
33191116Smsmithstatic int
33267754Smsmithprinttype(mode)
33367754Smsmith	u_int mode;
33482367Smsmith{
33582367Smsmith	switch (mode & S_IFMT) {
33691116Smsmith	case S_IFDIR:
33767754Smsmith		(void)putchar('/');
33869746Smsmith		return (1);
33967754Smsmith	case S_IFIFO:
34067754Smsmith		(void)putchar('|');
34167754Smsmith		return (1);
34267754Smsmith	case S_IFLNK:
34369746Smsmith		(void)putchar('@');
34467754Smsmith		return (1);
34567754Smsmith	case S_IFSOCK:
34667754Smsmith		(void)putchar('=');
34767754Smsmith		return (1);
34869746Smsmith	case S_IFWHT:
34970243Smsmith		(void)putchar('%');
35070243Smsmith		return (1);
35169746Smsmith	}
35267754Smsmith	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
35367754Smsmith		(void)putchar('*');
35491116Smsmith		return (1);
35567754Smsmith	}
35699679Siwasaki	return (0);
35791116Smsmith}
35891116Smsmith
35991116Smsmith#ifdef COLORLS
36091116Smsmithint putch(c)
36191116Smsmith	int c;
36291116Smsmith{
36391116Smsmith	return putc(c, stdout);
36491116Smsmith}
36591116Smsmith
36691116Smsmith
36799679Siwasakivoid
36891116Smsmithprintcolor(c)
36991116Smsmith       Colors c;
37071867Smsmith{
37171867Smsmith	char *ansiseq;
37271867Smsmith
37391116Smsmith	if (colors[c][0] != -1) {
37471867Smsmith		ansiseq = tparm(ansi_fgcol, colors[c][0]);
37591116Smsmith		if (ansiseq)
37667754Smsmith			tputs(ansiseq, 1, putch);
377107325Siwasaki	}
37867754Smsmith
37991116Smsmith	if (colors[c][1] != -1) {
38067754Smsmith		ansiseq = tparm(ansi_bgcol, colors[c][1]);
38169746Smsmith		if (ansiseq)
38267754Smsmith			tputs(ansiseq, 1, putch);
38367754Smsmith	}
384107325Siwasaki}
38569746Smsmith
38669746Smsmithvoid
38767754Smsmithendcolor()
38869746Smsmith{
38967754Smsmith	tputs(ansi_coloff, 1, putch);
39067754Smsmith}
39177424Smsmith
39267754Smsmithint
39367754Smsmithcolortype(mode)
39467754Smsmith       mode_t mode;
39567754Smsmith{
39667754Smsmith	switch(mode & S_IFMT) {
39777424Smsmith	      case S_IFDIR:
39877424Smsmith		if (mode & S_IWOTH)
39977424Smsmith		    if (mode & S_ISTXT)
40067754Smsmith			printcolor(C_WSDIR);
40169746Smsmith		    else
40267754Smsmith			printcolor(C_WDIR);
40367754Smsmith		else
40469746Smsmith		    printcolor(C_DIR);
40567754Smsmith		return(1);
40669746Smsmith	      case S_IFLNK:
40769746Smsmith		printcolor(C_LNK);
40869746Smsmith		return(1);
40969746Smsmith	      case S_IFSOCK:
41069746Smsmith		printcolor(C_SOCK);
41169746Smsmith		return(1);
41269746Smsmith	      case S_IFIFO:
413107325Siwasaki		printcolor(C_FIFO);
41477424Smsmith		return(1);
41567754Smsmith	      case S_IFBLK:
41669746Smsmith		printcolor(C_BLK);
41767754Smsmith		return(1);
41867754Smsmith	      case S_IFCHR:
41999679Siwasaki		printcolor(C_CHR);
42099679Siwasaki		return(1);
42199679Siwasaki	}
42299679Siwasaki	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
42369746Smsmith		if (mode & S_ISUID)
42467754Smsmith		    printcolor(C_SUID);
42567754Smsmith		else if (mode & S_ISGID)
42669746Smsmith		    printcolor(C_SGID);
42769746Smsmith		else
42869746Smsmith		    printcolor(C_EXEC);
42977424Smsmith		return(1);
43069746Smsmith	}
43169746Smsmith	return(0);
43269746Smsmith}
43369746Smsmith
43467754Smsmithvoid
435104470Siwasakiparsecolors(cs)
436104470Siwasakichar *cs;
437104470Siwasaki{
438104470Siwasaki	int i, j, len;
43969746Smsmith	char c[2];
44069746Smsmith	if (cs == NULL)    cs = ""; /* LSCOLORS not set */
44169746Smsmith	len = strlen(cs);
44269746Smsmith	for (i = 0 ; i < C_NUMCOLORS ; i++) {
44369746Smsmith		if (len <= 2*i) {
44469746Smsmith			c[0] = defcolors[2*i];
44569746Smsmith			c[1] = defcolors[2*i+1];
44669746Smsmith		}
44769746Smsmith		else {
44867754Smsmith			c[0] = cs[2*i];
44967754Smsmith			c[1] = cs[2*i+1];
45067754Smsmith		}
45167754Smsmith		for (j = 0 ; j < 2 ; j++) {
45269746Smsmith			if ((c[j] < '0' || c[j] > '7') &&
45367754Smsmith			    tolower((unsigned char)c[j]) != 'x') {
45467754Smsmith				fprintf(stderr,
45567754Smsmith					"error: invalid character '%c' in LSCOLORS env var\n",
45667754Smsmith					c[j]);
45767754Smsmith				c[j] = defcolors[2*i+j];
45867754Smsmith			}
45969746Smsmith			if (c[j] == 'x')
46067754Smsmith			    colors[i][j] = -1;
46167754Smsmith			else
46267754Smsmith			    colors[i][j] = c[j]-'0';
46367754Smsmith		}
46467754Smsmith	}
46567754Smsmith}
46669746Smsmith
46769746Smsmithvoid colorquit(sig)
46867754Smsmith	int sig;
46969746Smsmith{
47069746Smsmith	endcolor();
47169746Smsmith	fflush(stdout);
47269746Smsmith
47369746Smsmith	(void) signal(sig, SIG_DFL);
47467754Smsmith	(void) kill(getpid(), sig);
47567754Smsmith}
47667754Smsmith#endif /*COLORLS*/
47769746Smsmith
47869746Smsmithstatic void
47969746Smsmithprintlink(p)
48071867Smsmith	FTSENT *p;
48171867Smsmith{
48271867Smsmith	int lnklen;
48371867Smsmith	char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
48471867Smsmith
485104470Siwasaki	if (p->fts_level == FTS_ROOTLEVEL)
48671867Smsmith		(void)snprintf(name, sizeof(name), "%s", p->fts_name);
487104470Siwasaki	else
48871867Smsmith		(void)snprintf(name, sizeof(name),
48971867Smsmith		    "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
49071867Smsmith	if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
49171867Smsmith		(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
49291116Smsmith		return;
49382367Smsmith	}
494104470Siwasaki	path[lnklen] = '\0';
49571867Smsmith	if (f_octal || f_octal_escape) {
49671867Smsmith	        (void)printf(" -> ");
49771867Smsmith	        (void)prn_octal(path);
49871867Smsmith	}
49971867Smsmith	else (void)printf(" -> %s", path);
50071867Smsmith}
50171867Smsmith