1  | 
     | 
     | 
    /*	$NetBSD: create.c,v 1.11 1996/09/05 09:24:19 mycroft Exp $	*/  | 
    
    
    2  | 
     | 
     | 
    /*	$OpenBSD: create.c,v 1.32 2016/08/16 16:41:46 krw Exp $	*/  | 
    
    
    3  | 
     | 
     | 
     | 
    
    
    4  | 
     | 
     | 
    /*-  | 
    
    
    5  | 
     | 
     | 
     * Copyright (c) 1989, 1993  | 
    
    
    6  | 
     | 
     | 
     *	The Regents of the University of California.  All rights reserved.  | 
    
    
    7  | 
     | 
     | 
     *  | 
    
    
    8  | 
     | 
     | 
     * Redistribution and use in source and binary forms, with or without  | 
    
    
    9  | 
     | 
     | 
     * modification, are permitted provided that the following conditions  | 
    
    
    10  | 
     | 
     | 
     * are met:  | 
    
    
    11  | 
     | 
     | 
     * 1. Redistributions of source code must retain the above copyright  | 
    
    
    12  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer.  | 
    
    
    13  | 
     | 
     | 
     * 2. Redistributions in binary form must reproduce the above copyright  | 
    
    
    14  | 
     | 
     | 
     *    notice, this list of conditions and the following disclaimer in the  | 
    
    
    15  | 
     | 
     | 
     *    documentation and/or other materials provided with the distribution.  | 
    
    
    16  | 
     | 
     | 
     * 3. Neither the name of the University nor the names of its contributors  | 
    
    
    17  | 
     | 
     | 
     *    may be used to endorse or promote products derived from this software  | 
    
    
    18  | 
     | 
     | 
     *    without specific prior written permission.  | 
    
    
    19  | 
     | 
     | 
     *  | 
    
    
    20  | 
     | 
     | 
     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND  | 
    
    
    21  | 
     | 
     | 
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  | 
    
    
    22  | 
     | 
     | 
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
    
    
    23  | 
     | 
     | 
     * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  | 
    
    
    24  | 
     | 
     | 
     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
    
    
    25  | 
     | 
     | 
     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  | 
    
    
    26  | 
     | 
     | 
     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  | 
    
    
    27  | 
     | 
     | 
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  | 
    
    
    28  | 
     | 
     | 
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  | 
    
    
    29  | 
     | 
     | 
     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  | 
    
    
    30  | 
     | 
     | 
     * SUCH DAMAGE.  | 
    
    
    31  | 
     | 
     | 
     */  | 
    
    
    32  | 
     | 
     | 
     | 
    
    
    33  | 
     | 
     | 
    #include <sys/stat.h>  | 
    
    
    34  | 
     | 
     | 
    #include <time.h>  | 
    
    
    35  | 
     | 
     | 
    #include <fcntl.h>  | 
    
    
    36  | 
     | 
     | 
    #include <fts.h>  | 
    
    
    37  | 
     | 
     | 
    #include <dirent.h>  | 
    
    
    38  | 
     | 
     | 
    #include <grp.h>  | 
    
    
    39  | 
     | 
     | 
    #include <pwd.h>  | 
    
    
    40  | 
     | 
     | 
    #include <errno.h>  | 
    
    
    41  | 
     | 
     | 
    #include <unistd.h>  | 
    
    
    42  | 
     | 
     | 
    #include <limits.h>  | 
    
    
    43  | 
     | 
     | 
    #include <stdio.h>  | 
    
    
    44  | 
     | 
     | 
    #include <stdarg.h>  | 
    
    
    45  | 
     | 
     | 
    #include <vis.h>  | 
    
    
    46  | 
     | 
     | 
    #include <md5.h>  | 
    
    
    47  | 
     | 
     | 
    #include <rmd160.h>  | 
    
    
    48  | 
     | 
     | 
    #include <sha1.h>  | 
    
    
    49  | 
     | 
     | 
    #include <sha2.h>  | 
    
    
    50  | 
     | 
     | 
    #include "mtree.h"  | 
    
    
    51  | 
     | 
     | 
    #include "extern.h"  | 
    
    
    52  | 
     | 
     | 
     | 
    
    
    53  | 
     | 
     | 
    #define	INDENTNAMELEN	15  | 
    
    
    54  | 
     | 
     | 
    #define	MAXLINELEN	80  | 
    
    
    55  | 
     | 
     | 
     | 
    
    
    56  | 
     | 
     | 
    extern u_int32_t crc_total;  | 
    
    
    57  | 
     | 
     | 
    extern int ftsoptions;  | 
    
    
    58  | 
     | 
     | 
    extern int dflag, iflag, nflag, sflag;  | 
    
    
    59  | 
     | 
     | 
    extern u_int keys;  | 
    
    
    60  | 
     | 
     | 
    extern char fullpath[PATH_MAX];  | 
    
    
    61  | 
     | 
     | 
     | 
    
    
    62  | 
     | 
     | 
    static gid_t gid;  | 
    
    
    63  | 
     | 
     | 
    static uid_t uid;  | 
    
    
    64  | 
     | 
     | 
    static mode_t mode;  | 
    
    
    65  | 
     | 
     | 
     | 
    
    
    66  | 
     | 
     | 
    static void	output(int, int *, const char *, ...)  | 
    
    
    67  | 
     | 
     | 
    		    __attribute__((__format__ (printf, 3, 4)));  | 
    
    
    68  | 
     | 
     | 
    static int	statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *);  | 
    
    
    69  | 
     | 
     | 
    static void	statf(int, FTSENT *);  | 
    
    
    70  | 
     | 
     | 
     | 
    
    
    71  | 
     | 
     | 
    void  | 
    
    
    72  | 
     | 
     | 
    cwalk(void)  | 
    
    
    73  | 
     | 
     | 
    { | 
    
    
    74  | 
     | 
     | 
    	FTS *t;  | 
    
    
    75  | 
     | 
     | 
    	FTSENT *p;  | 
    
    
    76  | 
     | 
     | 
    	time_t clock;  | 
    
    
    77  | 
     | 
     | 
    	char *argv[2], host[HOST_NAME_MAX+1];  | 
    
    
    78  | 
     | 
     | 
    	int indent = 0;  | 
    
    
    79  | 
     | 
     | 
     | 
    
    
    80  | 
     | 
     | 
    	(void)time(&clock);  | 
    
    
    81  | 
     | 
     | 
    	(void)gethostname(host, sizeof(host));  | 
    
    
    82  | 
     | 
     | 
    	(void)printf(  | 
    
    
    83  | 
     | 
     | 
    	    "#\t   user: %s\n#\tmachine: %s\n#\t   tree: %s\n#\t   date: %s",  | 
    
    
    84  | 
     | 
     | 
    	    getlogin(), host, fullpath, ctime(&clock));  | 
    
    
    85  | 
     | 
     | 
     | 
    
    
    86  | 
     | 
     | 
    	argv[0] = ".";  | 
    
    
    87  | 
     | 
     | 
    	argv[1] = NULL;  | 
    
    
    88  | 
     | 
     | 
    	if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)  | 
    
    
    89  | 
     | 
     | 
    		error("fts_open: %s", strerror(errno)); | 
    
    
    90  | 
     | 
     | 
    	while ((p = fts_read(t))) { | 
    
    
    91  | 
     | 
     | 
    		if (iflag)  | 
    
    
    92  | 
     | 
     | 
    			indent = p->fts_level * 4;  | 
    
    
    93  | 
     | 
     | 
    		switch(p->fts_info) { | 
    
    
    94  | 
     | 
     | 
    		case FTS_D:  | 
    
    
    95  | 
     | 
     | 
    			if (!dflag)  | 
    
    
    96  | 
     | 
     | 
    				(void)printf("\n"); | 
    
    
    97  | 
     | 
     | 
    			if (!nflag)  | 
    
    
    98  | 
     | 
     | 
    				(void)printf("# %s\n", p->fts_path); | 
    
    
    99  | 
     | 
     | 
    			statd(t, p, &uid, &gid, &mode);  | 
    
    
    100  | 
     | 
     | 
    			statf(indent, p);  | 
    
    
    101  | 
     | 
     | 
    			break;  | 
    
    
    102  | 
     | 
     | 
    		case FTS_DP:  | 
    
    
    103  | 
     | 
     | 
    			if (!nflag && (p->fts_level > 0))  | 
    
    
    104  | 
     | 
     | 
    				(void)printf("%*s# %s\n", indent, "", p->fts_path); | 
    
    
    105  | 
     | 
     | 
    			(void)printf("%*s..\n", indent, ""); | 
    
    
    106  | 
     | 
     | 
    			if (!dflag)  | 
    
    
    107  | 
     | 
     | 
    				(void)printf("\n"); | 
    
    
    108  | 
     | 
     | 
    			break;  | 
    
    
    109  | 
     | 
     | 
    		case FTS_DNR:  | 
    
    
    110  | 
     | 
     | 
    		case FTS_ERR:  | 
    
    
    111  | 
     | 
     | 
    		case FTS_NS:  | 
    
    
    112  | 
     | 
     | 
    			(void)fprintf(stderr, "mtree: %s: %s\n",  | 
    
    
    113  | 
     | 
     | 
    			    p->fts_path, strerror(p->fts_errno));  | 
    
    
    114  | 
     | 
     | 
    			break;  | 
    
    
    115  | 
     | 
     | 
    		default:  | 
    
    
    116  | 
     | 
     | 
    			if (!dflag)  | 
    
    
    117  | 
     | 
     | 
    				statf(indent, p);  | 
    
    
    118  | 
     | 
     | 
    			break;  | 
    
    
    119  | 
     | 
     | 
    		}  | 
    
    
    120  | 
     | 
     | 
    	}  | 
    
    
    121  | 
     | 
     | 
    	(void)fts_close(t);  | 
    
    
    122  | 
     | 
     | 
    	if (sflag && keys & F_CKSUM)  | 
    
    
    123  | 
     | 
     | 
    		(void)fprintf(stderr,  | 
    
    
    124  | 
     | 
     | 
    		    "mtree: %s checksum: %u\n", fullpath, crc_total);  | 
    
    
    125  | 
     | 
     | 
    }  | 
    
    
    126  | 
     | 
     | 
     | 
    
    
    127  | 
     | 
     | 
    static void  | 
    
    
    128  | 
     | 
     | 
    statf(int indent, FTSENT *p)  | 
    
    
    129  | 
     | 
     | 
    { | 
    
    
    130  | 
     | 
     | 
    	struct group *gr;  | 
    
    
    131  | 
     | 
     | 
    	struct passwd *pw;  | 
    
    
    132  | 
     | 
     | 
    	u_int32_t len, val;  | 
    
    
    133  | 
     | 
     | 
    	int fd, offset;  | 
    
    
    134  | 
     | 
     | 
    	char *name, *escaped_name;  | 
    
    
    135  | 
     | 
     | 
    	size_t esc_len;  | 
    
    
    136  | 
     | 
     | 
     | 
    
    
    137  | 
     | 
     | 
    	esc_len = p->fts_namelen * 4 + 1;  | 
    
    
    138  | 
     | 
     | 
    	escaped_name = malloc(esc_len);  | 
    
    
    139  | 
     | 
     | 
    	if (escaped_name == NULL)  | 
    
    
    140  | 
     | 
     | 
    		error("statf: %s", strerror(errno)); | 
    
    
    141  | 
     | 
     | 
    	strnvis(escaped_name, p->fts_name, esc_len,  | 
    
    
    142  | 
     | 
     | 
    	    VIS_WHITE | VIS_OCTAL | VIS_GLOB);  | 
    
    
    143  | 
     | 
     | 
     | 
    
    
    144  | 
     | 
     | 
    	if (iflag || S_ISDIR(p->fts_statp->st_mode))  | 
    
    
    145  | 
     | 
     | 
    		offset = printf("%*s%s", indent, "", escaped_name); | 
    
    
    146  | 
     | 
     | 
    	else  | 
    
    
    147  | 
     | 
     | 
    		offset = printf("%*s    %s", indent, "", escaped_name); | 
    
    
    148  | 
     | 
     | 
     | 
    
    
    149  | 
     | 
     | 
    	free(escaped_name);  | 
    
    
    150  | 
     | 
     | 
     | 
    
    
    151  | 
     | 
     | 
    	if (offset > (INDENTNAMELEN + indent))  | 
    
    
    152  | 
     | 
     | 
    		offset = MAXLINELEN;  | 
    
    
    153  | 
     | 
     | 
    	else  | 
    
    
    154  | 
     | 
     | 
    		offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); | 
    
    
    155  | 
     | 
     | 
     | 
    
    
    156  | 
     | 
     | 
    	if (!S_ISREG(p->fts_statp->st_mode) && !dflag)  | 
    
    
    157  | 
     | 
     | 
    		output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode));  | 
    
    
    158  | 
     | 
     | 
    	if (p->fts_statp->st_uid != uid) { | 
    
    
    159  | 
     | 
     | 
    		if (keys & F_UNAME) { | 
    
    
    160  | 
     | 
     | 
    			if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) { | 
    
    
    161  | 
     | 
     | 
    				output(indent, &offset, "uname=%s", pw->pw_name);  | 
    
    
    162  | 
     | 
     | 
    			} else { | 
    
    
    163  | 
     | 
     | 
    				error("could not get uname for uid=%u", | 
    
    
    164  | 
     | 
     | 
    				    p->fts_statp->st_uid);  | 
    
    
    165  | 
     | 
     | 
    			}  | 
    
    
    166  | 
     | 
     | 
    		}  | 
    
    
    167  | 
     | 
     | 
    		if (keys & F_UID)  | 
    
    
    168  | 
     | 
     | 
    			output(indent, &offset, "uid=%u", p->fts_statp->st_uid);  | 
    
    
    169  | 
     | 
     | 
    	}  | 
    
    
    170  | 
     | 
     | 
    	if (p->fts_statp->st_gid != gid) { | 
    
    
    171  | 
     | 
     | 
    		if (keys & F_GNAME) { | 
    
    
    172  | 
     | 
     | 
    			if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) { | 
    
    
    173  | 
     | 
     | 
    				output(indent, &offset, "gname=%s", gr->gr_name);  | 
    
    
    174  | 
     | 
     | 
    			} else { | 
    
    
    175  | 
     | 
     | 
    				error("could not get gname for gid=%u", | 
    
    
    176  | 
     | 
     | 
    				    p->fts_statp->st_gid);  | 
    
    
    177  | 
     | 
     | 
    			}  | 
    
    
    178  | 
     | 
     | 
    		}  | 
    
    
    179  | 
     | 
     | 
    		if (keys & F_GID)  | 
    
    
    180  | 
     | 
     | 
    			output(indent, &offset, "gid=%u", p->fts_statp->st_gid);  | 
    
    
    181  | 
     | 
     | 
    	}  | 
    
    
    182  | 
     | 
     | 
    	if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)  | 
    
    
    183  | 
     | 
     | 
    		output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS);  | 
    
    
    184  | 
     | 
     | 
    	if (keys & F_NLINK && p->fts_statp->st_nlink != 1)  | 
    
    
    185  | 
     | 
     | 
    		output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink);  | 
    
    
    186  | 
     | 
     | 
    	if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode))  | 
    
    
    187  | 
     | 
     | 
    		output(indent, &offset, "size=%lld",  | 
    
    
    188  | 
     | 
     | 
    		    (long long)p->fts_statp->st_size);  | 
    
    
    189  | 
     | 
     | 
    	if (keys & F_TIME)  | 
    
    
    190  | 
     | 
     | 
    		output(indent, &offset, "time=%lld.%ld",  | 
    
    
    191  | 
     | 
     | 
    		    (long long)p->fts_statp->st_mtimespec.tv_sec,  | 
    
    
    192  | 
     | 
     | 
    		    p->fts_statp->st_mtimespec.tv_nsec);  | 
    
    
    193  | 
     | 
     | 
    	if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { | 
    
    
    194  | 
     | 
     | 
    		if ((fd = open(p->fts_accpath, MTREE_O_FLAGS, 0)) < 0 ||  | 
    
    
    195  | 
     | 
     | 
    		    crc(fd, &val, &len))  | 
    
    
    196  | 
     | 
     | 
    			error("%s: %s", p->fts_accpath, strerror(errno)); | 
    
    
    197  | 
     | 
     | 
    		(void)close(fd);  | 
    
    
    198  | 
     | 
     | 
    		output(indent, &offset, "cksum=%u", val);  | 
    
    
    199  | 
     | 
     | 
    	}  | 
    
    
    200  | 
     | 
     | 
    	if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { | 
    
    
    201  | 
     | 
     | 
    		char *md5digest, buf[MD5_DIGEST_STRING_LENGTH];  | 
    
    
    202  | 
     | 
     | 
     | 
    
    
    203  | 
     | 
     | 
    		md5digest = MD5File(p->fts_accpath,buf);  | 
    
    
    204  | 
     | 
     | 
    		if (!md5digest)  | 
    
    
    205  | 
     | 
     | 
    			error("%s: %s", p->fts_accpath, strerror(errno)); | 
    
    
    206  | 
     | 
     | 
    		else  | 
    
    
    207  | 
     | 
     | 
    			output(indent, &offset, "md5digest=%s", md5digest);  | 
    
    
    208  | 
     | 
     | 
    	}  | 
    
    
    209  | 
     | 
     | 
    	if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { | 
    
    
    210  | 
     | 
     | 
    		char *rmd160digest, buf[RMD160_DIGEST_STRING_LENGTH];  | 
    
    
    211  | 
     | 
     | 
     | 
    
    
    212  | 
     | 
     | 
    		rmd160digest = RMD160File(p->fts_accpath,buf);  | 
    
    
    213  | 
     | 
     | 
    		if (!rmd160digest)  | 
    
    
    214  | 
     | 
     | 
    			error("%s: %s", p->fts_accpath, strerror(errno)); | 
    
    
    215  | 
     | 
     | 
    		else  | 
    
    
    216  | 
     | 
     | 
    			output(indent, &offset, "rmd160digest=%s", rmd160digest);  | 
    
    
    217  | 
     | 
     | 
    	}  | 
    
    
    218  | 
     | 
     | 
    	if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { | 
    
    
    219  | 
     | 
     | 
    		char *sha1digest, buf[SHA1_DIGEST_STRING_LENGTH];  | 
    
    
    220  | 
     | 
     | 
     | 
    
    
    221  | 
     | 
     | 
    		sha1digest = SHA1File(p->fts_accpath,buf);  | 
    
    
    222  | 
     | 
     | 
    		if (!sha1digest)  | 
    
    
    223  | 
     | 
     | 
    			error("%s: %s", p->fts_accpath, strerror(errno)); | 
    
    
    224  | 
     | 
     | 
    		else  | 
    
    
    225  | 
     | 
     | 
    			output(indent, &offset, "sha1digest=%s", sha1digest);  | 
    
    
    226  | 
     | 
     | 
    	}  | 
    
    
    227  | 
     | 
     | 
    	if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { | 
    
    
    228  | 
     | 
     | 
    		char *sha256digest, buf[SHA256_DIGEST_STRING_LENGTH];  | 
    
    
    229  | 
     | 
     | 
     | 
    
    
    230  | 
     | 
     | 
    		sha256digest = SHA256File(p->fts_accpath,buf);  | 
    
    
    231  | 
     | 
     | 
    		if (!sha256digest)  | 
    
    
    232  | 
     | 
     | 
    			error("%s: %s", p->fts_accpath, strerror(errno)); | 
    
    
    233  | 
     | 
     | 
    		else  | 
    
    
    234  | 
     | 
     | 
    			output(indent, &offset, "sha256digest=%s", sha256digest);  | 
    
    
    235  | 
     | 
     | 
    	}  | 
    
    
    236  | 
     | 
     | 
    	if (keys & F_SLINK &&  | 
    
    
    237  | 
     | 
     | 
    	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { | 
    
    
    238  | 
     | 
     | 
    		name = rlink(p->fts_accpath);  | 
    
    
    239  | 
     | 
     | 
    		esc_len = strlen(name) * 4 + 1;  | 
    
    
    240  | 
     | 
     | 
    		escaped_name = malloc(esc_len);  | 
    
    
    241  | 
     | 
     | 
    		if (escaped_name == NULL)  | 
    
    
    242  | 
     | 
     | 
    			error("statf: %s", strerror(errno)); | 
    
    
    243  | 
     | 
     | 
    		strnvis(escaped_name, name, esc_len, VIS_WHITE | VIS_OCTAL);  | 
    
    
    244  | 
     | 
     | 
    		output(indent, &offset, "link=%s", escaped_name);  | 
    
    
    245  | 
     | 
     | 
    		free(escaped_name);  | 
    
    
    246  | 
     | 
     | 
    	}  | 
    
    
    247  | 
     | 
     | 
    	if (keys & F_FLAGS && !S_ISLNK(p->fts_statp->st_mode)) { | 
    
    
    248  | 
     | 
     | 
    		char *file_flags;  | 
    
    
    249  | 
     | 
     | 
     | 
    
    
    250  | 
     | 
     | 
    		file_flags = fflagstostr(p->fts_statp->st_flags);  | 
    
    
    251  | 
     | 
     | 
    		if (file_flags == NULL)  | 
    
    
    252  | 
     | 
     | 
    			error("%s", strerror(errno)); | 
    
    
    253  | 
     | 
     | 
    		if (*file_flags != '\0')  | 
    
    
    254  | 
     | 
     | 
    			output(indent, &offset, "flags=%s", file_flags);  | 
    
    
    255  | 
     | 
     | 
    		else  | 
    
    
    256  | 
     | 
     | 
    			output(indent, &offset, "flags=none");  | 
    
    
    257  | 
     | 
     | 
    		free(file_flags);  | 
    
    
    258  | 
     | 
     | 
    	}  | 
    
    
    259  | 
     | 
     | 
    	(void)putchar('\n'); | 
    
    
    260  | 
     | 
     | 
    }  | 
    
    
    261  | 
     | 
     | 
     | 
    
    
    262  | 
     | 
     | 
    #define	MAXGID	5000  | 
    
    
    263  | 
     | 
     | 
    #define	MAXUID	5000  | 
    
    
    264  | 
     | 
     | 
    #define	MAXMODE	MBITS + 1  | 
    
    
    265  | 
     | 
     | 
     | 
    
    
    266  | 
     | 
     | 
    static int  | 
    
    
    267  | 
     | 
     | 
    statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode)  | 
    
    
    268  | 
     | 
     | 
    { | 
    
    
    269  | 
     | 
     | 
    	FTSENT *p;  | 
    
    
    270  | 
     | 
     | 
    	gid_t sgid;  | 
    
    
    271  | 
     | 
     | 
    	uid_t suid;  | 
    
    
    272  | 
     | 
     | 
    	mode_t smode;  | 
    
    
    273  | 
     | 
     | 
    	struct group *gr;  | 
    
    
    274  | 
     | 
     | 
    	struct passwd *pw;  | 
    
    
    275  | 
     | 
     | 
    	gid_t savegid = *pgid;  | 
    
    
    276  | 
     | 
     | 
    	uid_t saveuid = *puid;  | 
    
    
    277  | 
     | 
     | 
    	mode_t savemode = *pmode;  | 
    
    
    278  | 
     | 
     | 
    	int maxgid;  | 
    
    
    279  | 
     | 
     | 
    	int maxuid;  | 
    
    
    280  | 
     | 
     | 
    	u_short maxmode;  | 
    
    
    281  | 
     | 
     | 
    	gid_t g[MAXGID];  | 
    
    
    282  | 
     | 
     | 
    	uid_t u[MAXUID];  | 
    
    
    283  | 
     | 
     | 
    	mode_t m[MAXMODE];  | 
    
    
    284  | 
     | 
     | 
    	static int first = 1;  | 
    
    
    285  | 
     | 
     | 
     | 
    
    
    286  | 
     | 
     | 
    	if ((p = fts_children(t, 0)) == NULL) { | 
    
    
    287  | 
     | 
     | 
    		if (errno)  | 
    
    
    288  | 
     | 
     | 
    			error("%s: %s", RP(parent), strerror(errno)); | 
    
    
    289  | 
     | 
     | 
    		return (1);  | 
    
    
    290  | 
     | 
     | 
    	}  | 
    
    
    291  | 
     | 
     | 
     | 
    
    
    292  | 
     | 
     | 
    	bzero(g, sizeof(g));  | 
    
    
    293  | 
     | 
     | 
    	bzero(u, sizeof(u));  | 
    
    
    294  | 
     | 
     | 
    	bzero(m, sizeof(m));  | 
    
    
    295  | 
     | 
     | 
     | 
    
    
    296  | 
     | 
     | 
    	maxuid = maxgid = maxmode = 0;  | 
    
    
    297  | 
     | 
     | 
    	for (; p; p = p->fts_link) { | 
    
    
    298  | 
     | 
     | 
    		if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) { | 
    
    
    299  | 
     | 
     | 
    			smode = p->fts_statp->st_mode & MBITS;  | 
    
    
    300  | 
     | 
     | 
    			if (smode < MAXMODE && ++m[smode] > maxmode) { | 
    
    
    301  | 
     | 
     | 
    				savemode = smode;  | 
    
    
    302  | 
     | 
     | 
    				maxmode = m[smode];  | 
    
    
    303  | 
     | 
     | 
    			}  | 
    
    
    304  | 
     | 
     | 
    			sgid = p->fts_statp->st_gid;  | 
    
    
    305  | 
     | 
     | 
    			if (sgid < MAXGID && ++g[sgid] > maxgid) { | 
    
    
    306  | 
     | 
     | 
    				savegid = sgid;  | 
    
    
    307  | 
     | 
     | 
    				maxgid = g[sgid];  | 
    
    
    308  | 
     | 
     | 
    			}  | 
    
    
    309  | 
     | 
     | 
    			suid = p->fts_statp->st_uid;  | 
    
    
    310  | 
     | 
     | 
    			if (suid < MAXUID && ++u[suid] > maxuid) { | 
    
    
    311  | 
     | 
     | 
    				saveuid = suid;  | 
    
    
    312  | 
     | 
     | 
    				maxuid = u[suid];  | 
    
    
    313  | 
     | 
     | 
    			}  | 
    
    
    314  | 
     | 
     | 
    		}  | 
    
    
    315  | 
     | 
     | 
    	}  | 
    
    
    316  | 
     | 
     | 
    	/*  | 
    
    
    317  | 
     | 
     | 
    	 * If the /set record is the same as the last one we do not need to output  | 
    
    
    318  | 
     | 
     | 
    	 * a new one.  So first we check to see if anything changed.  Note that we  | 
    
    
    319  | 
     | 
     | 
    	 * always output a /set record for the first directory.  | 
    
    
    320  | 
     | 
     | 
    	 */  | 
    
    
    321  | 
     | 
     | 
    	if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) ||  | 
    
    
    322  | 
     | 
     | 
    	    (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) ||  | 
    
    
    323  | 
     | 
     | 
    	    ((keys & F_MODE) && (*pmode != savemode)) || (first)) { | 
    
    
    324  | 
     | 
     | 
    		first = 0;  | 
    
    
    325  | 
     | 
     | 
    		if (dflag)  | 
    
    
    326  | 
     | 
     | 
    			(void)printf("/set type=dir"); | 
    
    
    327  | 
     | 
     | 
    		else  | 
    
    
    328  | 
     | 
     | 
    			(void)printf("/set type=file"); | 
    
    
    329  | 
     | 
     | 
    		if (keys & F_UNAME) { | 
    
    
    330  | 
     | 
     | 
    			if ((pw = getpwuid(saveuid)) != NULL)  | 
    
    
    331  | 
     | 
     | 
    				(void)printf(" uname=%s", pw->pw_name); | 
    
    
    332  | 
     | 
     | 
    			else  | 
    
    
    333  | 
     | 
     | 
    				error("could not get uname for uid=%u", saveuid); | 
    
    
    334  | 
     | 
     | 
    		}  | 
    
    
    335  | 
     | 
     | 
    		if (keys & F_UID)  | 
    
    
    336  | 
     | 
     | 
    			(void)printf(" uid=%u", saveuid); | 
    
    
    337  | 
     | 
     | 
    		if (keys & F_GNAME) { | 
    
    
    338  | 
     | 
     | 
    			if ((gr = getgrgid(savegid)) != NULL)  | 
    
    
    339  | 
     | 
     | 
    				(void)printf(" gname=%s", gr->gr_name); | 
    
    
    340  | 
     | 
     | 
    			else  | 
    
    
    341  | 
     | 
     | 
    				error("could not get gname for gid=%u", savegid); | 
    
    
    342  | 
     | 
     | 
    		}  | 
    
    
    343  | 
     | 
     | 
    		if (keys & F_GID)  | 
    
    
    344  | 
     | 
     | 
    			(void)printf(" gid=%u", savegid); | 
    
    
    345  | 
     | 
     | 
    		if (keys & F_MODE)  | 
    
    
    346  | 
     | 
     | 
    			(void)printf(" mode=%#o", savemode); | 
    
    
    347  | 
     | 
     | 
    		if (keys & F_NLINK)  | 
    
    
    348  | 
     | 
     | 
    			(void)printf(" nlink=1"); | 
    
    
    349  | 
     | 
     | 
    		(void)printf("\n"); | 
    
    
    350  | 
     | 
     | 
    		*puid = saveuid;  | 
    
    
    351  | 
     | 
     | 
    		*pgid = savegid;  | 
    
    
    352  | 
     | 
     | 
    		*pmode = savemode;  | 
    
    
    353  | 
     | 
     | 
    	}  | 
    
    
    354  | 
     | 
     | 
    	return (0);  | 
    
    
    355  | 
     | 
     | 
    }  | 
    
    
    356  | 
     | 
     | 
     | 
    
    
    357  | 
     | 
     | 
    int  | 
    
    
    358  | 
     | 
     | 
    dsort(const FTSENT **a, const FTSENT **b)  | 
    
    
    359  | 
     | 
     | 
    { | 
    
    
    360  | 
    ✗✓ | 
    8  | 
    	if (S_ISDIR((*a)->fts_statp->st_mode)) { | 
    
    
    361  | 
     | 
     | 
    		if (!S_ISDIR((*b)->fts_statp->st_mode))  | 
    
    
    362  | 
     | 
     | 
    			return (1);  | 
    
    
    363  | 
    ✗✓ | 
    4  | 
    	} else if (S_ISDIR((*b)->fts_statp->st_mode))  | 
    
    
    364  | 
     | 
     | 
    		return (-1);  | 
    
    
    365  | 
     | 
    4  | 
    	return (strcmp((*a)->fts_name, (*b)->fts_name));  | 
    
    
    366  | 
     | 
    4  | 
    }  | 
    
    
    367  | 
     | 
     | 
     | 
    
    
    368  | 
     | 
     | 
    void  | 
    
    
    369  | 
     | 
     | 
    output(int indent, int *offset, const char *fmt, ...)  | 
    
    
    370  | 
     | 
     | 
    { | 
    
    
    371  | 
     | 
     | 
    	va_list ap;  | 
    
    
    372  | 
     | 
     | 
    	char buf[1024];  | 
    
    
    373  | 
     | 
     | 
     | 
    
    
    374  | 
     | 
     | 
    	va_start(ap, fmt);  | 
    
    
    375  | 
     | 
     | 
    	(void)vsnprintf(buf, sizeof(buf), fmt, ap);  | 
    
    
    376  | 
     | 
     | 
    	va_end(ap);  | 
    
    
    377  | 
     | 
     | 
     | 
    
    
    378  | 
     | 
     | 
    	if (*offset + strlen(buf) > MAXLINELEN - 3) { | 
    
    
    379  | 
     | 
     | 
    		(void)printf(" \\\n%*s", INDENTNAMELEN + indent, ""); | 
    
    
    380  | 
     | 
     | 
    		*offset = INDENTNAMELEN + indent;  | 
    
    
    381  | 
     | 
     | 
    	}  | 
    
    
    382  | 
     | 
     | 
    	*offset += printf(" %s", buf) + 1; | 
    
    
    383  | 
     | 
     | 
    }  |