Esempio n. 1
0
/*
 * Display() takes a linked list of FTSENT structures and passes the list
 * along with any other necessary information to the print function.  P
 * points to the parent directory of the display list.
 */
static void
display(FTSENT *p, FTSENT *list)
{
	struct stat *sp;
	DISPLAY d;
	FTSENT *cur;
	NAMES *np;
	u_int64_t btotal, stotal;
	off_t maxsize;
	blkcnt_t maxblock;
	ino_t maxinode;
	int maxmajor, maxminor;
	uint32_t maxnlink;
	int bcfile, entries, flen, glen, ulen, maxflags, maxgroup;
	unsigned int maxlen;
	int maxuser, needstats;
	const char *user, *group;
	char buf[21];		/* 64 bits == 20 digits, +1 for NUL */
	char nuser[12], ngroup[12];
	char *flags = NULL;

	/*
	 * If list is NULL there are two possibilities: that the parent
	 * directory p has no children, or that fts_children() returned an
	 * error.  We ignore the error case since it will be replicated
	 * on the next call to fts_read() on the post-order visit to the
	 * directory p, and will be signalled in traverse().
	 */
	if (list == NULL)
		return;

	needstats = f_inode || f_longform || f_size;
	flen = 0;
	maxinode = maxnlink = 0;
	bcfile = 0;
	maxuser = maxgroup = maxflags = maxlen = 0;
	btotal = stotal = maxblock = maxsize = 0;
	maxmajor = maxminor = 0;
	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
			warnx("%s: %s",
			    cur->fts_name, strerror(cur->fts_errno));
			cur->fts_number = NO_PRINT;
			rval = EXIT_FAILURE;
			continue;
		}

		/*
		 * P is NULL if list is the argv list, to which different rules
		 * apply.
		 */
		if (p == NULL) {
			/* Directories will be displayed later. */
			if (cur->fts_info == FTS_D && !f_listdir) {
				cur->fts_number = NO_PRINT;
				continue;
			}
		} else {
			/* Only display dot file if -a/-A set. */
			if (cur->fts_name[0] == '.' && !f_listdot) {
				cur->fts_number = NO_PRINT;
				continue;
			}
		}
		if (cur->fts_namelen > maxlen)
			maxlen = cur->fts_namelen;
		if (needstats) {
			sp = cur->fts_statp;
			if (sp->st_blocks > maxblock)
				maxblock = sp->st_blocks;
			if (sp->st_ino > maxinode)
				maxinode = sp->st_ino;
			if (sp->st_nlink > maxnlink)
				maxnlink = sp->st_nlink;
			if (sp->st_size > maxsize)
				maxsize = sp->st_size;
			if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) {
				bcfile = 1;
				if (major(sp->st_rdev) > maxmajor)
					maxmajor = major(sp->st_rdev);
				if (minor(sp->st_rdev) > maxminor)
					maxminor = minor(sp->st_rdev);
			}

			btotal += sp->st_blocks;
			stotal += sp->st_size;
			if (f_longform) {
				if (f_numericonly ||
				    (user = user_from_uid(sp->st_uid, 0)) ==
				    NULL) {
					(void)snprintf(nuser, sizeof(nuser),
					    "%u", sp->st_uid);
					user = nuser;
				}
				if (f_numericonly ||
				    (group = group_from_gid(sp->st_gid, 0)) ==
				    NULL) {
					(void)snprintf(ngroup, sizeof(ngroup),
					    "%u", sp->st_gid);
					group = ngroup;
				}
				if ((ulen = strlen(user)) > maxuser)
					maxuser = ulen;
				if ((glen = strlen(group)) > maxgroup)
					maxgroup = glen;
				if (f_flags) {
					flags =
					    flags_to_string((u_long)sp->st_flags, "-");
					if ((flen = strlen(flags)) > maxflags)
						maxflags = flen;
				} else
					flen = 0;

				if ((np = malloc(sizeof(NAMES) +
				    ulen + glen + flen + 2)) == NULL)
					err(EXIT_FAILURE, NULL);

				np->user = &np->data[0];
				(void)strcpy(np->user, user);
				np->group = &np->data[ulen + 1];
				(void)strcpy(np->group, group);

				if (f_flags) {
					np->flags = &np->data[ulen + glen + 2];
				  	(void)strcpy(np->flags, flags);
					free(flags);
				}
				cur->fts_pointer = np;
			}
		}
		++entries;
	}

	if (!entries)
		return;

	d.list = list;
	d.entries = entries;
	d.maxlen = maxlen;
	if (needstats) {
		d.btotal = btotal;
		d.stotal = stotal;
		if (f_humanize) {
			d.s_block = 4; /* min buf length for humanize_number */
		} else {
			(void)snprintf(buf, sizeof(buf), "%lld",
			    (long long)howmany(maxblock, blocksize));
			d.s_block = strlen(buf);
			if (f_commas) /* allow for commas before every third digit */
				d.s_block += (d.s_block - 1) / 3;
		}
		d.s_flags = maxflags;
		d.s_group = maxgroup;
		(void)snprintf(buf, sizeof(buf), "%llu",
		    (unsigned long long)maxinode);
		d.s_inode = strlen(buf);
		(void)snprintf(buf, sizeof(buf), "%u", maxnlink);
		d.s_nlink = strlen(buf);
		if (f_humanize) {
			d.s_size = 4; /* min buf length for humanize_number */
		} else {
			(void)snprintf(buf, sizeof(buf), "%lld",
			    (long long)maxsize);
			d.s_size = strlen(buf);
			if (f_commas) /* allow for commas before every third digit */
				d.s_size += (d.s_size - 1) / 3;
		}
		d.s_user = maxuser;
		if (bcfile) {
			(void)snprintf(buf, sizeof(buf), "%d", maxmajor);
			d.s_major = strlen(buf);
			(void)snprintf(buf, sizeof(buf), "%d", maxminor);
			d.s_minor = strlen(buf);
			if (d.s_major + d.s_minor + 2 > d.s_size)
				d.s_size = d.s_major + d.s_minor + 2;
			else if (d.s_size - d.s_minor - 2 > d.s_major)
				d.s_major = d.s_size - d.s_minor - 2;
		} else {
			d.s_major = 0;
			d.s_minor = 0;
		}
	}

	printfcn(&d);
	output = 1;

	if (f_longform)
		for (cur = list; cur; cur = cur->fts_link)
			free(cur->fts_pointer);
}
Esempio n. 2
0
/*
 * Display() takes a linked list of FTSENT structures and passes the list
 * along with any other necessary information to the print function.  P
 * points to the parent directory of the display list.
 */
static void
display(const FTSENT *p, FTSENT *list, int options)
{
	struct stat *sp;
	DISPLAY d;
	FTSENT *cur;
	NAMES *np;
	off_t maxsize;
	long maxblock;
	uintmax_t maxinode;
	u_long btotal, labelstrlen, maxlen, maxnlink;
	u_long maxlabelstr;
	u_int sizelen;
	int maxflags;
	gid_t maxgroup;
	uid_t maxuser;
	size_t flen, ulen, glen;
	char *initmax;
	int entries, needstats;
	const char *user, *group;
	char *flags, *labelstr = NULL;
	char ngroup[STRBUF_SIZEOF(uid_t) + 1];
	char nuser[STRBUF_SIZEOF(gid_t) + 1];

	needstats = f_inode || f_longform || f_size;
	flen = 0;
	btotal = 0;
	initmax = getenv("LS_COLWIDTHS");
	/* Fields match -lios order.  New ones should be added at the end. */
	maxlabelstr = maxblock = maxlen = maxnlink = 0;
	maxuser = maxgroup = maxflags = maxsize = 0;
	maxinode = 0;
	if (initmax != NULL && *initmax != '\0') {
		char *initmax2, *jinitmax;
		int ninitmax;

		/* Fill-in "::" as "0:0:0" for the sake of scanf. */
		jinitmax = malloc(strlen(initmax) * 2 + 2);
		if (jinitmax == NULL)
			err(1, "malloc");
		initmax2 = jinitmax;
		if (*initmax == ':')
			strcpy(initmax2, "0:"), initmax2 += 2;
		else
			*initmax2++ = *initmax, *initmax2 = '\0';
		for (initmax++; *initmax != '\0'; initmax++) {
			if (initmax[-1] == ':' && initmax[0] == ':') {
				*initmax2++ = '0';
				*initmax2++ = initmax[0];
				initmax2[1] = '\0';
			} else {
				*initmax2++ = initmax[0];
				initmax2[1] = '\0';
			}
		}
		if (initmax2[-1] == ':')
			strcpy(initmax2, "0");

		ninitmax = sscanf(jinitmax,
		    " %ju : %ld : %lu : %u : %u : %i : %jd : %lu : %lu ",
		    &maxinode, &maxblock, &maxnlink, &maxuser,
		    &maxgroup, &maxflags, &maxsize, &maxlen, &maxlabelstr);
		f_notabs = 1;
		switch (ninitmax) {
		case 0:
			maxinode = 0;
			/* FALLTHROUGH */
		case 1:
			maxblock = 0;
			/* FALLTHROUGH */
		case 2:
			maxnlink = 0;
			/* FALLTHROUGH */
		case 3:
			maxuser = 0;
			/* FALLTHROUGH */
		case 4:
			maxgroup = 0;
			/* FALLTHROUGH */
		case 5:
			maxflags = 0;
			/* FALLTHROUGH */
		case 6:
			maxsize = 0;
			/* FALLTHROUGH */
		case 7:
			maxlen = 0;
			/* FALLTHROUGH */
		case 8:
			maxlabelstr = 0;
			/* FALLTHROUGH */
#ifdef COLORLS
			if (!f_color)
#endif
				f_notabs = 0;
			/* FALLTHROUGH */
		default:
			break;
		}
		MAKENINES(maxinode);
		MAKENINES(maxblock);
		MAKENINES(maxnlink);
		MAKENINES(maxsize);
		free(jinitmax);
	}
	d.s_size = 0;
	sizelen = 0;
	flags = NULL;
	for (cur = list, entries = 0; cur; cur = cur->fts_link) {
		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
			warnx("%s: %s",
			    cur->fts_name, strerror(cur->fts_errno));
			cur->fts_number = NO_PRINT;
			rval = 1;
			continue;
		}
		/*
		 * P is NULL if list is the argv list, to which different rules
		 * apply.
		 */
		if (p == NULL) {
			/* Directories will be displayed later. */
			if (cur->fts_info == FTS_D && !f_listdir) {
				cur->fts_number = NO_PRINT;
				continue;
			}
		} else {
			/* Only display dot file if -a/-A set. */
			if (cur->fts_name[0] == '.' && !f_listdot) {
				cur->fts_number = NO_PRINT;
				continue;
			}
		}
		if (cur->fts_namelen > maxlen)
			maxlen = cur->fts_namelen;
		if (f_octal || f_octal_escape) {
			u_long t = len_octal(cur->fts_name, cur->fts_namelen);

			if (t > maxlen)
				maxlen = t;
		}
		if (needstats) {
			sp = cur->fts_statp;
			if (sp->st_blocks > maxblock)
				maxblock = sp->st_blocks;
			if (sp->st_ino > maxinode)
				maxinode = sp->st_ino;
			if (sp->st_nlink > maxnlink)
				maxnlink = sp->st_nlink;
			if (sp->st_size > maxsize)
				maxsize = sp->st_size;

			btotal += sp->st_blocks;
			if (f_longform) {
				if (f_numericonly) {
					(void)snprintf(nuser, sizeof(nuser),
					    "%u", sp->st_uid);
					(void)snprintf(ngroup, sizeof(ngroup),
					    "%u", sp->st_gid);
					user = nuser;
					group = ngroup;
				} else {
					user = user_from_uid(sp->st_uid, 0);
					group = group_from_gid(sp->st_gid, 0);
				}
				if ((ulen = strlen(user)) > maxuser)
					maxuser = ulen;
				if ((glen = strlen(group)) > maxgroup)
					maxgroup = glen;
				if (f_flags) {
					flags = fflagstostr(sp->st_flags);
					if (flags != NULL && *flags == '\0') {
						free(flags);
						flags = strdup("-");
					}
					if (flags == NULL)
						err(1, "fflagstostr");
					flen = strlen(flags);
					if (flen > (size_t)maxflags)
						maxflags = flen;
				} else
					flen = 0;
				labelstr = NULL;
				if (f_label) {
					char name[PATH_MAX + 1];
					mac_t label;
					int error;

					error = mac_prepare_file_label(&label);
					if (error == -1) {
						warn("MAC label for %s/%s",
						    cur->fts_parent->fts_path,
						    cur->fts_name);
						goto label_out;
					}

					if (cur->fts_level == FTS_ROOTLEVEL)
						snprintf(name, sizeof(name),
						    "%s", cur->fts_name);
					else
						snprintf(name, sizeof(name),
						    "%s/%s", cur->fts_parent->
						    fts_accpath, cur->fts_name);

					if (options & FTS_LOGICAL)
						error = mac_get_file(name,
						    label);
					else
						error = mac_get_link(name,
						    label);
					if (error == -1) {
						warn("MAC label for %s/%s",
						    cur->fts_parent->fts_path,
						    cur->fts_name);
						mac_free(label);
						goto label_out;
					}

					error = mac_to_text(label,
					    &labelstr);
					if (error == -1) {
						warn("MAC label for %s/%s",
						    cur->fts_parent->fts_path,
						    cur->fts_name);
						mac_free(label);
						goto label_out;
					}
					mac_free(label);
label_out:
					if (labelstr == NULL)
						labelstr = strdup("-");
					labelstrlen = strlen(labelstr);
					if (labelstrlen > maxlabelstr)
						maxlabelstr = labelstrlen;
				} else
					labelstrlen = 0;

				if ((np = malloc(sizeof(NAMES) + labelstrlen +
				    ulen + glen + flen + 4)) == NULL)
					err(1, "malloc");

				np->user = &np->data[0];
				(void)strcpy(np->user, user);
				np->group = &np->data[ulen + 1];
				(void)strcpy(np->group, group);

				if (S_ISCHR(sp->st_mode) ||
				    S_ISBLK(sp->st_mode)) {
					sizelen = snprintf(NULL, 0,
					    "%#jx", (uintmax_t)sp->st_rdev);
					if (d.s_size < sizelen)
						d.s_size = sizelen;
				}

				if (f_flags) {
					np->flags = &np->data[ulen + glen + 2];
					(void)strcpy(np->flags, flags);
					free(flags);
				}
				if (f_label) {
					np->label = &np->data[ulen + glen + 2
					    + (f_flags ? flen + 1 : 0)];
					(void)strcpy(np->label, labelstr);
					free(labelstr);
				}
				cur->fts_pointer = np;
			}
		}
		++entries;
	}

	/*
	 * If there are no entries to display, we normally stop right
	 * here.  However, we must continue if we have to display the
	 * total block count.  In this case, we display the total only
	 * on the second (p != NULL) pass.
	 */
	if (!entries && (!(f_longform || f_size) || p == NULL))
		return;

	d.list = list;
	d.entries = entries;
	d.maxlen = maxlen;
	if (needstats) {
		d.btotal = btotal;
		d.s_block = snprintf(NULL, 0, "%lu", howmany(maxblock, blocksize));
		d.s_flags = maxflags;
		d.s_label = maxlabelstr;
		d.s_group = maxgroup;
		d.s_inode = snprintf(NULL, 0, "%ju", maxinode);
		d.s_nlink = snprintf(NULL, 0, "%lu", maxnlink);
		sizelen = f_humanval ? HUMANVALSTR_LEN :
		    snprintf(NULL, 0, "%ju", maxsize);
		if (d.s_size < sizelen)
			d.s_size = sizelen;
		d.s_user = maxuser;
	}
	if (f_thousands)			/* make space for commas */
		d.s_size += (d.s_size - 1) / 3;
	printfcn(&d);
	output = 1;

	if (f_longform)
		for (cur = list; cur; cur = cur->fts_link)
			free(cur->fts_pointer);
}
Esempio n. 3
0
/*
 * Display() takes a linked list of FTSENT structures and passes the list
 * along with any other necessary information to the print function.  P
 * points to the parent directory of the display list.
 */
static void
display(FTSENT *p, FTSENT *list)
{
	struct stat *sp;
	DISPLAY d;
	FTSENT *cur;
	NAMES *np;
	off_t maxsize;
	u_long maxlen, maxnlink;
	unsigned long long btotal, maxblock;
	ino_t maxinode;
	int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser;
	int entries, needstats;
	char *user, *group, buf[21];	/* 64 bits == 20 digits */
	char nuser[12], ngroup[12];
	char *flags = NULL;

	/*
	 * If list is NULL there are two possibilities: that the parent
	 * directory p has no children, or that fts_children() returned an
	 * error.  We ignore the error case since it will be replicated
	 * on the next call to fts_read() on the post-order visit to the
	 * directory p, and will be signalled in traverse().
	 */
	if (list == NULL)
		return;

	needstats = f_inode || f_longform || f_size;
	flen = 0;
	btotal = maxblock = maxinode = maxlen = maxnlink = 0;
	bcfile = 0;
	maxuser = maxgroup = maxflags = 0;
	maxsize = 0;
	for (cur = list, entries = 0; cur != NULL; cur = cur->fts_link) {
		if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
			warnx("%s: %s",
			    cur->fts_name, strerror(cur->fts_errno));
			cur->fts_number = NO_PRINT;
			rval = 1;
			continue;
		}

		/*
		 * P is NULL if list is the argv list, to which different rules
		 * apply.
		 */
		if (p == NULL) {
			/* Directories will be displayed later. */
			if (cur->fts_info == FTS_D && !f_listdir) {
				cur->fts_number = NO_PRINT;
				continue;
			}
		} else {
			/* Only display dot file if -a/-A set. */
			if (cur->fts_name[0] == '.' && !f_listdot) {
				cur->fts_number = NO_PRINT;
				continue;
			}
		}
		if (cur->fts_namelen > maxlen)
			maxlen = cur->fts_namelen;
		if (needstats) {
			sp = cur->fts_statp;
			if (sp->st_blocks > maxblock)
				maxblock = sp->st_blocks;
			if (sp->st_ino > maxinode)
				maxinode = sp->st_ino;
			if (sp->st_nlink > maxnlink)
				maxnlink = sp->st_nlink;
			if (sp->st_size > maxsize)
				maxsize = sp->st_size;

			btotal += sp->st_blocks;
			if (f_longform) {
				if (f_numericonly) {
					snprintf(nuser, 12, "%u", sp->st_uid);
					snprintf(ngroup, 12, "%u", sp->st_gid);
					user = nuser;
					group = ngroup;
				} else {
					user = user_from_uid(sp->st_uid, 0);
					group = group_from_gid(sp->st_gid, 0);
				}
				if ((ulen = strlen(user)) > maxuser)
					maxuser = ulen;
				if ((glen = strlen(group)) > maxgroup)
					maxgroup = glen;
				if (f_flags) {
					flags = fflagstostr(sp->st_flags);
					if (*flags == '\0')
						flags = "-";
					if ((flen = strlen(flags)) > maxflags)
						maxflags = flen;
				} else
					flen = 0;

				if ((np = malloc(sizeof(NAMES) +
				    ulen + 1 + glen + 1 + flen + 1)) == NULL)
					err(1, NULL);

				np->user = &np->data[0];
				(void)strlcpy(np->user, user, ulen + 1);
				np->group = &np->data[ulen + 1];
				(void)strlcpy(np->group, group, glen + 1);

				if (S_ISCHR(sp->st_mode) ||
				    S_ISBLK(sp->st_mode))
					bcfile = 1;

				if (f_flags) {
					np->flags = &np->data[ulen + 1 + glen + 1];
				  	(void)strlcpy(np->flags, flags, flen + 1);
					if (*flags != '-')
						free(flags);
				}
				cur->fts_pointer = np;
			}
		}
		++entries;
	}

	if (!entries)
		return;

	d.list = list;
	d.entries = entries;
	d.maxlen = maxlen;
	if (needstats) {
		d.bcfile = bcfile;
		d.btotal = btotal;
		(void)snprintf(buf, sizeof(buf), "%llu", maxblock);
		d.s_block = strlen(buf);
		d.s_flags = maxflags;
		d.s_group = maxgroup;
		(void)snprintf(buf, sizeof(buf), "%llu",
		    (unsigned long long)maxinode);
		d.s_inode = strlen(buf);
		(void)snprintf(buf, sizeof(buf), "%lu", maxnlink);
		d.s_nlink = strlen(buf);
		if (!f_humanval) {
			(void)snprintf(buf, sizeof(buf), "%lld",
				(long long) maxsize);
			d.s_size = strlen(buf);
		} else
			d.s_size = FMT_SCALED_STRSIZE-2; /* no - or '\0' */
		d.s_user = maxuser;
	}

	printfcn(&d);
	output = 1;

	if (f_longform)
		for (cur = list; cur != NULL; cur = cur->fts_link)
			free(cur->fts_pointer);
}