gen_subs.c revision 76017
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1992 Keith Muller.
31556Srgrimes * Copyright (c) 1992, 1993
41556Srgrimes *	The Regents of the University of California.  All rights reserved.
51556Srgrimes *
61556Srgrimes * This code is derived from software contributed to Berkeley by
71556Srgrimes * Keith Muller of the University of California, San Diego.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 3. All advertising materials mentioning features or use of this software
181556Srgrimes *    must display the following acknowledgement:
191556Srgrimes *	This product includes software developed by the University of
201556Srgrimes *	California, Berkeley and its contributors.
211556Srgrimes * 4. Neither the name of the University nor the names of its contributors
221556Srgrimes *    may be used to endorse or promote products derived from this software
231556Srgrimes *    without specific prior written permission.
241556Srgrimes *
251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351556Srgrimes * SUCH DAMAGE.
361556Srgrimes */
371556Srgrimes
381556Srgrimes#ifndef lint
3936049Scharnier#if 0
4036049Scharnierstatic char sccsid[] = "@(#)gen_subs.c	8.1 (Berkeley) 5/31/93";
4136049Scharnier#endif
4236049Scharnierstatic const char rcsid[] =
4350471Speter  "$FreeBSD: head/bin/pax/gen_subs.c 76017 2001-04-26 08:37:00Z kris $";
441556Srgrimes#endif /* not lint */
451556Srgrimes
461556Srgrimes#include <sys/types.h>
471556Srgrimes#include <sys/time.h>
481556Srgrimes#include <sys/stat.h>
4974567Sache#include <langinfo.h>
501556Srgrimes#include <stdio.h>
511556Srgrimes#include <utmp.h>
521556Srgrimes#include <unistd.h>
531556Srgrimes#include <stdlib.h>
541556Srgrimes#include <string.h>
551556Srgrimes#include "pax.h"
561556Srgrimes#include "extern.h"
571556Srgrimes
581556Srgrimes/*
591556Srgrimes * a collection of general purpose subroutines used by pax
601556Srgrimes */
611556Srgrimes
621556Srgrimes/*
631556Srgrimes * constants used by ls_list() when printing out archive members
641556Srgrimes */
651556Srgrimes#define MODELEN 20
661556Srgrimes#define DATELEN 64
679987Swollman#define SIXMONTHS	 ((365 / 2) * 86400)
6874567Sache#define CURFRMTM	"%b %e %H:%M"
6974567Sache#define OLDFRMTM	"%b %e  %Y"
7074567Sache#define CURFRMTD	"%e %b %H:%M"
7174567Sache#define OLDFRMTD	"%e %b  %Y"
721556Srgrimes#ifndef UT_NAMESIZE
731556Srgrimes#define UT_NAMESIZE	8
741556Srgrimes#endif
751556Srgrimes#define UT_GRPSIZE	6
761556Srgrimes
7774567Sachestatic int d_first = -1;
7874567Sache
791556Srgrimes/*
801556Srgrimes * ls_list()
811556Srgrimes *	list the members of an archive in ls format
821556Srgrimes */
831556Srgrimes
8476017Skris#ifdef __STDC__
851556Srgrimesvoid
861556Srgrimesls_list(register ARCHD *arcn, time_t now)
871556Srgrimes#else
881556Srgrimesvoid
891556Srgrimesls_list(arcn, now)
901556Srgrimes	register ARCHD *arcn;
911556Srgrimes	time_t now;
921556Srgrimes#endif
931556Srgrimes{
941556Srgrimes	register struct stat *sbp;
951556Srgrimes	char f_mode[MODELEN];
961556Srgrimes	char f_date[DATELEN];
971556Srgrimes	char *timefrmt;
981556Srgrimes
991556Srgrimes	/*
1001556Srgrimes	 * if not verbose, just print the file name
1011556Srgrimes	 */
1021556Srgrimes	if (!vflag) {
1031556Srgrimes		(void)printf("%s\n", arcn->name);
1041556Srgrimes		(void)fflush(stdout);
1051556Srgrimes		return;
1061556Srgrimes	}
1071556Srgrimes
10874567Sache	if (d_first < 0)
10974567Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
1101556Srgrimes	/*
1111556Srgrimes	 * user wants long mode
1121556Srgrimes	 */
1131556Srgrimes	sbp = &(arcn->sb);
1141556Srgrimes	strmode(sbp->st_mode, f_mode);
1151556Srgrimes
11673345Sru	/*
11773345Sru	 * time format based on age compared to the time pax was started.
11873345Sru	 */
11973345Sru	if ((sbp->st_mtime + SIXMONTHS) <= now)
12074567Sache		timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
12173345Sru	else
12274567Sache		timefrmt = d_first ? CURFRMTD : CURFRMTM;
1231556Srgrimes
1241556Srgrimes	/*
1251556Srgrimes	 * print file mode, link count, uid, gid and time
1261556Srgrimes	 */
1271556Srgrimes	if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
1281556Srgrimes		f_date[0] = '\0';
1291556Srgrimes	(void)printf("%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, UT_NAMESIZE,
1301556Srgrimes		name_uid(sbp->st_uid, 1), UT_GRPSIZE,
1311556Srgrimes		name_gid(sbp->st_gid, 1));
1321556Srgrimes
1331556Srgrimes	/*
1341556Srgrimes	 * print device id's for devices, or sizes for other nodes
1351556Srgrimes	 */
1361556Srgrimes	if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
1371556Srgrimes#		ifdef NET2_STAT
1381556Srgrimes		(void)printf("%4u,%4u ", MAJOR(sbp->st_rdev),
13920420Ssteve		    MINOR(sbp->st_rdev));
1401556Srgrimes#		else
1417165Sjoerg		(void)printf("%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
14220420Ssteve		    (unsigned long)MINOR(sbp->st_rdev));
1431556Srgrimes#		endif
1441556Srgrimes	else {
1451556Srgrimes#		ifdef NET2_STAT
1461556Srgrimes		(void)printf("%9lu ", sbp->st_size);
1471556Srgrimes#		else
1481556Srgrimes		(void)printf("%9qu ", sbp->st_size);
1491556Srgrimes#		endif
1501556Srgrimes	}
1511556Srgrimes
1521556Srgrimes	/*
1531556Srgrimes	 * print name and link info for hard and soft links
1541556Srgrimes	 */
1551556Srgrimes	(void)printf("%s %s", f_date, arcn->name);
1561556Srgrimes	if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
1571556Srgrimes		(void)printf(" == %s\n", arcn->ln_name);
1581556Srgrimes	else if (arcn->type == PAX_SLK)
1591556Srgrimes		(void)printf(" => %s\n", arcn->ln_name);
1601556Srgrimes	else
1611556Srgrimes		(void)putchar('\n');
1621556Srgrimes	(void)fflush(stdout);
1631556Srgrimes	return;
1641556Srgrimes}
1651556Srgrimes
1661556Srgrimes/*
1671556Srgrimes * tty_ls()
1681556Srgrimes * 	print a short summary of file to tty.
1691556Srgrimes */
1701556Srgrimes
17176017Skris#ifdef __STDC__
1721556Srgrimesvoid
1731556Srgrimesls_tty(register ARCHD *arcn)
1741556Srgrimes#else
1751556Srgrimesvoid
1761556Srgrimesls_tty(arcn)
1771556Srgrimes	register ARCHD *arcn;
1781556Srgrimes#endif
1791556Srgrimes{
1801556Srgrimes	char f_date[DATELEN];
1811556Srgrimes	char f_mode[MODELEN];
1821556Srgrimes	char *timefrmt;
1831556Srgrimes
18474567Sache	if (d_first < 0)
18574567Sache		d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
18674567Sache
18776017Skris	if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
18874567Sache		timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
18973345Sru	else
19074567Sache		timefrmt = d_first ? CURFRMTD : CURFRMTM;
1911556Srgrimes
1921556Srgrimes	/*
1931556Srgrimes	 * convert time to string, and print
1941556Srgrimes	 */
1951556Srgrimes	if (strftime(f_date, DATELEN, timefrmt,
1961556Srgrimes	    localtime(&(arcn->sb.st_mtime))) == 0)
1971556Srgrimes		f_date[0] = '\0';
1981556Srgrimes	strmode(arcn->sb.st_mode, f_mode);
1991556Srgrimes	tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
2001556Srgrimes	return;
2011556Srgrimes}
2021556Srgrimes
2031556Srgrimes/*
2041556Srgrimes * zf_strncpy()
2051556Srgrimes *	copy src to dest up to len chars (stopping at first '\0'), when src is
2068855Srgrimes *	shorter than len, pads to len with '\0'. big performance win (and
2071556Srgrimes *	a lot easier to code) over strncpy(), then a strlen() then a
20876017Skris *	memset(). (or doing the memset() first).
2091556Srgrimes */
2101556Srgrimes
21176017Skris#ifdef __STDC__
2121556Srgrimesvoid
2131556Srgrimeszf_strncpy(register char *dest, register char *src, int len)
2141556Srgrimes#else
2151556Srgrimesvoid
2161556Srgrimeszf_strncpy(dest, src, len)
2171556Srgrimes	register char *dest;
2181556Srgrimes	register char *src;
2191556Srgrimes	int len;
2201556Srgrimes#endif
2211556Srgrimes{
2221556Srgrimes	register char *stop;
2231556Srgrimes
2241556Srgrimes	stop = dest + len;
2251556Srgrimes	while ((dest < stop) && (*src != '\0'))
2261556Srgrimes		*dest++ = *src++;
2271556Srgrimes	while (dest < stop)
2281556Srgrimes		*dest++ = '\0';
2291556Srgrimes	return;
2301556Srgrimes}
2311556Srgrimes
2321556Srgrimes/*
2331556Srgrimes * l_strncpy()
2341556Srgrimes *	copy src to dest up to len chars (stopping at first '\0')
2351556Srgrimes * Return:
2361556Srgrimes *	number of chars copied. (Note this is a real performance win over
2371556Srgrimes *	doing a strncpy() then a strlen()
2381556Srgrimes */
2391556Srgrimes
24076017Skris#ifdef __STDC__
2411556Srgrimesint
2421556Srgrimesl_strncpy(register char *dest, register char *src, int len)
2431556Srgrimes#else
2441556Srgrimesint
2451556Srgrimesl_strncpy(dest, src, len)
2461556Srgrimes	register char *dest;
2471556Srgrimes	register char *src;
2481556Srgrimes	int len;
2491556Srgrimes#endif
2501556Srgrimes{
2511556Srgrimes	register char *stop;
2521556Srgrimes	register char *start;
2531556Srgrimes
2541556Srgrimes	stop = dest + len;
2551556Srgrimes	start = dest;
2561556Srgrimes	while ((dest < stop) && (*src != '\0'))
2571556Srgrimes		*dest++ = *src++;
2581556Srgrimes	if (dest < stop)
2591556Srgrimes		*dest = '\0';
2601556Srgrimes	return(dest - start);
2611556Srgrimes}
2621556Srgrimes
2631556Srgrimes/*
2641556Srgrimes * asc_ul()
2651556Srgrimes *	convert hex/octal character string into a u_long. We do not have to
2661556Srgrimes *	check for overflow! (the headers in all supported formats are not large
2671556Srgrimes *	enough to create an overflow).
2681556Srgrimes *	NOTE: strings passed to us are NOT TERMINATED.
2691556Srgrimes * Return:
2701556Srgrimes *	unsigned long value
2711556Srgrimes */
2721556Srgrimes
27376017Skris#ifdef __STDC__
2741556Srgrimesu_long
2751556Srgrimesasc_ul(register char *str, int len, register int base)
2761556Srgrimes#else
2771556Srgrimesu_long
2781556Srgrimesasc_ul(str, len, base)
2791556Srgrimes	register char *str;
2801556Srgrimes	int len;
2811556Srgrimes	register int base;
2821556Srgrimes#endif
2831556Srgrimes{
2841556Srgrimes	register char *stop;
2851556Srgrimes	u_long tval = 0;
2861556Srgrimes
2871556Srgrimes	stop = str + len;
2881556Srgrimes
2891556Srgrimes	/*
2901556Srgrimes	 * skip over leading blanks and zeros
2911556Srgrimes	 */
2921556Srgrimes	while ((str < stop) && ((*str == ' ') || (*str == '0')))
2931556Srgrimes		++str;
2941556Srgrimes
2951556Srgrimes	/*
2961556Srgrimes	 * for each valid digit, shift running value (tval) over to next digit
2971556Srgrimes	 * and add next digit
2981556Srgrimes	 */
2991556Srgrimes	if (base == HEX) {
3001556Srgrimes		while (str < stop) {
3011556Srgrimes			if ((*str >= '0') && (*str <= '9'))
3021556Srgrimes				tval = (tval << 4) + (*str++ - '0');
3031556Srgrimes			else if ((*str >= 'A') && (*str <= 'F'))
3041556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'A');
3051556Srgrimes			else if ((*str >= 'a') && (*str <= 'f'))
3061556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'a');
3071556Srgrimes			else
3081556Srgrimes				break;
3091556Srgrimes		}
3101556Srgrimes	} else {
3111556Srgrimes 		while ((str < stop) && (*str >= '0') && (*str <= '7'))
3121556Srgrimes			tval = (tval << 3) + (*str++ - '0');
3131556Srgrimes	}
3141556Srgrimes	return(tval);
3151556Srgrimes}
3161556Srgrimes
3171556Srgrimes/*
3181556Srgrimes * ul_asc()
3191556Srgrimes *	convert an unsigned long into an hex/oct ascii string. pads with LEADING
3201556Srgrimes *	ascii 0's to fill string completely
3211556Srgrimes *	NOTE: the string created is NOT TERMINATED.
3221556Srgrimes */
3231556Srgrimes
32476017Skris#ifdef __STDC__
3251556Srgrimesint
3261556Srgrimesul_asc(u_long val, register char *str, register int len, register int base)
3271556Srgrimes#else
3281556Srgrimesint
3291556Srgrimesul_asc(val, str, len, base)
3301556Srgrimes	u_long val;
3311556Srgrimes	register char *str;
3321556Srgrimes	register int len;
3331556Srgrimes	register int base;
3341556Srgrimes#endif
3351556Srgrimes{
3361556Srgrimes	register char *pt;
3371556Srgrimes	u_long digit;
3388855Srgrimes
3391556Srgrimes	/*
3401556Srgrimes	 * WARNING str is not '\0' terminated by this routine
3411556Srgrimes	 */
3421556Srgrimes	pt = str + len - 1;
3431556Srgrimes
3441556Srgrimes	/*
3451556Srgrimes	 * do a tailwise conversion (start at right most end of string to place
3461556Srgrimes	 * least significant digit). Keep shifting until conversion value goes
3471556Srgrimes	 * to zero (all digits were converted)
3481556Srgrimes	 */
3491556Srgrimes	if (base == HEX) {
3501556Srgrimes		while (pt >= str) {
3511556Srgrimes			if ((digit = (val & 0xf)) < 10)
3521556Srgrimes				*pt-- = '0' + (char)digit;
3538855Srgrimes			else
3541556Srgrimes				*pt-- = 'a' + (char)(digit - 10);
3551556Srgrimes			if ((val = (val >> 4)) == (u_long)0)
3561556Srgrimes				break;
3571556Srgrimes		}
3581556Srgrimes	} else {
3591556Srgrimes		while (pt >= str) {
3601556Srgrimes			*pt-- = '0' + (char)(val & 0x7);
3611556Srgrimes			if ((val = (val >> 3)) == (u_long)0)
3621556Srgrimes				break;
3631556Srgrimes		}
3641556Srgrimes	}
3651556Srgrimes
3661556Srgrimes	/*
3671556Srgrimes	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
3681556Srgrimes	 */
3691556Srgrimes	while (pt >= str)
3701556Srgrimes		*pt-- = '0';
3711556Srgrimes	if (val != (u_long)0)
3721556Srgrimes		return(-1);
3731556Srgrimes	return(0);
3741556Srgrimes}
3751556Srgrimes
3761556Srgrimes#ifndef NET2_STAT
3771556Srgrimes/*
3781556Srgrimes * asc_uqd()
3791556Srgrimes *	convert hex/octal character string into a u_quad_t. We do not have to
3801556Srgrimes *	check for overflow! (the headers in all supported formats are not large
3811556Srgrimes *	enough to create an overflow).
3821556Srgrimes *	NOTE: strings passed to us are NOT TERMINATED.
3831556Srgrimes * Return:
3841556Srgrimes *	u_quad_t value
3851556Srgrimes */
3861556Srgrimes
38776017Skris#ifdef __STDC__
3881556Srgrimesu_quad_t
3891556Srgrimesasc_uqd(register char *str, int len, register int base)
3901556Srgrimes#else
3911556Srgrimesu_quad_t
3921556Srgrimesasc_uqd(str, len, base)
3931556Srgrimes	register char *str;
3941556Srgrimes	int len;
3951556Srgrimes	register int base;
3961556Srgrimes#endif
3971556Srgrimes{
3981556Srgrimes	register char *stop;
3991556Srgrimes	u_quad_t tval = 0;
4001556Srgrimes
4011556Srgrimes	stop = str + len;
4021556Srgrimes
4031556Srgrimes	/*
4041556Srgrimes	 * skip over leading blanks and zeros
4051556Srgrimes	 */
4061556Srgrimes	while ((str < stop) && ((*str == ' ') || (*str == '0')))
4071556Srgrimes		++str;
4081556Srgrimes
4091556Srgrimes	/*
4101556Srgrimes	 * for each valid digit, shift running value (tval) over to next digit
4111556Srgrimes	 * and add next digit
4121556Srgrimes	 */
4131556Srgrimes	if (base == HEX) {
4141556Srgrimes		while (str < stop) {
4151556Srgrimes			if ((*str >= '0') && (*str <= '9'))
4161556Srgrimes				tval = (tval << 4) + (*str++ - '0');
4171556Srgrimes			else if ((*str >= 'A') && (*str <= 'F'))
4181556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'A');
4191556Srgrimes			else if ((*str >= 'a') && (*str <= 'f'))
4201556Srgrimes				tval = (tval << 4) + 10 + (*str++ - 'a');
4211556Srgrimes			else
4221556Srgrimes				break;
4231556Srgrimes		}
4241556Srgrimes	} else {
4251556Srgrimes 		while ((str < stop) && (*str >= '0') && (*str <= '7'))
4261556Srgrimes			tval = (tval << 3) + (*str++ - '0');
4271556Srgrimes	}
4281556Srgrimes	return(tval);
4291556Srgrimes}
4301556Srgrimes
4311556Srgrimes/*
4321556Srgrimes * uqd_asc()
4331556Srgrimes *	convert an u_quad_t into a hex/oct ascii string. pads with LEADING
4341556Srgrimes *	ascii 0's to fill string completely
4351556Srgrimes *	NOTE: the string created is NOT TERMINATED.
4361556Srgrimes */
4371556Srgrimes
43876017Skris#ifdef __STDC__
4391556Srgrimesint
4401556Srgrimesuqd_asc(u_quad_t val, register char *str, register int len, register int base)
4411556Srgrimes#else
4421556Srgrimesint
4431556Srgrimesuqd_asc(val, str, len, base)
4441556Srgrimes	u_quad_t val;
4451556Srgrimes	register char *str;
4461556Srgrimes	register int len;
4471556Srgrimes	register int base;
4481556Srgrimes#endif
4491556Srgrimes{
4501556Srgrimes	register char *pt;
4511556Srgrimes	u_quad_t digit;
4528855Srgrimes
4531556Srgrimes	/*
4541556Srgrimes	 * WARNING str is not '\0' terminated by this routine
4551556Srgrimes	 */
4561556Srgrimes	pt = str + len - 1;
4571556Srgrimes
4581556Srgrimes	/*
4591556Srgrimes	 * do a tailwise conversion (start at right most end of string to place
4601556Srgrimes	 * least significant digit). Keep shifting until conversion value goes
4611556Srgrimes	 * to zero (all digits were converted)
4621556Srgrimes	 */
4631556Srgrimes	if (base == HEX) {
4641556Srgrimes		while (pt >= str) {
4651556Srgrimes			if ((digit = (val & 0xf)) < 10)
4661556Srgrimes				*pt-- = '0' + (char)digit;
4678855Srgrimes			else
4681556Srgrimes				*pt-- = 'a' + (char)(digit - 10);
4691556Srgrimes			if ((val = (val >> 4)) == (u_quad_t)0)
4701556Srgrimes				break;
4711556Srgrimes		}
4721556Srgrimes	} else {
4731556Srgrimes		while (pt >= str) {
4741556Srgrimes			*pt-- = '0' + (char)(val & 0x7);
4751556Srgrimes			if ((val = (val >> 3)) == (u_quad_t)0)
4761556Srgrimes				break;
4771556Srgrimes		}
4781556Srgrimes	}
4791556Srgrimes
4801556Srgrimes	/*
4811556Srgrimes	 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
4821556Srgrimes	 */
4831556Srgrimes	while (pt >= str)
4841556Srgrimes		*pt-- = '0';
4851556Srgrimes	if (val != (u_quad_t)0)
4861556Srgrimes		return(-1);
4871556Srgrimes	return(0);
4881556Srgrimes}
4891556Srgrimes#endif
490