Initial import from FreeBSD RELENG_4:
[dragonfly.git] / bin / pax / gen_subs.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1992 Keith Muller.
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Keith Muller of the University of California, San Diego.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93";
41#endif
42static const char rcsid[] =
43 "$FreeBSD: src/bin/pax/gen_subs.c,v 1.12.2.4 2002/03/12 17:49:17 phantom Exp $";
44#endif /* not lint */
45
46#include <sys/types.h>
47#include <sys/time.h>
48#include <sys/stat.h>
49#include <langinfo.h>
50#include <stdio.h>
51#include <utmp.h>
52#include <unistd.h>
53#include <stdlib.h>
54#include <string.h>
55#include "pax.h"
56#include "extern.h"
57
58/*
59 * a collection of general purpose subroutines used by pax
60 */
61
62/*
63 * constants used by ls_list() when printing out archive members
64 */
65#define MODELEN 20
66#define DATELEN 64
67#define SIXMONTHS ((365 / 2) * 86400)
68#define CURFRMTM "%b %e %H:%M"
69#define OLDFRMTM "%b %e %Y"
70#define CURFRMTD "%e %b %H:%M"
71#define OLDFRMTD "%e %b %Y"
72#ifndef UT_NAMESIZE
73#define UT_NAMESIZE 8
74#endif
75#define UT_GRPSIZE 6
76
77static int d_first = -1;
78
79/*
80 * ls_list()
81 * list the members of an archive in ls format
82 */
83
84#ifdef __STDC__
85void
86ls_list(register ARCHD *arcn, time_t now, FILE *fp)
87#else
88void
89ls_list(arcn, now, fp)
90 register ARCHD *arcn;
91 time_t now;
92 FILE *fp;
93#endif
94{
95 register struct stat *sbp;
96 char f_mode[MODELEN];
97 char f_date[DATELEN];
98 char *timefrmt;
99
100 /*
101 * if not verbose, just print the file name
102 */
103 if (!vflag) {
104 (void)fprintf(fp, "%s\n", arcn->name);
105 (void)fflush(fp);
106 return;
107 }
108
109 if (d_first < 0)
110 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
111 /*
112 * user wants long mode
113 */
114 sbp = &(arcn->sb);
115 strmode(sbp->st_mode, f_mode);
116
117 /*
118 * time format based on age compared to the time pax was started.
119 */
120 if ((sbp->st_mtime + SIXMONTHS) <= now)
121 timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
122 else
123 timefrmt = d_first ? CURFRMTD : CURFRMTM;
124
125 /*
126 * print file mode, link count, uid, gid and time
127 */
128 if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
129 f_date[0] = '\0';
130 (void)fprintf(fp, "%s%2u %-*s %-*s ", f_mode, sbp->st_nlink,
131 UT_NAMESIZE, name_uid(sbp->st_uid, 1), UT_GRPSIZE,
132 name_gid(sbp->st_gid, 1));
133
134 /*
135 * print device id's for devices, or sizes for other nodes
136 */
137 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
138# ifdef NET2_STAT
139 (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
140 MINOR(sbp->st_rdev));
141# else
142 (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
143 (unsigned long)MINOR(sbp->st_rdev));
144# endif
145 else {
146# ifdef NET2_STAT
147 (void)fprintf(fp, "%9lu ", sbp->st_size);
148# else
149 (void)fprintf(fp, "%9qu ", sbp->st_size);
150# endif
151 }
152
153 /*
154 * print name and link info for hard and soft links
155 */
156 (void)fprintf(fp, "%s %s", f_date, arcn->name);
157 if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
158 (void)fprintf(fp, " == %s\n", arcn->ln_name);
159 else if (arcn->type == PAX_SLK)
160 (void)fprintf(fp, " => %s\n", arcn->ln_name);
161 else
162 (void)putc('\n', fp);
163 (void)fflush(fp);
164 return;
165}
166
167/*
168 * tty_ls()
169 * print a short summary of file to tty.
170 */
171
172#ifdef __STDC__
173void
174ls_tty(register ARCHD *arcn)
175#else
176void
177ls_tty(arcn)
178 register ARCHD *arcn;
179#endif
180{
181 char f_date[DATELEN];
182 char f_mode[MODELEN];
183 char *timefrmt;
184
185 if (d_first < 0)
186 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
187
188 if ((arcn->sb.st_mtime + SIXMONTHS) <= time((time_t *)NULL))
189 timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
190 else
191 timefrmt = d_first ? CURFRMTD : CURFRMTM;
192
193 /*
194 * convert time to string, and print
195 */
196 if (strftime(f_date, DATELEN, timefrmt,
197 localtime(&(arcn->sb.st_mtime))) == 0)
198 f_date[0] = '\0';
199 strmode(arcn->sb.st_mode, f_mode);
200 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
201 return;
202}
203
204/*
205 * l_strncpy()
206 * copy src to dest up to len chars (stopping at first '\0').
207 * when src is shorter than len, pads to len with '\0'.
208 * Return:
209 * number of chars copied. (Note this is a real performance win over
210 * doing a strncpy(), a strlen(), and then a possible memset())
211 */
212
213#ifdef __STDC__
214int
215l_strncpy(register char *dest, register char *src, int len)
216#else
217int
218l_strncpy(dest, src, len)
219 register char *dest;
220 register char *src;
221 int len;
222#endif
223{
224 register char *stop;
225 register char *start;
226
227 stop = dest + len;
228 start = dest;
229 while ((dest < stop) && (*src != '\0'))
230 *dest++ = *src++;
231 len = dest - start;
232 while (dest < stop)
233 *dest++ = '\0';
234 return(len);
235}
236
237/*
238 * asc_ul()
239 * convert hex/octal character string into a u_long. We do not have to
240 * check for overflow! (the headers in all supported formats are not large
241 * enough to create an overflow).
242 * NOTE: strings passed to us are NOT TERMINATED.
243 * Return:
244 * unsigned long value
245 */
246
247#ifdef __STDC__
248u_long
249asc_ul(register char *str, int len, register int base)
250#else
251u_long
252asc_ul(str, len, base)
253 register char *str;
254 int len;
255 register int base;
256#endif
257{
258 register char *stop;
259 u_long tval = 0;
260
261 stop = str + len;
262
263 /*
264 * skip over leading blanks and zeros
265 */
266 while ((str < stop) && ((*str == ' ') || (*str == '0')))
267 ++str;
268
269 /*
270 * for each valid digit, shift running value (tval) over to next digit
271 * and add next digit
272 */
273 if (base == HEX) {
274 while (str < stop) {
275 if ((*str >= '0') && (*str <= '9'))
276 tval = (tval << 4) + (*str++ - '0');
277 else if ((*str >= 'A') && (*str <= 'F'))
278 tval = (tval << 4) + 10 + (*str++ - 'A');
279 else if ((*str >= 'a') && (*str <= 'f'))
280 tval = (tval << 4) + 10 + (*str++ - 'a');
281 else
282 break;
283 }
284 } else {
285 while ((str < stop) && (*str >= '0') && (*str <= '7'))
286 tval = (tval << 3) + (*str++ - '0');
287 }
288 return(tval);
289}
290
291/*
292 * ul_asc()
293 * convert an unsigned long into an hex/oct ascii string. pads with LEADING
294 * ascii 0's to fill string completely
295 * NOTE: the string created is NOT TERMINATED.
296 */
297
298#ifdef __STDC__
299int
300ul_asc(u_long val, register char *str, register int len, register int base)
301#else
302int
303ul_asc(val, str, len, base)
304 u_long val;
305 register char *str;
306 register int len;
307 register int base;
308#endif
309{
310 register char *pt;
311 u_long digit;
312
313 /*
314 * WARNING str is not '\0' terminated by this routine
315 */
316 pt = str + len - 1;
317
318 /*
319 * do a tailwise conversion (start at right most end of string to place
320 * least significant digit). Keep shifting until conversion value goes
321 * to zero (all digits were converted)
322 */
323 if (base == HEX) {
324 while (pt >= str) {
325 if ((digit = (val & 0xf)) < 10)
326 *pt-- = '0' + (char)digit;
327 else
328 *pt-- = 'a' + (char)(digit - 10);
329 if ((val = (val >> 4)) == (u_long)0)
330 break;
331 }
332 } else {
333 while (pt >= str) {
334 *pt-- = '0' + (char)(val & 0x7);
335 if ((val = (val >> 3)) == (u_long)0)
336 break;
337 }
338 }
339
340 /*
341 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
342 */
343 while (pt >= str)
344 *pt-- = '0';
345 if (val != (u_long)0)
346 return(-1);
347 return(0);
348}
349
350#ifndef NET2_STAT
351/*
352 * asc_uqd()
353 * convert hex/octal character string into a u_quad_t. We do not have to
354 * check for overflow! (the headers in all supported formats are not large
355 * enough to create an overflow).
356 * NOTE: strings passed to us are NOT TERMINATED.
357 * Return:
358 * u_quad_t value
359 */
360
361#ifdef __STDC__
362u_quad_t
363asc_uqd(register char *str, int len, register int base)
364#else
365u_quad_t
366asc_uqd(str, len, base)
367 register char *str;
368 int len;
369 register int base;
370#endif
371{
372 register char *stop;
373 u_quad_t tval = 0;
374
375 stop = str + len;
376
377 /*
378 * skip over leading blanks and zeros
379 */
380 while ((str < stop) && ((*str == ' ') || (*str == '0')))
381 ++str;
382
383 /*
384 * for each valid digit, shift running value (tval) over to next digit
385 * and add next digit
386 */
387 if (base == HEX) {
388 while (str < stop) {
389 if ((*str >= '0') && (*str <= '9'))
390 tval = (tval << 4) + (*str++ - '0');
391 else if ((*str >= 'A') && (*str <= 'F'))
392 tval = (tval << 4) + 10 + (*str++ - 'A');
393 else if ((*str >= 'a') && (*str <= 'f'))
394 tval = (tval << 4) + 10 + (*str++ - 'a');
395 else
396 break;
397 }
398 } else {
399 while ((str < stop) && (*str >= '0') && (*str <= '7'))
400 tval = (tval << 3) + (*str++ - '0');
401 }
402 return(tval);
403}
404
405/*
406 * uqd_asc()
407 * convert an u_quad_t into a hex/oct ascii string. pads with LEADING
408 * ascii 0's to fill string completely
409 * NOTE: the string created is NOT TERMINATED.
410 */
411
412#ifdef __STDC__
413int
414uqd_asc(u_quad_t val, register char *str, register int len, register int base)
415#else
416int
417uqd_asc(val, str, len, base)
418 u_quad_t val;
419 register char *str;
420 register int len;
421 register int base;
422#endif
423{
424 register char *pt;
425 u_quad_t digit;
426
427 /*
428 * WARNING str is not '\0' terminated by this routine
429 */
430 pt = str + len - 1;
431
432 /*
433 * do a tailwise conversion (start at right most end of string to place
434 * least significant digit). Keep shifting until conversion value goes
435 * to zero (all digits were converted)
436 */
437 if (base == HEX) {
438 while (pt >= str) {
439 if ((digit = (val & 0xf)) < 10)
440 *pt-- = '0' + (char)digit;
441 else
442 *pt-- = 'a' + (char)(digit - 10);
443 if ((val = (val >> 4)) == (u_quad_t)0)
444 break;
445 }
446 } else {
447 while (pt >= str) {
448 *pt-- = '0' + (char)(val & 0x7);
449 if ((val = (val >> 3)) == (u_quad_t)0)
450 break;
451 }
452 }
453
454 /*
455 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
456 */
457 while (pt >= str)
458 *pt-- = '0';
459 if (val != (u_quad_t)0)
460 return(-1);
461 return(0);
462}
463#endif