gen_subs.c revision 1.31 1 /* $NetBSD: gen_subs.c,v 1.31 2003/10/13 07:41:22 agc 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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93";
40 #else
41 __RCSID("$NetBSD: gen_subs.c,v 1.31 2003/10/13 07:41:22 agc Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/types.h>
46 #include <sys/time.h>
47 #include <sys/stat.h>
48 #include <sys/param.h>
49
50 #include <ctype.h>
51 #include <grp.h>
52 #include <pwd.h>
53 #include <vis.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <time.h>
58 #include <tzfile.h>
59 #include <unistd.h>
60
61 #include "pax.h"
62 #include "extern.h"
63
64 /*
65 * a collection of general purpose subroutines used by pax
66 */
67
68 /*
69 * constants used by ls_list() when printing out archive members
70 */
71 #define MODELEN 20
72 #define DATELEN 64
73 #define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
74 #define CURFRMT "%b %e %H:%M"
75 #define OLDFRMT "%b %e %Y"
76 #ifndef UT_NAMESIZE
77 #define UT_NAMESIZE 8
78 #endif
79 #define UT_GRPSIZE 6
80
81 /*
82 * ls_list()
83 * list the members of an archive in ls format
84 */
85
86 void
87 ls_list(ARCHD *arcn, time_t now, FILE *fp)
88 {
89 struct stat *sbp;
90 char f_mode[MODELEN];
91 char f_date[DATELEN];
92 const char *timefrmt, *user, *group;
93
94 /*
95 * if not verbose, just print the file name
96 */
97 if (!vflag) {
98 (void)fprintf(fp, "%s\n", arcn->name);
99 (void)fflush(fp);
100 return;
101 }
102
103 /*
104 * user wants long mode
105 */
106 sbp = &(arcn->sb);
107 strmode(sbp->st_mode, f_mode);
108
109 /*
110 * time format based on age compared to the time pax was started.
111 */
112 if ((sbp->st_mtime + SIXMONTHS) <= now)
113 timefrmt = OLDFRMT;
114 else
115 timefrmt = CURFRMT;
116
117 /*
118 * print file mode, link count, uid, gid and time
119 */
120 if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
121 f_date[0] = '\0';
122 user = user_from_uid(sbp->st_uid, 0);
123 group = group_from_gid(sbp->st_gid, 0);
124 (void)fprintf(fp, "%s%2lu %-*s %-*s ", f_mode,
125 (unsigned long)sbp->st_nlink,
126 UT_NAMESIZE, user ? user : "", UT_GRPSIZE, group ? group : "");
127
128 /*
129 * print device id's for devices, or sizes for other nodes
130 */
131 if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
132 (void)fprintf(fp, "%4lu,%4lu ", (long) MAJOR(sbp->st_rdev),
133 (long) MINOR(sbp->st_rdev));
134 else {
135 (void)fprintf(fp, OFFT_FP("9") " ", (OFFT_T)sbp->st_size);
136 }
137
138 /*
139 * print name and link info for hard and soft links
140 */
141 (void)fprintf(fp, "%s %s", f_date, arcn->name);
142 if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
143 (void)fprintf(fp, " == %s\n", arcn->ln_name);
144 else if (arcn->type == PAX_SLK)
145 (void)fprintf(fp, " -> %s\n", arcn->ln_name);
146 else
147 (void)fputc('\n', fp);
148 (void)fflush(fp);
149 }
150
151 /*
152 * tty_ls()
153 * print a short summary of file to tty.
154 */
155
156 void
157 ls_tty(ARCHD *arcn)
158 {
159 char f_date[DATELEN];
160 char f_mode[MODELEN];
161 const char *timefrmt;
162
163 if ((arcn->sb.st_mtime + SIXMONTHS) <= time((time_t *)NULL))
164 timefrmt = OLDFRMT;
165 else
166 timefrmt = CURFRMT;
167
168 /*
169 * convert time to string, and print
170 */
171 if (strftime(f_date, DATELEN, timefrmt,
172 localtime(&(arcn->sb.st_mtime))) == 0)
173 f_date[0] = '\0';
174 strmode(arcn->sb.st_mode, f_mode);
175 tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
176 return;
177 }
178
179 void
180 safe_print(const char *str, FILE *fp)
181 {
182 char visbuf[5];
183 const char *cp;
184
185 /*
186 * if printing to a tty, use vis(3) to print special characters.
187 */
188 if (isatty(fileno(fp))) {
189 for (cp = str; *cp; cp++) {
190 (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]);
191 (void)fputs(visbuf, fp);
192 }
193 } else {
194 (void)fputs(str, fp);
195 }
196 }
197
198 /*
199 * asc_ul()
200 * convert hex/octal character string into a u_long. We do not have to
201 * check for overflow! (the headers in all supported formats are not large
202 * enough to create an overflow).
203 * NOTE: strings passed to us are NOT TERMINATED.
204 * Return:
205 * unsigned long value
206 */
207
208 u_long
209 asc_ul(char *str, int len, int base)
210 {
211 char *stop;
212 u_long tval = 0;
213
214 stop = str + len;
215
216 /*
217 * skip over leading blanks and zeros
218 */
219 while ((str < stop) && ((*str == ' ') || (*str == '0')))
220 ++str;
221
222 /*
223 * for each valid digit, shift running value (tval) over to next digit
224 * and add next digit
225 */
226 if (base == HEX) {
227 while (str < stop) {
228 if ((*str >= '0') && (*str <= '9'))
229 tval = (tval << 4) + (*str++ - '0');
230 else if ((*str >= 'A') && (*str <= 'F'))
231 tval = (tval << 4) + 10 + (*str++ - 'A');
232 else if ((*str >= 'a') && (*str <= 'f'))
233 tval = (tval << 4) + 10 + (*str++ - 'a');
234 else
235 break;
236 }
237 } else {
238 while ((str < stop) && (*str >= '0') && (*str <= '7'))
239 tval = (tval << 3) + (*str++ - '0');
240 }
241 return(tval);
242 }
243
244 /*
245 * ul_asc()
246 * convert an unsigned long into an hex/oct ascii string. pads with LEADING
247 * ascii 0's to fill string completely
248 * NOTE: the string created is NOT TERMINATED.
249 */
250
251 int
252 ul_asc(u_long val, char *str, int len, int base)
253 {
254 char *pt;
255 u_long digit;
256
257 /*
258 * WARNING str is not '\0' terminated by this routine
259 */
260 pt = str + len - 1;
261
262 /*
263 * do a tailwise conversion (start at right most end of string to place
264 * least significant digit). Keep shifting until conversion value goes
265 * to zero (all digits were converted)
266 */
267 if (base == HEX) {
268 while (pt >= str) {
269 if ((digit = (val & 0xf)) < 10)
270 *pt-- = '0' + (char)digit;
271 else
272 *pt-- = 'a' + (char)(digit - 10);
273 if ((val = (val >> 4)) == (u_long)0)
274 break;
275 }
276 } else {
277 while (pt >= str) {
278 *pt-- = '0' + (char)(val & 0x7);
279 if ((val = (val >> 3)) == (u_long)0)
280 break;
281 }
282 }
283
284 /*
285 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
286 */
287 while (pt >= str)
288 *pt-- = '0';
289 if (val != (u_long)0)
290 return(-1);
291 return(0);
292 }
293
294 #if !defined(NET2_STAT) && !defined(_LP64)
295 /*
296 * asc_ull()
297 * convert hex/octal character string into a unsigned long long. We do
298 * not have to to check for overflow! (the headers in all supported
299 * formats are not large enough to create an overflow).
300 * NOTE: strings passed to us are NOT TERMINATED.
301 * Return:
302 * unsigned long long value
303 */
304
305 unsigned long long
306 asc_ull(char *str, int len, int base)
307 {
308 char *stop;
309 unsigned long long tval = 0;
310
311 stop = str + len;
312
313 /*
314 * skip over leading blanks and zeros
315 */
316 while ((str < stop) && ((*str == ' ') || (*str == '0')))
317 ++str;
318
319 /*
320 * for each valid digit, shift running value (tval) over to next digit
321 * and add next digit
322 */
323 if (base == HEX) {
324 while (str < stop) {
325 if ((*str >= '0') && (*str <= '9'))
326 tval = (tval << 4) + (*str++ - '0');
327 else if ((*str >= 'A') && (*str <= 'F'))
328 tval = (tval << 4) + 10 + (*str++ - 'A');
329 else if ((*str >= 'a') && (*str <= 'f'))
330 tval = (tval << 4) + 10 + (*str++ - 'a');
331 else
332 break;
333 }
334 } else {
335 while ((str < stop) && (*str >= '0') && (*str <= '7'))
336 tval = (tval << 3) + (*str++ - '0');
337 }
338 return(tval);
339 }
340
341 /*
342 * ull_asc()
343 * convert an unsigned long long into a hex/oct ascii string. pads with
344 * LEADING ascii 0's to fill string completely
345 * NOTE: the string created is NOT TERMINATED.
346 */
347
348 int
349 ull_asc(unsigned long long val, char *str, int len, int base)
350 {
351 char *pt;
352 unsigned long long digit;
353
354 /*
355 * WARNING str is not '\0' terminated by this routine
356 */
357 pt = str + len - 1;
358
359 /*
360 * do a tailwise conversion (start at right most end of string to place
361 * least significant digit). Keep shifting until conversion value goes
362 * to zero (all digits were converted)
363 */
364 if (base == HEX) {
365 while (pt >= str) {
366 if ((digit = (val & 0xf)) < 10)
367 *pt-- = '0' + (char)digit;
368 else
369 *pt-- = 'a' + (char)(digit - 10);
370 if ((val = (val >> 4)) == (unsigned long long)0)
371 break;
372 }
373 } else {
374 while (pt >= str) {
375 *pt-- = '0' + (char)(val & 0x7);
376 if ((val = (val >> 3)) == (unsigned long long)0)
377 break;
378 }
379 }
380
381 /*
382 * pad with leading ascii ZEROS. We return -1 if we ran out of space.
383 */
384 while (pt >= str)
385 *pt-- = '0';
386 if (val != (unsigned long long)0)
387 return(-1);
388 return(0);
389 }
390 #endif
391
392 int
393 check_Aflag(void)
394 {
395
396 if (Aflag > 0)
397 return 1;
398 if (Aflag == 0) {
399 Aflag = -1;
400 tty_warn(0,
401 "Removing leading / from absolute path names in the archive");
402 }
403 return 0;
404 }
405