xref: /titanic_44/usr/src/cmd/sgs/ar/common/file.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  *	Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  *	Use is subject to license terms.
24  */
25 
26 /*
27  *	Copyright (c) 1988 AT&T
28  *	  All Rights Reserved
29  *
30  */
31 
32 #include "gelf.h"
33 #include "inc.h"
34 #include "extern.h"
35 
36 static char *str_base;	/* start of string table for names */
37 static char *str_top;	/* pointer to next available location */
38 static char *str_base1, *str_top1;
39 static int pad_symtab;	/* # of bytes by which to pad symbol table */
40 
41 
42 /*
43  * The ar file format requires objects to be padded to an even size.
44  * We do that, but it turns out to be beneficial to go farther.
45  *
46  * ld(1) accesses archives by mmapping them into memory. If the mapped
47  * objects have the proper alignment, we can access them directly. If the
48  * alignment is wrong, libelf "slides" them so that they are also accessible.
49  * This  is expensive in time (to copy memory) and space (it causes swap
50  * to be allocated by the system to back the now-modified pages). Hence, we
51  * really want to ensure that the alignment is right.
52  *
53  * We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects
54  * at 8-byte. More recently, an elf section type has appeared that has
55  * 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So,
56  * the current strategy is to align all objects to 8-bytes.
57  *
58  * There are two important things to consider when setting this value:
59  *	1) If a new elf section that ld(1) accesses in memory appears
60  *	   with a greater than 8-byte alignment requirement, this value
61  *	   will need to be raised. Or, alternatively, the entire approach may
62  *	   need reconsideration.
63  *	2) The size of this padding must be smaller than the size of the
64  *	   smallest possible ELF section. Otherwise, the logic contained
65  *	   in recover_padding() can be tricked.
66  */
67 #define	PADSZ 8
68 
69 /*
70  * Function Prototypes
71  */
72 static long mklong_tab(int *);
73 static char *trimslash(char *s);
74 
75 static long mksymtab(ARFILEP **, int *);
76 static int writesymtab(char *, long, ARFILEP *);
77 static void savename(char *);
78 static void savelongname(ARFILE *, char *);
79 static void sputl(long, char *);
80 
81 static char *writelargefile(Cmd_info *cmd_info, long long_tab_size,
82     int longnames, ARFILEP *symlist, long nsyms, int found_obj,
83     int new_archive);
84 
85 static int sizeofmembers();
86 static int sizeofnewarchive(int, int);
87 
88 static int search_sym_tab(ARFILE *, Elf *, Elf_Scn *,
89 	long *, ARFILEP **, int *);
90 
91 
92 int
93 getaf(Cmd_info *cmd_info)
94 {
95 	Elf_Cmd cmd;
96 	int fd;
97 	char *arnam = cmd_info->arnam;
98 
99 	if (elf_version(EV_CURRENT) == EV_NONE) {
100 		error_message(ELF_VERSION_ERROR,
101 		    LIBELF_ERROR, elf_errmsg(-1));
102 		exit(1);
103 	}
104 
105 	if ((cmd_info->afd = fd = open(arnam, O_RDONLY)) == -1) {
106 		if (errno == ENOENT) {
107 			/* archive does not exist yet, may have to create one */
108 			return (fd);
109 		} else {
110 			/* problem other than "does not exist" */
111 			error_message(SYS_OPEN_ERROR,
112 			    SYSTEM_ERROR, strerror(errno), arnam);
113 			exit(1);
114 		}
115 	}
116 
117 	cmd = ELF_C_READ;
118 	cmd_info->arf = elf_begin(fd, cmd, (Elf *)0);
119 
120 	if (elf_kind(cmd_info->arf) != ELF_K_AR) {
121 		error_message(NOT_ARCHIVE_ERROR,
122 		    PLAIN_ERROR, (char *)0, arnam);
123 		if (opt_FLAG(cmd_info, a_FLAG) || opt_FLAG(cmd_info, b_FLAG))
124 			error_message(USAGE_06_ERROR,
125 			    PLAIN_ERROR, (char *)0, cmd_info->ponam);
126 		exit(1);
127 	}
128 	return (fd);
129 }
130 
131 /*
132  * Given a size, return the number of bytes required to round it
133  * up to the next PADSZ boundary.
134  */
135 static int
136 pad(int n)
137 {
138 	int r;
139 
140 	r = n % PADSZ;
141 	if (r)
142 		r = PADSZ - r;
143 
144 	return (r);
145 }
146 
147 /*
148  * If the current archive item is an object, then ar(1) may have added
149  * newline padding at the end in order to bring the following object
150  * into PADSZ alignment within the file. This padding cannot be
151  * distinguished from data using the information kept in the ar headers.
152  * This routine examines the objects, using knowledge of
153  * ELF and how our tools lay out objects to determine whether padding was
154  * added to an archive item. If so, it adjusts the st_size and
155  * st_padding fields of the file argument to reflect it.
156  */
157 static void
158 recover_padding(Elf *elf, ARFILE *file)
159 {
160 	long extent;
161 	long padding;
162 	GElf_Ehdr ehdr;
163 
164 
165 	/* ar(1) only pads objects, so bail if not looking at one */
166 	if (gelf_getclass(elf) == ELFCLASSNONE)
167 		return;
168 
169 	/*
170 	 * libelf always puts the section header array at the end
171 	 * of the object, and all of our compilers and other tools
172 	 * use libelf or follow this convention. So, it is extremely
173 	 * likely that the section header array is at the end of this
174 	 * object: Find the address at the end of the array and compare
175 	 * it to the archive ar_size. If they are within PADSZ bytes, then
176 	 * we've found the end, and the difference is padding (We assume
177 	 * that no ELF section can fit into PADSZ bytes).
178 	 */
179 	extent = gelf_getehdr(elf, &ehdr)
180 	    ? (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) : 0;
181 	padding = file->ar_size - extent;
182 
183 	if ((padding < 0) || (padding >= PADSZ)) {
184 		/*
185 		 * The section header array is not at the end of the object.
186 		 * Traverse the section headers and look for the one with
187 		 * the highest used address. If this address is within
188 		 * PADSZ bytes of ar_size, then this is the end of the object.
189 		 */
190 		Elf_Scn *scn = 0;
191 
192 		do {
193 			scn = elf_nextscn(elf, scn);
194 			if (scn) {
195 				GElf_Shdr shdr;
196 
197 				if (gelf_getshdr(scn, &shdr)) {
198 					long t = shdr.sh_offset + shdr.sh_size;
199 					if (t > extent)
200 						extent = t;
201 				}
202 			}
203 		} while (scn);
204 	}
205 
206 	/*
207 	 * Now, test the padding. We only act on padding in the range
208 	 * (0 < pad < PADSZ) (ar(1) will never add more than this). A pad
209 	 * of 0 requires no action, and any other size above (PADSZ-1) means
210 	 * that we don't understand the layout of this object, and as such,
211 	 * cannot do anything.
212 	 *
213 	 * If the padding is in range, and the raw data for the
214 	 * object is available, then we perform one additional sanity
215 	 * check before moving forward: ar(1) always pads with newline
216 	 * characters. If anything else is seen, it is not padding so
217 	 * leave it alone.
218 	 */
219 	if ((padding > 0) && (padding < PADSZ)) {
220 		if (file->ar_contents) {
221 			long cnt = padding;
222 			char *p = file->ar_contents + extent;
223 
224 			while (cnt--) {
225 				if (*p++ != '\n') {   /* No padding */
226 					padding = 0;
227 					break;
228 				}
229 			}
230 		}
231 
232 		/* Remove the padding from the size */
233 		file->ar_size -= padding;
234 		file->ar_padding = padding;
235 	}
236 }
237 
238 ARFILE *
239 getfile(Cmd_info *cmd_info)
240 {
241 	Elf_Arhdr *mem_header;
242 	ARFILE	*file;
243 	char *tmp_rawname, *file_rawname;
244 	Elf *elf;
245 	char *arnam = cmd_info->arnam;
246 	int fd = cmd_info->afd;
247 	Elf *arf = cmd_info->arf;
248 
249 	if (fd == -1)
250 		return (NULL); /* the archive doesn't exist */
251 
252 	if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
253 		return (NULL);  /* the archive is empty or have hit the end */
254 
255 	if ((mem_header = elf_getarhdr(elf)) == NULL) {
256 		error_message(ELF_MALARCHIVE_ERROR,
257 		    LIBELF_ERROR, elf_errmsg(-1),
258 		    arnam, elf_getbase(elf));
259 		exit(1);
260 	}
261 
262 	/* zip past special members like the symbol and string table members */
263 
264 	while (strncmp(mem_header->ar_name, "/", 1) == 0 ||
265 	    strncmp(mem_header->ar_name, "//", 2) == 0) {
266 		(void) elf_next(elf);
267 		(void) elf_end(elf);
268 		if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
269 			return (NULL);
270 			/* the archive is empty or have hit the end */
271 		if ((mem_header = elf_getarhdr(elf)) == NULL) {
272 			error_message(ELF_MALARCHIVE_ERROR,
273 			    LIBELF_ERROR, elf_errmsg(-1),
274 			    arnam, elf_getbase(elf));
275 			exit(0);
276 		}
277 	}
278 
279 	/*
280 	 * NOTE:
281 	 *	The mem_header->ar_name[] is set to a NULL string
282 	 *	if the archive member header has some error.
283 	 *	(See elf_getarhdr() man page.)
284 	 *	It is set to NULL for example, the ar command reads
285 	 *	the archive files created by SunOS 4.1 system.
286 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
287 	 */
288 	file = newfile();
289 	(void) strncpy(file->ar_name, mem_header->ar_name, SNAME);
290 
291 	if ((file->ar_longname
292 	    = malloc(strlen(mem_header->ar_name) + 1))
293 	    == NULL) {
294 		error_message(MALLOC_ERROR,
295 		    PLAIN_ERROR, (char *)0);
296 		exit(1);
297 	}
298 	(void) strcpy(file->ar_longname, mem_header->ar_name);
299 	if ((file->ar_rawname
300 	    = malloc(strlen(mem_header->ar_rawname) + 1))
301 	    == NULL) {
302 		error_message(MALLOC_ERROR,
303 		    PLAIN_ERROR, (char *)0);
304 		exit(1);
305 	}
306 	tmp_rawname = mem_header->ar_rawname;
307 	file_rawname = file->ar_rawname;
308 	while (!isspace(*tmp_rawname) &&
309 	    ((*file_rawname = *tmp_rawname) != '\0')) {
310 		file_rawname++;
311 		tmp_rawname++;
312 	}
313 	if (!(*tmp_rawname == '\0'))
314 		*file_rawname = '\0';
315 
316 	file->ar_date = mem_header->ar_date;
317 	file->ar_uid  = mem_header->ar_uid;
318 	file->ar_gid  = mem_header->ar_gid;
319 	file->ar_mode = (unsigned long) mem_header->ar_mode;
320 	file->ar_size = mem_header->ar_size;
321 
322 	/* reverse logic */
323 	if (!(opt_FLAG(cmd_info, t_FLAG) && !opt_FLAG(cmd_info, s_FLAG))) {
324 		size_t ptr;
325 		file->ar_flag = F_ELFRAW;
326 		if ((file->ar_contents = elf_rawfile(elf, &ptr))
327 		    == NULL) {
328 			if (ptr != 0) {
329 				error_message(ELF_RAWFILE_ERROR,
330 				    LIBELF_ERROR, elf_errmsg(-1));
331 				exit(1);
332 			}
333 		}
334 		file->ar_elf = elf;
335 	}
336 
337 	recover_padding(elf, file);
338 
339 	(void) elf_next(elf);
340 	return (file);
341 }
342 
343 ARFILE *
344 newfile(void)
345 {
346 	static ARFILE	*buffer =  NULL;
347 	static int	count = 0;
348 	ARFILE	*fileptr;
349 
350 	if (count == 0) {
351 		if ((buffer = (ARFILE *) calloc(CHUNK, sizeof (ARFILE)))
352 		    == NULL) {
353 			error_message(MALLOC_ERROR,
354 			    PLAIN_ERROR, (char *)0);
355 			exit(1);
356 		}
357 		count = CHUNK;
358 	}
359 	count--;
360 	fileptr = buffer++;
361 
362 	if (listhead)
363 		listend->ar_next = fileptr;
364 	else
365 		listhead = fileptr;
366 	listend = fileptr;
367 	return (fileptr);
368 }
369 
370 static char *
371 trimslash(char *s)
372 {
373 	static char buf[SNAME];
374 
375 	(void) strncpy(buf, trim(s), SNAME - 2);
376 	buf[SNAME - 2] = '\0';
377 	return (strcat(buf, "/"));
378 }
379 
380 char *
381 trim(char *s)
382 {
383 	char *p1, *p2;
384 
385 	for (p1 = s; *p1; p1++)
386 		;
387 	while (p1 > s) {
388 		if (*--p1 != '/')
389 			break;
390 		*p1 = 0;
391 	}
392 	p2 = s;
393 	for (p1 = s; *p1; p1++)
394 		if (*p1 == '/')
395 			p2 = p1 + 1;
396 	return (p2);
397 }
398 
399 
400 static long
401 mksymtab(ARFILEP **symlist, int *found_obj)
402 {
403 	ARFILE	*fptr;
404 	long	mem_offset = 0;
405 	Elf *elf;
406 	Elf_Scn	*scn;
407 	GElf_Ehdr ehdr;
408 	int newfd;
409 	long nsyms = 0;
410 	int class = 0;
411 	Elf_Data *data;
412 	int num_errs = 0;
413 
414 	newfd = 0;
415 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
416 		/* determine if file is coming from the archive or not */
417 		if ((fptr->ar_elf != 0) && (fptr->ar_pathname == NULL)) {
418 			/*
419 			 * I can use the saved elf descriptor.
420 			 */
421 			elf = fptr->ar_elf;
422 		} else if ((fptr->ar_elf == 0) &&
423 		    (fptr->ar_pathname != NULL)) {
424 			if ((newfd  =
425 			    open(fptr->ar_pathname, O_RDONLY)) == -1) {
426 				error_message(SYS_OPEN_ERROR,
427 				    SYSTEM_ERROR, strerror(errno),
428 				    fptr->ar_pathname);
429 				num_errs++;
430 				continue;
431 			}
432 
433 			if ((elf = elf_begin(newfd,
434 			    ELF_C_READ, (Elf *)0)) == 0) {
435 				if (fptr->ar_pathname != NULL)
436 					error_message(ELF_BEGIN_02_ERROR,
437 					    LIBELF_ERROR, elf_errmsg(-1),
438 					    fptr->ar_pathname);
439 				else
440 					error_message(ELF_BEGIN_03_ERROR,
441 					    LIBELF_ERROR, elf_errmsg(-1));
442 				(void) close(newfd);
443 				newfd = 0;
444 				num_errs++;
445 				continue;
446 			}
447 			if (elf_kind(elf) == ELF_K_AR) {
448 				if (fptr->ar_pathname != NULL)
449 					error_message(ARCHIVE_IN_ARCHIVE_ERROR,
450 					    PLAIN_ERROR, (char *)0,
451 					    fptr->ar_pathname);
452 				else
453 					error_message(ARCHIVE_USAGE_ERROR,
454 					    PLAIN_ERROR, (char *)0);
455 				if (newfd) {
456 					(void) close(newfd);
457 					newfd = 0;
458 				}
459 				(void) elf_end(elf);
460 				continue;
461 			}
462 		} else {
463 			error_message(INTERNAL_01_ERROR,
464 			    PLAIN_ERROR, (char *)0);
465 			exit(1);
466 		}
467 		if (gelf_getehdr(elf, &ehdr) != 0) {
468 			if ((class = gelf_getclass(elf)) == ELFCLASS64) {
469 				fptr->ar_flag |= F_CLASS64;
470 			} else if (class == ELFCLASS32)
471 				fptr->ar_flag |= F_CLASS32;
472 			scn = elf_getscn(elf, ehdr.e_shstrndx);
473 			if (scn == NULL) {
474 				if (fptr->ar_pathname != NULL)
475 					error_message(ELF_GETSCN_01_ERROR,
476 					    LIBELF_ERROR, elf_errmsg(-1),
477 					    fptr->ar_pathname);
478 				else
479 					error_message(ELF_GETSCN_02_ERROR,
480 					    LIBELF_ERROR, elf_errmsg(-1));
481 				num_errs++;
482 				if (newfd) {
483 					(void) close(newfd);
484 					newfd = 0;
485 				}
486 				(void) elf_end(elf);
487 				continue;
488 			}
489 
490 			data = 0;
491 			data = elf_getdata(scn, data);
492 			if (data == NULL) {
493 				if (fptr->ar_pathname != NULL)
494 					error_message(ELF_GETDATA_01_ERROR,
495 					    LIBELF_ERROR, elf_errmsg(-1),
496 					    fptr->ar_pathname);
497 				else
498 					error_message(ELF_GETDATA_02_ERROR,
499 					    LIBELF_ERROR, elf_errmsg(-1));
500 				num_errs++;
501 				if (newfd) {
502 					(void) close(newfd);
503 					newfd = 0;
504 				}
505 				(void) elf_end(elf);
506 				continue;
507 			}
508 			if (data->d_size == 0) {
509 				if (fptr->ar_pathname != NULL)
510 					error_message(W_ELF_NO_DATA_01_ERROR,
511 					    PLAIN_ERROR, (char *)0,
512 					    fptr->ar_pathname);
513 				else
514 					error_message(W_ELF_NO_DATA_02_ERROR,
515 					    PLAIN_ERROR, (char *)0);
516 				if (newfd) {
517 					(void) close(newfd);
518 					newfd = 0;
519 				}
520 				(void) elf_end(elf);
521 				num_errs++;
522 				continue;
523 			}
524 
525 			/* loop through sections to find symbol table */
526 			scn = 0;
527 			while ((scn = elf_nextscn(elf, scn)) != 0) {
528 				GElf_Shdr shdr;
529 				if (gelf_getshdr(scn, &shdr) == NULL) {
530 					if (fptr->ar_pathname != NULL)
531 						error_message(
532 						    ELF_GETDATA_01_ERROR,
533 						    LIBELF_ERROR,
534 						    elf_errmsg(-1),
535 						    fptr->ar_pathname);
536 					else
537 						error_message(
538 						    ELF_GETDATA_02_ERROR,
539 						    LIBELF_ERROR,
540 						    elf_errmsg(-1));
541 					if (newfd) {
542 						(void) close(newfd);
543 						newfd = 0;
544 					}
545 					num_errs++;
546 					(void) elf_end(elf);
547 					continue;
548 				}
549 				*found_obj = 1;
550 				if (shdr.sh_type == SHT_SYMTAB)
551 					if (search_sym_tab(fptr, elf,
552 					    scn, &nsyms, symlist,
553 					    &num_errs) == -1) {
554 						if (newfd) {
555 							(void) close(newfd);
556 							newfd = 0;
557 						}
558 						continue;
559 					}
560 			}
561 		}
562 		mem_offset += sizeof (struct ar_hdr) + fptr->ar_size;
563 		if (fptr->ar_size & 01)
564 			mem_offset++;
565 		(void) elf_end(elf);
566 		if (newfd) {
567 			(void) close(newfd);
568 			newfd = 0;
569 		}
570 	} /* for */
571 	if (num_errs)
572 		exit(1);
573 	return (nsyms);
574 }
575 
576 /*
577  * This routine writes an archive symbol table for the
578  * output archive file. The symbol table is built if
579  * there was at least one object file specified.
580  * In rare case, there could be no symbol.
581  * In this case, str_top and str_base can not be used to
582  * make the string table. So the routine adjust the size
583  * and make a dummy string table. String table is needed
584  * by elf_getarsym().
585  */
586 static int
587 writesymtab(char *dst, long nsyms, ARFILEP *symlist)
588 {
589 	char	buf1[sizeof (struct ar_hdr) + 1];
590 	char	*buf2, *bptr;
591 	int	i, j;
592 	ARFILEP	*ptr;
593 	long	sym_tab_size = 0;
594 	int sum = 0;
595 
596 	/*
597 	 * patch up archive pointers and write the symbol entries
598 	 */
599 	while ((str_top - str_base) & 03)	/* round up string table */
600 		*str_top++ = '\0';
601 	sym_tab_size = (nsyms +1) * 4 + sizeof (char) * (str_top - str_base);
602 	if (nsyms == 0)
603 		sym_tab_size += 4;
604 	sym_tab_size += pad_symtab;
605 
606 	(void) sprintf(buf1, FORMAT, SYMDIRNAME, time(0), (unsigned)0,
607 	    (unsigned)0, (unsigned)0, (long)sym_tab_size, ARFMAG);
608 
609 	if (strlen(buf1) != sizeof (struct ar_hdr)) {
610 		error_message(INTERNAL_02_ERROR);
611 		exit(1);
612 	}
613 
614 	if ((buf2 = malloc(4 * (nsyms + 1))) == NULL) {
615 		error_message(MALLOC_ERROR);
616 		error_message(DIAG_01_ERROR, errno);
617 		exit(1);
618 	}
619 	sputl(nsyms, buf2);
620 	bptr = buf2 + 4;
621 
622 	for (i = 0, j = SYMCHUNK, ptr = symlist; i < nsyms; i++, j--, ptr++) {
623 		if (!j) {
624 			j = SYMCHUNK;
625 			ptr = (ARFILEP *)*ptr;
626 		}
627 		sputl((*ptr)->ar_offset, bptr);
628 		bptr += 4;
629 	}
630 	(void) memcpy(dst, buf1, sizeof (struct ar_hdr));
631 	dst += sizeof (struct ar_hdr);
632 	sum += sizeof (struct ar_hdr);
633 
634 	(void) memcpy(dst, buf2, (nsyms + 1) * 4);
635 	dst += (nsyms + 1)*4;
636 	sum += (nsyms + 1)*4;
637 
638 	if (nsyms != 0) {
639 		(void) memcpy(dst, str_base, (str_top - str_base));
640 		dst += str_top - str_base;
641 		sum += str_top - str_base;
642 	} else {
643 		/*
644 		 * Writing a dummy string table.
645 		 */
646 		int i;
647 		for (i = 0; i < 4; i++)
648 			*dst++ = 0;
649 		sum += 4;
650 	}
651 
652 	/*
653 	 * The first member file is an ELF object. We need to make
654 	 * sure it will be placed at the PADSZ byte boundary.
655 	 */
656 	if (pad_symtab) {
657 		int i;
658 		for (i = 0; i < pad_symtab; i++)
659 			*dst++ = 0;
660 		sum += pad_symtab;
661 	}
662 
663 	free(buf2);
664 	return (sum);
665 }
666 
667 static void
668 savename(char *symbol)
669 {
670 	static int str_length = BUFSIZ * 5;
671 	char *p, *s;
672 	unsigned int i;
673 	int diff;
674 
675 	diff = 0;
676 	if (str_base == (char *)0) {
677 		/* no space allocated yet */
678 		if ((str_base = malloc((unsigned)str_length)) == NULL) {
679 			error_message(MALLOC_ERROR,
680 			    PLAIN_ERROR, (char *)0);
681 			exit(1);
682 		}
683 		str_top = str_base;
684 	}
685 
686 	p = str_top;
687 	str_top += strlen(symbol) + 1;
688 
689 	if (str_top > str_base + str_length) {
690 		char *old_base = str_base;
691 
692 		do
693 			str_length += BUFSIZ * 2;
694 		while (str_top > str_base + str_length)
695 			;
696 		if ((str_base = (char *)realloc(str_base, str_length)) ==
697 		    NULL) {
698 			error_message(MALLOC_ERROR,
699 			    PLAIN_ERROR, (char *)0);
700 			exit(1);
701 		}
702 		/*
703 		 * Re-adjust other pointers
704 		 */
705 		diff = str_base - old_base;
706 		p += diff;
707 	}
708 	for (i = 0, s = symbol; i < strlen(symbol) && *s != '\0'; i++) {
709 		*p++ = *s++;
710 	}
711 	*p++ = '\0';
712 	str_top = p;
713 }
714 
715 static void
716 savelongname(ARFILE *fptr, char *ptr_index)
717 {
718 	static int str_length = BUFSIZ * 5;
719 	char *p, *s;
720 	unsigned int i;
721 	int diff;
722 	static int bytes_used;
723 	int index;
724 	char	ptr_index1[SNAME-1];
725 
726 	diff = 0;
727 	if (str_base1 == (char *)0) {
728 		/* no space allocated yet */
729 		if ((str_base1 = malloc((unsigned)str_length))
730 		    == NULL) {
731 			error_message(MALLOC_ERROR,
732 			    PLAIN_ERROR, (char *)0);
733 			exit(1);
734 		}
735 		str_top1 = str_base1;
736 	}
737 
738 	p = str_top1;
739 	str_top1 += strlen(fptr->ar_longname) + 2;
740 
741 	index = bytes_used;
742 	(void) sprintf(ptr_index1, "%d", index); /* holds digits */
743 	(void) sprintf(ptr_index, FNFORMAT, SYMDIRNAME);
744 	ptr_index[1] = '\0';
745 	(void) strcat(ptr_index, ptr_index1);
746 	(void) strcpy(fptr->ar_name, ptr_index);
747 	bytes_used += strlen(fptr->ar_longname) + 2;
748 
749 	if (str_top1 > str_base1 + str_length) {
750 		char *old_base = str_base1;
751 
752 		do
753 			str_length += BUFSIZ * 2;
754 		while (str_top1 > str_base1 + str_length)
755 			;
756 		if ((str_base1 = (char *)realloc(str_base1, str_length))
757 		    == NULL) {
758 			error_message(MALLOC_ERROR,
759 			    PLAIN_ERROR, (char *)0);
760 			exit(1);
761 		}
762 		/*
763 		 * Re-adjust other pointers
764 		 */
765 		diff = str_base1 - old_base;
766 		p += diff;
767 	}
768 	for (i = 0, s = fptr->ar_longname;
769 	    i < strlen(fptr->ar_longname) && *s != '\0'; i++) {
770 		*p++ = *s++;
771 	}
772 	*p++ = '/';
773 	*p++ = '\n';
774 	str_top1 = p;
775 }
776 
777 char *
778 writefile(Cmd_info *cmd_info)
779 {
780 	ARFILE	* fptr;
781 	ARFILEP *symlist = 0;
782 	int i;
783 	int longnames = 0;
784 	long long_tab_size = 0;
785 	long nsyms;
786 	int new_archive = 0;
787 	char *name = cmd_info->arnam;
788 	int arsize;
789 	char *dst;
790 	char *tmp_dst;
791 	int nfd;
792 	int found_obj = 0;
793 
794 	long_tab_size = mklong_tab(&longnames);
795 	nsyms = mksymtab(&symlist, &found_obj);
796 
797 	for (i = 0; signum[i]; i++)
798 		/* started writing, cannot interrupt */
799 		(void) signal(signum[i], SIG_IGN);
800 
801 
802 	/* Is this a new archive? */
803 	if ((access(cmd_info->arnam,  0)  < 0) && (errno == ENOENT)) {
804 		new_archive = 1;
805 		if (!opt_FLAG(cmd_info, c_FLAG)) {
806 			error_message(BER_MES_CREATE_ERROR,
807 			    PLAIN_ERROR, (char *)0, cmd_info->arnam);
808 		}
809 	} else
810 		new_archive = 0;
811 
812 	/*
813 	 * Calculate the size of the new archive
814 	 */
815 	arsize = sizeofnewarchive(nsyms, longnames);
816 
817 	/*
818 	 * Dummy symtab ?
819 	 */
820 	if (nsyms == 0 && found_obj != 0)
821 		/*
822 		 * 4 + 4 = First 4 bytes to keep the number of symbols.
823 		 *	   The second 4 bytes for string table.
824 		 */
825 		arsize += sizeof (struct ar_hdr) + 4 + 4;
826 
827 	if (arsize > AR_MAX_BYTES_IN_MEM) {
828 		tmp_dst = dst = NULL;
829 	} else {
830 		tmp_dst = dst = malloc(arsize);
831 	}
832 	if (dst == NULL) {
833 		return writelargefile(cmd_info, long_tab_size,
834 		    longnames, symlist, nsyms, found_obj, new_archive);
835 	}
836 
837 	(void) memcpy(tmp_dst, ARMAG, SARMAG);
838 	tmp_dst += SARMAG;
839 
840 	if (nsyms || found_obj != 0) {
841 		int diff;
842 		diff = writesymtab(tmp_dst, nsyms, symlist);
843 		tmp_dst += diff;
844 	}
845 
846 	if (longnames) {
847 		(void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0),
848 		    (unsigned)0, (unsigned)0, (unsigned)0,
849 		    (long)long_tab_size, ARFMAG);
850 		tmp_dst += sizeof (struct ar_hdr);
851 		(void) memcpy(tmp_dst, str_base1, str_top1 - str_base1);
852 		tmp_dst += str_top1 - str_base1;
853 	}
854 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
855 
856 	/*
857 	 * NOTE:
858 	 *	The mem_header->ar_name[] is set to a NULL string
859 	 *	if the archive member header has some error.
860 	 *	(See elf_getarhdr() man page.)
861 	 *	It is set to NULL for example, the ar command reads
862 	 *	the archive files created by SunOS 4.1 system.
863 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
864 	 */
865 		if (fptr->ar_name[0] == 0) {
866 			fptr->ar_longname = fptr->ar_rawname;
867 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
868 		}
869 		if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2)
870 			(void) sprintf(tmp_dst, FNFORMAT,
871 			    trimslash(fptr->ar_longname));
872 		else
873 			(void) sprintf(tmp_dst, FNFORMAT, fptr->ar_name);
874 		(void) sprintf(tmp_dst+16, TLFORMAT, fptr->ar_date,
875 		    (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid,
876 		    (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding,
877 		    ARFMAG);
878 
879 		tmp_dst += sizeof (struct ar_hdr);
880 
881 		if (!(fptr->ar_flag & F_MALLOCED) &&
882 		    !(fptr->ar_flag & F_MMAPED) &&
883 		    !(fptr->ar_flag & F_ELFRAW)) {
884 		/* file was not read in fptr->ar_contents during 'cmd' */
885 		/* do it now */
886 			FILE *f;
887 			f = fopen(fptr->ar_pathname, "r");
888 			if (f == NULL) {
889 				error_message(SYS_OPEN_ERROR,
890 				    SYSTEM_ERROR, strerror(errno),
891 				    fptr->ar_longname);
892 				exit(1);
893 			} else {
894 				if (fread(tmp_dst, sizeof (char),
895 				    fptr->ar_size, f) != fptr->ar_size) {
896 					error_message(SYS_READ_ERROR,
897 					    SYSTEM_ERROR, strerror(errno),
898 					    fptr->ar_longname);
899 					exit(1);
900 				}
901 			}
902 			(void) fclose(f);
903 		} else {
904 			(void) memcpy(tmp_dst, fptr->ar_contents,
905 			    fptr->ar_size);
906 			if (fptr->ar_flag & F_MALLOCED) {
907 				(void) free(fptr->ar_contents);
908 				fptr->ar_flag &= ~(F_MALLOCED);
909 			}
910 		}
911 		tmp_dst += fptr->ar_size;
912 
913 		if (fptr->ar_size & 0x1) {
914 			(void) memcpy(tmp_dst, "\n", 1);
915 			tmp_dst++;
916 		}
917 
918 		if (fptr->ar_padding) {
919 			int i = fptr->ar_padding;
920 			while (i) {
921 				*tmp_dst++ = '\n';
922 				--i;
923 			}
924 		}
925 	}
926 
927 	/*
928 	 * All preparation for writing is done.
929 	 */
930 	(void) elf_end(cmd_info->arf);
931 	(void) close(cmd_info->afd);
932 
933 	/*
934 	 * Write out to the file
935 	 */
936 	if (new_archive) {
937 		/*
938 		 * create a new file
939 		 */
940 		nfd = creat(name, 0666);
941 		if (nfd == -1) {
942 			error_message(SYS_CREATE_01_ERROR,
943 			    SYSTEM_ERROR, strerror(errno), name);
944 			exit(1);
945 		}
946 	} else {
947 		/*
948 		 * Open the new file
949 		 */
950 		nfd = open(name, O_RDWR|O_TRUNC);
951 		if (nfd == -1) {
952 			error_message(SYS_WRITE_02_ERROR,
953 			    SYSTEM_ERROR, strerror(errno), name);
954 			exit(1);
955 		}
956 	}
957 #ifndef XPG4
958 	if (opt_FLAG(cmd_info, v_FLAG)) {
959 		error_message(BER_MES_WRITE_ERROR,
960 		    PLAIN_ERROR, (char *)0, cmd_info->arnam);
961 	}
962 #endif
963 	if (write(nfd, dst, arsize) != arsize) {
964 		error_message(SYS_WRITE_04_ERROR,
965 		    SYSTEM_ERROR, strerror(errno), name);
966 		if (!new_archive)
967 			error_message(WARN_USER_ERROR,
968 			    PLAIN_ERROR, (char *)0);
969 		exit(2);
970 	}
971 	return (dst);
972 }
973 
974 static long
975 mklong_tab(int *longnames)
976 {
977 	ARFILE  *fptr;
978 	char ptr_index[SNAME+1];
979 	long ret = 0;
980 
981 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
982 		if (strlen(fptr->ar_longname) >= (unsigned)SNAME-1) {
983 			(*longnames)++;
984 			savelongname(fptr, ptr_index);
985 			(void) strcpy(fptr->ar_name, ptr_index);
986 		}
987 	}
988 	if (*longnames) {
989 		/* round up table that keeps the long filenames */
990 		while ((str_top1 - str_base1) & 03)
991 			*str_top1++ = '\n';
992 		ret = sizeof (char) * (str_top1 - str_base1);
993 	}
994 	return (ret);
995 }
996 
997 /* Put bytes in archive header in machine independent order.  */
998 
999 static void
1000 sputl(long n, char *cp)
1001 {
1002 	*cp++ = n >> 24;
1003 	*cp++ = n >> 16;
1004 	*cp++ = n >> 8;
1005 
1006 	*cp++ = n & 255;
1007 }
1008 
1009 static int
1010 search_sym_tab(ARFILE *fptr, Elf *elf, Elf_Scn *scn,
1011 	long *nsyms, ARFILEP **symlist, int *num_errs)
1012 {
1013 	Elf_Data *str_data, *sym_data; /* string table, symbol table */
1014 	Elf_Scn *str_scn;
1015 	GElf_Sxword no_of_symbols;
1016 	GElf_Shdr shdr;
1017 	int counter;
1018 	int str_shtype;
1019 	char *symname;
1020 	static ARFILEP *sym_ptr = 0;
1021 	static ARFILEP *nextsym = NULL;
1022 	static int syms_left = 0;
1023 	char *fname = fptr->ar_pathname;
1024 
1025 	(void) gelf_getshdr(scn, &shdr);
1026 	str_scn = elf_getscn(elf, shdr.sh_link); /* index for string table */
1027 	if (str_scn == NULL) {
1028 		if (fname != NULL)
1029 			error_message(ELF_GETDATA_01_ERROR,
1030 			    LIBELF_ERROR, elf_errmsg(-1),
1031 			    fname);
1032 		else
1033 			error_message(ELF_GETDATA_02_ERROR,
1034 			    LIBELF_ERROR, elf_errmsg(-1));
1035 		(*num_errs)++;
1036 		return (-1);
1037 	}
1038 
1039 	no_of_symbols = shdr.sh_size / shdr.sh_entsize;
1040 	if (no_of_symbols == -1) {
1041 		error_message(SYMTAB_01_ERROR,
1042 		    PLAIN_ERROR, (char *)0);
1043 		return (-1);
1044 	}
1045 
1046 	(void) gelf_getshdr(str_scn, &shdr);
1047 	str_shtype = shdr.sh_type;
1048 	if (str_shtype == -1) {
1049 		if (fname != NULL)
1050 			error_message(ELF_GETDATA_01_ERROR,
1051 			    LIBELF_ERROR, elf_errmsg(-1), fname);
1052 		else
1053 			error_message(ELF_GETDATA_02_ERROR,
1054 			    LIBELF_ERROR, elf_errmsg(-1));
1055 		(*num_errs)++;
1056 		return (-1);
1057 	}
1058 
1059 	/* This test must happen before testing the string table. */
1060 	if (no_of_symbols == 1)
1061 		return (0);	/* no symbols; 0th symbol is the non-symbol */
1062 
1063 	if (str_shtype != SHT_STRTAB) {
1064 		if (fname != NULL)
1065 			error_message(SYMTAB_02_ERROR,
1066 			    PLAIN_ERROR, (char *)0,
1067 			    fname);
1068 		else
1069 			error_message(SYMTAB_03_ERROR,
1070 			    PLAIN_ERROR, (char *)0);
1071 		return (0);
1072 	}
1073 	str_data = 0;
1074 	if ((str_data = elf_getdata(str_scn, str_data)) == 0) {
1075 		if (fname != NULL)
1076 			error_message(SYMTAB_04_ERROR,
1077 			    PLAIN_ERROR, (char *)0,
1078 			    fname);
1079 		else
1080 			error_message(SYMTAB_05_ERROR,
1081 			    PLAIN_ERROR, (char *)0);
1082 		return (0);
1083 	}
1084 	if (str_data->d_size == 0) {
1085 		if (fname != NULL)
1086 			error_message(SYMTAB_06_ERROR,
1087 			    PLAIN_ERROR, (char *)0,
1088 			    fname);
1089 		else
1090 			error_message(SYMTAB_07_ERROR,
1091 			    PLAIN_ERROR, (char *)0);
1092 		return (0);
1093 	}
1094 	sym_data = 0;
1095 	if ((sym_data = elf_getdata(scn, sym_data)) == NULL) {
1096 		if (fname != NULL)
1097 			error_message(ELF_01_ERROR,
1098 			    LIBELF_ERROR, elf_errmsg(-1),
1099 			    fname, elf_errmsg(-1));
1100 		else
1101 			error_message(ELF_02_ERROR,
1102 			    LIBELF_ERROR, elf_errmsg(-1),
1103 			    elf_errmsg(-1));
1104 		return (0);
1105 	}
1106 
1107 	/* start at 1, first symbol entry is ignored */
1108 	for (counter = 1; counter < no_of_symbols; counter++) {
1109 		GElf_Sym sym;
1110 		(void) gelf_getsym(sym_data, counter, &sym);
1111 
1112 		symname = (char *)(str_data->d_buf) + sym.st_name;
1113 
1114 		if (((GELF_ST_BIND(sym.st_info) == STB_GLOBAL) ||
1115 		    (GELF_ST_BIND(sym.st_info) == STB_WEAK)) &&
1116 		    (sym.st_shndx != SHN_UNDEF)) {
1117 			if (!syms_left) {
1118 				sym_ptr = malloc((SYMCHUNK+1)
1119 				    * sizeof (ARFILEP));
1120 				if (sym_ptr == NULL) {
1121 					error_message(MALLOC_ERROR,
1122 					    PLAIN_ERROR, (char *)0);
1123 					exit(1);
1124 				}
1125 				syms_left = SYMCHUNK;
1126 				if (nextsym)
1127 					*nextsym = (ARFILEP)sym_ptr;
1128 				else
1129 					*symlist = sym_ptr;
1130 				nextsym = sym_ptr;
1131 			}
1132 			sym_ptr = nextsym;
1133 			nextsym++;
1134 			syms_left--;
1135 			(*nsyms)++;
1136 			*sym_ptr = fptr;
1137 			savename(symname);	/* put name in the archiver's */
1138 						/* symbol table string table */
1139 		}
1140 	}
1141 	return (0);
1142 }
1143 
1144 /*
1145  * Get the output file size
1146  */
1147 static int
1148 sizeofmembers(int psum)
1149 {
1150 	int sum = 0;
1151 	ARFILE *fptr;
1152 	int hdrsize = sizeof (struct ar_hdr);
1153 
1154 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1155 		fptr->ar_offset = psum + sum;
1156 		sum += fptr->ar_size;
1157 		if (fptr->ar_size & 01)
1158 			sum++;
1159 		sum += hdrsize;
1160 
1161 		/*
1162 		 * If the current item, and the next item are both ELF
1163 		 * objects, then add padding to current item so that the
1164 		 * next item will have PADSZ alignment.
1165 		 *
1166 		 * In any other case, set the padding to 0. If the
1167 		 * item comes from another archive, it may be carrying
1168 		 * a non-zero padding value from that archive that does
1169 		 * not apply to the one we are about to build.
1170 		 */
1171 		if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) &&
1172 		    fptr->ar_next &&
1173 		    (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) {
1174 			fptr->ar_padding = pad(psum + sum + hdrsize);
1175 			sum += fptr->ar_padding;
1176 		} else {
1177 			fptr->ar_padding = 0;
1178 		}
1179 	}
1180 	return (sum);
1181 }
1182 
1183 static int
1184 sizeofnewarchiveheader(int nsyms, int longnames)
1185 {
1186 	int sum = 0;
1187 
1188 	sum += SARMAG;
1189 
1190 	if (nsyms) {
1191 		char *top = (char *)str_top;
1192 		char *base = (char *)str_base;
1193 
1194 		while ((top - base) & 03)
1195 			top++;
1196 		sum += sizeof (struct ar_hdr);
1197 		sum += (nsyms + 1) * 4;
1198 		sum += top - base;
1199 	}
1200 
1201 	if (longnames) {
1202 		sum += sizeof (struct ar_hdr);
1203 		sum += str_top1 - str_base1;
1204 	}
1205 
1206 	/*
1207 	 * If the first member file is an ELF object,
1208 	 * we have to ensure the member contents will align
1209 	 * on PADSZ byte boundary.
1210 	 */
1211 	if (listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64))) {
1212 		pad_symtab = pad(sum + sizeof (struct ar_hdr));
1213 		sum += pad_symtab;
1214 	}
1215 
1216 	return (sum);
1217 }
1218 
1219 static int
1220 sizeofnewarchive(int nsyms, int longnames)
1221 {
1222 	int sum;
1223 
1224 	sum = sizeofnewarchiveheader(nsyms, longnames);
1225 	sum += sizeofmembers(sum);
1226 	return (sum);
1227 }
1228 
1229 static void
1230 arwrite(char *name, int nfd, char *dst, int size) {
1231 	if (write(nfd, dst, size) != size) {
1232 		error_message(SYS_WRITE_04_ERROR,
1233 		    SYSTEM_ERROR, strerror(errno), name);
1234 		exit(2);
1235 	}
1236 }
1237 
1238 static char *
1239 make_tmpname(char *filename) {
1240 	static char template[] = "arXXXXXX";
1241 	char *tmpname;
1242 	char *slash = strrchr(filename, '/');
1243 
1244 	if (slash != (char *)NULL) {
1245 		char c;
1246 
1247 		c = *slash;
1248 		*slash = 0;
1249 		tmpname = (char *)malloc(strlen(filename) +
1250 			sizeof (template) + 2);
1251 		(void) strcpy(tmpname, filename);
1252 		(void) strcat(tmpname, "/");
1253 		(void) strcat(tmpname, template);
1254 		(void) mktemp(tmpname);
1255 		*slash = c;
1256 	} else {
1257 		tmpname = malloc(sizeof (template));
1258 		(void) strcpy(tmpname, template);
1259 		(void) mktemp(tmpname);
1260 	}
1261 	return (tmpname);
1262 }
1263 
1264 static int
1265 ar_copy(char *from, char *to) {
1266 	int fromfd, tofd, nread;
1267 	int saved;
1268 	char buf[8192];
1269 
1270 	fromfd = open(from, O_RDONLY);
1271 	if (fromfd < 0)
1272 		return (-1);
1273 	tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, 0777);
1274 	if (tofd < 0) {
1275 		saved = errno;
1276 		(void) close(fromfd);
1277 		errno = saved;
1278 		return (-1);
1279 	}
1280 	while ((nread = read(fromfd, buf, sizeof (buf))) > 0) {
1281 		if (write(tofd, buf, nread) != nread) {
1282 			saved = errno;
1283 			(void) close(fromfd);
1284 			(void) close(tofd);
1285 			errno = saved;
1286 			return (-1);
1287 		}
1288 	}
1289 	saved = errno;
1290 	(void) close(fromfd);
1291 	(void) close(tofd);
1292 	if (nread < 0) {
1293 		errno = saved;
1294 		return (-1);
1295 	}
1296 	return (0);
1297 }
1298 
1299 static int
1300 ar_rename(char *from, char *to)
1301 {
1302 	int exists;
1303 	struct stat s;
1304 	int ret = 0;
1305 
1306 	exists = lstat(to, &s) == 0;
1307 
1308 	if (! exists || (!S_ISLNK(s.st_mode) && s.st_nlink == 1)) {
1309 		ret = rename(from, to);
1310 		if (ret == 0) {
1311 			if (exists) {
1312 				(void) chmod(to, s.st_mode & 0777);
1313 				if (chown(to, s.st_uid, s.st_gid) >= 0)
1314 					(void) chmod(to, s.st_mode & 07777);
1315 				}
1316 		} else {
1317 			(void) unlink(from);
1318 		}
1319 	} else {
1320 		ret = ar_copy(from, to);
1321 		(void) unlink(from);
1322 	}
1323 	return (ret);
1324 }
1325 
1326 static char *
1327 writelargefile(Cmd_info *cmd_info, long long_tab_size, int longnames,
1328 	ARFILEP *symlist, long nsyms, int found_obj, int new_archive)
1329 {
1330 	ARFILE	* fptr;
1331 	char *name = cmd_info->arnam;
1332 	int arsize;
1333 	char *dst;
1334 	char *tmp_dst;
1335 	int nfd;
1336 	char  *new_name;
1337 	FILE *f;
1338 	struct stat stbuf;
1339 
1340 	new_name = make_tmpname(name);
1341 
1342 	if (new_archive) {
1343 		nfd = open(name, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
1344 		if (nfd == -1) {
1345 			error_message(SYS_CREATE_01_ERROR,
1346 			    SYSTEM_ERROR, strerror(errno), name);
1347 			exit(1);
1348 		}
1349 	} else {
1350 		nfd = open(new_name, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
1351 		if (nfd == -1) {
1352 			error_message(SYS_WRITE_02_ERROR,
1353 			    SYSTEM_ERROR, strerror(errno), name);
1354 			exit(1);
1355 		}
1356 	}
1357 
1358 	arsize = sizeofnewarchiveheader(nsyms, longnames);
1359 	if (nsyms == 0 && found_obj != 0)
1360 		arsize += sizeof (struct ar_hdr) + 4 + 4;
1361 	if (arsize < 2048) {
1362 		arsize = 2048;
1363 	}
1364 	dst = tmp_dst = (char *)malloc(arsize);
1365 	(void) memcpy(tmp_dst, ARMAG, SARMAG);
1366 	tmp_dst += SARMAG;
1367 
1368 	if (nsyms || found_obj != 0) {
1369 		int diff;
1370 		diff = writesymtab(tmp_dst, nsyms, symlist);
1371 		tmp_dst += diff;
1372 	}
1373 
1374 	if (longnames) {
1375 		(void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0),
1376 		    (unsigned)0, (unsigned)0, (unsigned)0,
1377 		    (long)long_tab_size, ARFMAG);
1378 		tmp_dst += sizeof (struct ar_hdr);
1379 		(void) memcpy(tmp_dst, str_base1, str_top1 - str_base1);
1380 		tmp_dst += str_top1 - str_base1;
1381 	}
1382 #ifndef XPG4
1383 	if (opt_FLAG(cmd_info, v_FLAG)) {
1384 		error_message(BER_MES_WRITE_ERROR,
1385 		    PLAIN_ERROR, (char *)0,
1386 		    cmd_info->arnam);
1387 	}
1388 #endif
1389 	arwrite(name, nfd, dst, (int)(tmp_dst - dst));
1390 
1391 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1392 		if (fptr->ar_name[0] == 0) {
1393 			fptr->ar_longname = fptr->ar_rawname;
1394 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
1395 		}
1396 		if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2)
1397 			(void) sprintf(dst, FNFORMAT,
1398 			    trimslash(fptr->ar_longname));
1399 		else
1400 			(void) sprintf(dst, FNFORMAT, fptr->ar_name);
1401 		(void) sprintf(dst+16, TLFORMAT, fptr->ar_date,
1402 		    (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid,
1403 		    (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding,
1404 		    ARFMAG);
1405 		arwrite(name, nfd, dst, sizeof (struct ar_hdr));
1406 
1407 		if (!(fptr->ar_flag & F_MALLOCED) &&
1408 		    !(fptr->ar_flag & F_MMAPED) &&
1409 		    !(fptr->ar_flag & F_ELFRAW)) {
1410 			f = fopen(fptr->ar_pathname, "r");
1411 			if (stat(fptr->ar_pathname, &stbuf) < 0) {
1412 				(void) fclose(f);
1413 				f = NULL;
1414 			}
1415 			if (f == NULL) {
1416 				error_message(SYS_OPEN_ERROR,
1417 				    SYSTEM_ERROR, strerror(errno),
1418 				    fptr->ar_longname);
1419 				exit(1);
1420 			} else {
1421 				if ((fptr->ar_contents = (char *)
1422 				    malloc(ROUNDUP(stbuf.st_size))) == NULL) {
1423 					error_message(MALLOC_ERROR,
1424 					    PLAIN_ERROR, (char *)0);
1425 					exit(1);
1426 				}
1427 				if (fread(fptr->ar_contents,
1428 				    sizeof (char),
1429 				    stbuf.st_size, f) != stbuf.st_size) {
1430 					error_message(SYS_READ_ERROR,
1431 					    SYSTEM_ERROR, strerror(errno),
1432 					    fptr->ar_longname);
1433 					exit(1);
1434 				}
1435 			}
1436 			arwrite(name, nfd, fptr->ar_contents, fptr->ar_size);
1437 			(void) fclose(f);
1438 			free(fptr->ar_contents);
1439 		} else {
1440 			arwrite(name, nfd, fptr->ar_contents, fptr->ar_size);
1441 			if (fptr->ar_flag & F_MALLOCED) {
1442 				(void) free(fptr->ar_contents);
1443 				fptr->ar_flag &= ~(F_MALLOCED);
1444 			}
1445 		}
1446 
1447 		if (fptr->ar_size & 0x1) {
1448 			arwrite(name, nfd, "\n", 1);
1449 		}
1450 
1451 		if (fptr->ar_padding) {
1452 			int i = fptr->ar_padding;
1453 			while (i) {
1454 				arwrite(name, nfd, "\n", 1);
1455 				--i;
1456 			}
1457 		}
1458 	}
1459 
1460 	/*
1461 	 * All preparation for writing is done.
1462 	 */
1463 	(void) elf_end(cmd_info->arf);
1464 	(void) close(cmd_info->afd);
1465 
1466 	if (!new_archive) {
1467 		(void) ar_rename(new_name, name);
1468 	}
1469 
1470 	return (dst);
1471 }
1472