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