1*a4c163faSchristos /* $NetBSD: gen_subs.c,v 1.37 2018/11/30 00:53:11 christos Exp $ */
2b5b29542Sagc
3b5b29542Sagc /*-
4ed6ed8e6Sagc * Copyright (c) 1992 Keith Muller.
5b5b29542Sagc * Copyright (c) 1992, 1993
6b5b29542Sagc * The Regents of the University of California. All rights reserved.
7b5b29542Sagc *
8b5b29542Sagc * This code is derived from software contributed to Berkeley by
9b5b29542Sagc * Keith Muller of the University of California, San Diego.
10b5b29542Sagc *
11b5b29542Sagc * Redistribution and use in source and binary forms, with or without
12b5b29542Sagc * modification, are permitted provided that the following conditions
13b5b29542Sagc * are met:
14b5b29542Sagc * 1. Redistributions of source code must retain the above copyright
15b5b29542Sagc * notice, this list of conditions and the following disclaimer.
16b5b29542Sagc * 2. Redistributions in binary form must reproduce the above copyright
17b5b29542Sagc * notice, this list of conditions and the following disclaimer in the
18b5b29542Sagc * documentation and/or other materials provided with the distribution.
19b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors
20b5b29542Sagc * may be used to endorse or promote products derived from this software
21b5b29542Sagc * without specific prior written permission.
22b5b29542Sagc *
23b5b29542Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24b5b29542Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b5b29542Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b5b29542Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27b5b29542Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b5b29542Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b5b29542Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b5b29542Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b5b29542Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b5b29542Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b5b29542Sagc * SUCH DAMAGE.
34b5b29542Sagc */
3549f0ad86Scgd
36171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
37171d6532Slukem #include "nbtool_config.h"
38171d6532Slukem #endif
39171d6532Slukem
40f3cd6022Schristos #include <sys/cdefs.h>
41171d6532Slukem #if !defined(lint)
4249f0ad86Scgd #if 0
4349f0ad86Scgd static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93";
4449f0ad86Scgd #else
45*a4c163faSchristos __RCSID("$NetBSD: gen_subs.c,v 1.37 2018/11/30 00:53:11 christos Exp $");
4649f0ad86Scgd #endif
478b35abe2Sjtc #endif /* not lint */
488b35abe2Sjtc
498b35abe2Sjtc #include <sys/types.h>
508b35abe2Sjtc #include <sys/time.h>
518b35abe2Sjtc #include <sys/stat.h>
528b35abe2Sjtc #include <sys/param.h>
53d0e267dcSmycroft
548b35abe2Sjtc #include <ctype.h>
55d0e267dcSmycroft #include <grp.h>
56d0e267dcSmycroft #include <pwd.h>
570c612021Schristos #include <vis.h>
58d0e267dcSmycroft #include <stdio.h>
598b35abe2Sjtc #include <stdlib.h>
608b35abe2Sjtc #include <string.h>
61d0e267dcSmycroft #include <time.h>
62d0e267dcSmycroft #include <tzfile.h>
63d0e267dcSmycroft #include <unistd.h>
64d0e267dcSmycroft
658b35abe2Sjtc #include "pax.h"
668b35abe2Sjtc #include "extern.h"
678b35abe2Sjtc
688b35abe2Sjtc /*
698b35abe2Sjtc * a collection of general purpose subroutines used by pax
708b35abe2Sjtc */
718b35abe2Sjtc
728b35abe2Sjtc /*
738b35abe2Sjtc * constants used by ls_list() when printing out archive members
748b35abe2Sjtc */
758b35abe2Sjtc #define MODELEN 20
768b35abe2Sjtc #define DATELEN 64
778b35abe2Sjtc #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
788b35abe2Sjtc #define CURFRMT "%b %e %H:%M"
798b35abe2Sjtc #define OLDFRMT "%b %e %Y"
808b35abe2Sjtc #ifndef UT_NAMESIZE
818b35abe2Sjtc #define UT_NAMESIZE 8
828b35abe2Sjtc #endif
838b35abe2Sjtc #define UT_GRPSIZE 6
848b35abe2Sjtc
858b35abe2Sjtc /*
865adf1dc2Schristos * convert time to string
875adf1dc2Schristos */
885adf1dc2Schristos static void
formattime(char * buf,size_t buflen,time_t when)895adf1dc2Schristos formattime(char *buf, size_t buflen, time_t when)
905adf1dc2Schristos {
915adf1dc2Schristos int error;
925adf1dc2Schristos struct tm tm;
935adf1dc2Schristos (void)localtime_r(&when, &tm);
945adf1dc2Schristos
955adf1dc2Schristos if (when + SIXMONTHS <= time(NULL))
965adf1dc2Schristos error = strftime(buf, buflen, OLDFRMT, &tm);
975adf1dc2Schristos else
985adf1dc2Schristos error = strftime(buf, buflen, CURFRMT, &tm);
995adf1dc2Schristos
1005adf1dc2Schristos if (error == 0)
1015adf1dc2Schristos buf[0] = '\0';
1025adf1dc2Schristos }
1035adf1dc2Schristos
1045adf1dc2Schristos /*
1058b35abe2Sjtc * ls_list()
1068b35abe2Sjtc * list the members of an archive in ls format
1078b35abe2Sjtc */
1088b35abe2Sjtc
1098b35abe2Sjtc void
ls_list(ARCHD * arcn,time_t now,FILE * fp)1100c612021Schristos ls_list(ARCHD *arcn, time_t now, FILE *fp)
1118b35abe2Sjtc {
11248250187Stls struct stat *sbp;
1138b35abe2Sjtc char f_mode[MODELEN];
1148b35abe2Sjtc char f_date[DATELEN];
1155adf1dc2Schristos const char *user, *group;
1168b35abe2Sjtc
1178b35abe2Sjtc /*
1188b35abe2Sjtc * if not verbose, just print the file name
1198b35abe2Sjtc */
1208b35abe2Sjtc if (!vflag) {
1210c612021Schristos (void)fprintf(fp, "%s\n", arcn->name);
1220c612021Schristos (void)fflush(fp);
1238b35abe2Sjtc return;
1248b35abe2Sjtc }
1258b35abe2Sjtc
1268b35abe2Sjtc /*
1278b35abe2Sjtc * user wants long mode
1288b35abe2Sjtc */
1298b35abe2Sjtc sbp = &(arcn->sb);
1308b35abe2Sjtc strmode(sbp->st_mode, f_mode);
1318b35abe2Sjtc
1328b35abe2Sjtc /*
133a8e69293Skleink * time format based on age compared to the time pax was started.
1348b35abe2Sjtc */
1355adf1dc2Schristos formattime(f_date, sizeof(f_date), arcn->sb.st_mtime);
1368b35abe2Sjtc /*
1378b35abe2Sjtc * print file mode, link count, uid, gid and time
1388b35abe2Sjtc */
139a47ed375Sgrant user = user_from_uid(sbp->st_uid, 0);
140a47ed375Sgrant group = group_from_gid(sbp->st_gid, 0);
1410c612021Schristos (void)fprintf(fp, "%s%2lu %-*s %-*s ", f_mode,
1420c612021Schristos (unsigned long)sbp->st_nlink,
143d0e267dcSmycroft UT_NAMESIZE, user ? user : "", UT_GRPSIZE, group ? group : "");
1448b35abe2Sjtc
1458b35abe2Sjtc /*
1468b35abe2Sjtc * print device id's for devices, or sizes for other nodes
1478b35abe2Sjtc */
1488b35abe2Sjtc if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
1490c612021Schristos (void)fprintf(fp, "%4lu,%4lu ", (long) MAJOR(sbp->st_rdev),
150f3cd6022Schristos (long) MINOR(sbp->st_rdev));
1518b35abe2Sjtc else {
1520c612021Schristos (void)fprintf(fp, OFFT_FP("9") " ", (OFFT_T)sbp->st_size);
1538b35abe2Sjtc }
1548b35abe2Sjtc
1558b35abe2Sjtc /*
1568b35abe2Sjtc * print name and link info for hard and soft links
1578b35abe2Sjtc */
1580c612021Schristos (void)fprintf(fp, "%s %s", f_date, arcn->name);
1598b35abe2Sjtc if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
1600c612021Schristos (void)fprintf(fp, " == %s\n", arcn->ln_name);
1618b35abe2Sjtc else if (arcn->type == PAX_SLK)
1621c8b4d7bSkleink (void)fprintf(fp, " -> %s\n", arcn->ln_name);
1638b35abe2Sjtc else
1640c612021Schristos (void)fputc('\n', fp);
1650c612021Schristos (void)fflush(fp);
1668b35abe2Sjtc }
1678b35abe2Sjtc
1688b35abe2Sjtc /*
1698b35abe2Sjtc * tty_ls()
1708b35abe2Sjtc * print a short summary of file to tty.
1718b35abe2Sjtc */
1728b35abe2Sjtc
1738b35abe2Sjtc void
ls_tty(ARCHD * arcn)17448250187Stls ls_tty(ARCHD *arcn)
1758b35abe2Sjtc {
1768b35abe2Sjtc char f_date[DATELEN];
1778b35abe2Sjtc char f_mode[MODELEN];
1788b35abe2Sjtc
1795adf1dc2Schristos formattime(f_date, sizeof(f_date), arcn->sb.st_mtime);
1808b35abe2Sjtc strmode(arcn->sb.st_mode, f_mode);
1818b35abe2Sjtc tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
1828b35abe2Sjtc return;
1838b35abe2Sjtc }
1848b35abe2Sjtc
1858b35abe2Sjtc void
safe_print(const char * str,FILE * fp)1860c612021Schristos safe_print(const char *str, FILE *fp)
1878b35abe2Sjtc {
1880c612021Schristos char visbuf[5];
1890c612021Schristos const char *cp;
1908b35abe2Sjtc
1918b35abe2Sjtc /*
1920c612021Schristos * if printing to a tty, use vis(3) to print special characters.
1938b35abe2Sjtc */
1940c612021Schristos if (isatty(fileno(fp))) {
1950c612021Schristos for (cp = str; *cp; cp++) {
1960c612021Schristos (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
1970c612021Schristos (void)fputs(visbuf, fp);
1980c612021Schristos }
1990c612021Schristos } else {
2000c612021Schristos (void)fputs(str, fp);
2010c612021Schristos }
2028b35abe2Sjtc }
2038b35abe2Sjtc
2048b35abe2Sjtc /*
205d653d57cSchristos * asc_u32()
206d653d57cSchristos * convert hex/octal character string into a uint32_t. We do not have to
2078b35abe2Sjtc * check for overflow! (the headers in all supported formats are not large
2088b35abe2Sjtc * enough to create an overflow).
2098b35abe2Sjtc * NOTE: strings passed to us are NOT TERMINATED.
2108b35abe2Sjtc * Return:
211d653d57cSchristos * uint32_t value
2128b35abe2Sjtc */
2138b35abe2Sjtc
214d653d57cSchristos uint32_t
asc_u32(char * str,int len,int base)215d653d57cSchristos asc_u32(char *str, int len, int base)
2168b35abe2Sjtc {
21748250187Stls char *stop;
218d653d57cSchristos uint32_t tval = 0;
2198b35abe2Sjtc
2208b35abe2Sjtc stop = str + len;
2218b35abe2Sjtc
2228b35abe2Sjtc /*
2238b35abe2Sjtc * skip over leading blanks and zeros
2248b35abe2Sjtc */
2258b35abe2Sjtc while ((str < stop) && ((*str == ' ') || (*str == '0')))
2268b35abe2Sjtc ++str;
2278b35abe2Sjtc
2288b35abe2Sjtc /*
2298b35abe2Sjtc * for each valid digit, shift running value (tval) over to next digit
2308b35abe2Sjtc * and add next digit
2318b35abe2Sjtc */
2328b35abe2Sjtc if (base == HEX) {
2338b35abe2Sjtc while (str < stop) {
2348b35abe2Sjtc if ((*str >= '0') && (*str <= '9'))
2358b35abe2Sjtc tval = (tval << 4) + (*str++ - '0');
2368b35abe2Sjtc else if ((*str >= 'A') && (*str <= 'F'))
2378b35abe2Sjtc tval = (tval << 4) + 10 + (*str++ - 'A');
2388b35abe2Sjtc else if ((*str >= 'a') && (*str <= 'f'))
2398b35abe2Sjtc tval = (tval << 4) + 10 + (*str++ - 'a');
2408b35abe2Sjtc else
2418b35abe2Sjtc break;
2428b35abe2Sjtc }
2438b35abe2Sjtc } else {
2448b35abe2Sjtc while ((str < stop) && (*str >= '0') && (*str <= '7'))
2458b35abe2Sjtc tval = (tval << 3) + (*str++ - '0');
2468b35abe2Sjtc }
247cdec4ac1Sdsl return tval;
2488b35abe2Sjtc }
2498b35abe2Sjtc
2508b35abe2Sjtc /*
251d653d57cSchristos * u32_asc()
252d653d57cSchristos * convert an uintmax_t into an hex/oct ascii string. pads with LEADING
2538b35abe2Sjtc * ascii 0's to fill string completely
2548b35abe2Sjtc * NOTE: the string created is NOT TERMINATED.
2558b35abe2Sjtc */
2568b35abe2Sjtc
2578b35abe2Sjtc int
u32_asc(uintmax_t val,char * str,int len,int base)258d653d57cSchristos u32_asc(uintmax_t val, char *str, int len, int base)
2598b35abe2Sjtc {
26048250187Stls char *pt;
261d653d57cSchristos uint32_t digit;
262d653d57cSchristos uintmax_t p;
263d653d57cSchristos
264d653d57cSchristos p = val & TOP_HALF;
265d653d57cSchristos if (p && p != TOP_HALF)
266d653d57cSchristos return -1;
267d653d57cSchristos
268d653d57cSchristos val &= BOTTOM_HALF;
2698b35abe2Sjtc
2708b35abe2Sjtc /*
2718b35abe2Sjtc * WARNING str is not '\0' terminated by this routine
2728b35abe2Sjtc */
2738b35abe2Sjtc pt = str + len - 1;
2748b35abe2Sjtc
2758b35abe2Sjtc /*
2768b35abe2Sjtc * do a tailwise conversion (start at right most end of string to place
2778b35abe2Sjtc * least significant digit). Keep shifting until conversion value goes
2788b35abe2Sjtc * to zero (all digits were converted)
2798b35abe2Sjtc */
2808b35abe2Sjtc if (base == HEX) {
2818b35abe2Sjtc while (pt >= str) {
2828b35abe2Sjtc if ((digit = (val & 0xf)) < 10)
2838b35abe2Sjtc *pt-- = '0' + (char)digit;
2848b35abe2Sjtc else
2858b35abe2Sjtc *pt-- = 'a' + (char)(digit - 10);
2868b35abe2Sjtc if ((val = (val >> 4)) == (u_long)0)
2878b35abe2Sjtc break;
2888b35abe2Sjtc }
2898b35abe2Sjtc } else {
2908b35abe2Sjtc while (pt >= str) {
2918b35abe2Sjtc *pt-- = '0' + (char)(val & 0x7);
292d653d57cSchristos if ((val = (val >> 3)) == 0)
2938b35abe2Sjtc break;
2948b35abe2Sjtc }
2958b35abe2Sjtc }
2968b35abe2Sjtc
2978b35abe2Sjtc /*
2988b35abe2Sjtc * pad with leading ascii ZEROS. We return -1 if we ran out of space.
2998b35abe2Sjtc */
3008b35abe2Sjtc while (pt >= str)
3018b35abe2Sjtc *pt-- = '0';
302d653d57cSchristos if (val != 0)
303cdec4ac1Sdsl return -1;
304cdec4ac1Sdsl return 0;
3058b35abe2Sjtc }
3068b35abe2Sjtc
3078b35abe2Sjtc /*
308d653d57cSchristos * asc_umax()
309*a4c163faSchristos * convert hex/octal/base-256 value into a uintmax.
3108b35abe2Sjtc * NOTE: strings passed to us are NOT TERMINATED.
3118b35abe2Sjtc * Return:
312*a4c163faSchristos * uintmax_t value; UINTMAX_MAX for overflow/negative
3138b35abe2Sjtc */
3148b35abe2Sjtc
315d653d57cSchristos uintmax_t
asc_umax(char * str,int len,int base)316d653d57cSchristos asc_umax(char *str, int len, int base)
3178b35abe2Sjtc {
31848250187Stls char *stop;
319d653d57cSchristos uintmax_t tval = 0;
3208b35abe2Sjtc
3218b35abe2Sjtc stop = str + len;
3228b35abe2Sjtc
3238b35abe2Sjtc /*
324*a4c163faSchristos * if the highest bit of first byte is set, it's base-256 encoded
325*a4c163faSchristos * (base-256 is basically (n-1)-bit big endian signed
326*a4c163faSchristos */
327*a4c163faSchristos if (str < stop && (*str & 0x80)) {
328*a4c163faSchristos /*
329*a4c163faSchristos * uintmax_t can't be negative, so fail on negative numbers
330*a4c163faSchristos */
331*a4c163faSchristos if (*str & 0x40)
332*a4c163faSchristos return UINTMAX_MAX;
333*a4c163faSchristos
334*a4c163faSchristos tval = *str++ & 0x3f;
335*a4c163faSchristos while (str < stop) {
336*a4c163faSchristos /*
337*a4c163faSchristos * check for overflow
338*a4c163faSchristos */
339*a4c163faSchristos if (tval > (UINTMAX_MAX/256))
340*a4c163faSchristos return UINTMAX_MAX;
341*a4c163faSchristos tval = (tval << 8) | ((*str++) & 0xFF);
342*a4c163faSchristos }
343*a4c163faSchristos
344*a4c163faSchristos return tval;
345*a4c163faSchristos }
346*a4c163faSchristos
347*a4c163faSchristos /*
3488b35abe2Sjtc * skip over leading blanks and zeros
3498b35abe2Sjtc */
3508b35abe2Sjtc while ((str < stop) && ((*str == ' ') || (*str == '0')))
3518b35abe2Sjtc ++str;
3528b35abe2Sjtc
3538b35abe2Sjtc /*
3548b35abe2Sjtc * for each valid digit, shift running value (tval) over to next digit
3558b35abe2Sjtc * and add next digit
3568b35abe2Sjtc */
3578b35abe2Sjtc if (base == HEX) {
3588b35abe2Sjtc while (str < stop) {
3598b35abe2Sjtc if ((*str >= '0') && (*str <= '9'))
3608b35abe2Sjtc tval = (tval << 4) + (*str++ - '0');
3618b35abe2Sjtc else if ((*str >= 'A') && (*str <= 'F'))
3628b35abe2Sjtc tval = (tval << 4) + 10 + (*str++ - 'A');
3638b35abe2Sjtc else if ((*str >= 'a') && (*str <= 'f'))
3648b35abe2Sjtc tval = (tval << 4) + 10 + (*str++ - 'a');
3658b35abe2Sjtc else
3668b35abe2Sjtc break;
3678b35abe2Sjtc }
3688b35abe2Sjtc } else {
3698b35abe2Sjtc while ((str < stop) && (*str >= '0') && (*str <= '7'))
3708b35abe2Sjtc tval = (tval << 3) + (*str++ - '0');
3718b35abe2Sjtc }
372cdec4ac1Sdsl return tval;
3738b35abe2Sjtc }
3748b35abe2Sjtc
3758b35abe2Sjtc /*
376d653d57cSchristos * umax_asc()
377d653d57cSchristos * convert an uintmax_t into a hex/oct ascii string. pads with
3789ee82d31Slukem * LEADING ascii 0's to fill string completely
3798b35abe2Sjtc * NOTE: the string created is NOT TERMINATED.
3808b35abe2Sjtc */
3818b35abe2Sjtc
3828b35abe2Sjtc int
umax_asc(uintmax_t val,char * str,int len,int base)383d653d57cSchristos umax_asc(uintmax_t val, char *str, int len, int base)
3848b35abe2Sjtc {
38548250187Stls char *pt;
386d653d57cSchristos uintmax_t digit;
3878b35abe2Sjtc
3888b35abe2Sjtc /*
3898b35abe2Sjtc * WARNING str is not '\0' terminated by this routine
3908b35abe2Sjtc */
3918b35abe2Sjtc pt = str + len - 1;
3928b35abe2Sjtc
3938b35abe2Sjtc /*
3948b35abe2Sjtc * do a tailwise conversion (start at right most end of string to place
3958b35abe2Sjtc * least significant digit). Keep shifting until conversion value goes
3968b35abe2Sjtc * to zero (all digits were converted)
3978b35abe2Sjtc */
3988b35abe2Sjtc if (base == HEX) {
3998b35abe2Sjtc while (pt >= str) {
4008b35abe2Sjtc if ((digit = (val & 0xf)) < 10)
4018b35abe2Sjtc *pt-- = '0' + (char)digit;
4028b35abe2Sjtc else
4038b35abe2Sjtc *pt-- = 'a' + (char)(digit - 10);
404d653d57cSchristos if ((val = (val >> 4)) == 0)
4058b35abe2Sjtc break;
4068b35abe2Sjtc }
4078b35abe2Sjtc } else {
4088b35abe2Sjtc while (pt >= str) {
4098b35abe2Sjtc *pt-- = '0' + (char)(val & 0x7);
410d653d57cSchristos if ((val = (val >> 3)) == 0)
4118b35abe2Sjtc break;
4128b35abe2Sjtc }
4138b35abe2Sjtc }
4148b35abe2Sjtc
4158b35abe2Sjtc /*
4168b35abe2Sjtc * pad with leading ascii ZEROS. We return -1 if we ran out of space.
4178b35abe2Sjtc */
4188b35abe2Sjtc while (pt >= str)
4198b35abe2Sjtc *pt-- = '0';
420d653d57cSchristos if (val != 0)
421cdec4ac1Sdsl return -1;
422cdec4ac1Sdsl return 0;
4238b35abe2Sjtc }
4241fbe6b7eStron
4251fbe6b7eStron int
check_Aflag(void)42627f963a9Smrg check_Aflag(void)
42727f963a9Smrg {
42827f963a9Smrg
4291fbe6b7eStron if (Aflag > 0)
4301fbe6b7eStron return 1;
4311fbe6b7eStron if (Aflag == 0) {
4321fbe6b7eStron Aflag = -1;
433c1bd745cSlukem tty_warn(0,
434c1bd745cSlukem "Removing leading / from absolute path names in the archive");
4351fbe6b7eStron }
4361fbe6b7eStron return 0;
4371fbe6b7eStron }
438