xref: /illumos-gate/usr/src/cmd/sgs/ar/common/file.c (revision d2d5cf7c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59d6538abSab  * Common Development and Distribution License (the "License").
69d6538abSab  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d2d5cf7cSAli Bahrami  *	Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  *	Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
287c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "gelf.h"
337c478bd9Sstevel@tonic-gate #include "inc.h"
347c478bd9Sstevel@tonic-gate #include "extern.h"
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate static char *str_base;	/* start of string table for names */
377c478bd9Sstevel@tonic-gate static char *str_top;	/* pointer to next available location */
387c478bd9Sstevel@tonic-gate static char *str_base1, *str_top1;
399d6538abSab static int pad_symtab;	/* # of bytes by which to pad symbol table */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
429d6538abSab /*
439d6538abSab  * The ar file format requires objects to be padded to an even size.
449d6538abSab  * We do that, but it turns out to be beneficial to go farther.
459d6538abSab  *
469d6538abSab  * ld(1) accesses archives by mmapping them into memory. If the mapped
479d6538abSab  * objects have the proper alignment, we can access them directly. If the
48*d2d5cf7cSAli Bahrami  * alignment is wrong, libelf "slides" them so that they are also accessible.
499d6538abSab  * This  is expensive in time (to copy memory) and space (it causes swap
509d6538abSab  * to be allocated by the system to back the now-modified pages). Hence, we
519d6538abSab  * really want to ensure that the alignment is right.
529d6538abSab  *
539d6538abSab  * We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects
549d6538abSab  * at 8-byte. More recently, an elf section type has appeared that has
559d6538abSab  * 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So,
569d6538abSab  * the current strategy is to align all objects to 8-bytes.
579d6538abSab  *
589d6538abSab  * There are two important things to consider when setting this value:
599d6538abSab  *	1) If a new elf section that ld(1) accesses in memory appears
609d6538abSab  *	   with a greater than 8-byte alignment requirement, this value
619d6538abSab  *	   will need to be raised. Or, alternatively, the entire approach may
629d6538abSab  *	   need reconsideration.
639d6538abSab  *	2) The size of this padding must be smaller than the size of the
649d6538abSab  *	   smallest possible ELF section. Otherwise, the logic contained
659d6538abSab  *	   in recover_padding() can be tricked.
669d6538abSab  */
679d6538abSab #define	PADSZ 8
689d6538abSab 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Function Prototypes
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate static long mklong_tab(int *);
737c478bd9Sstevel@tonic-gate static char *trimslash(char *s);
747c478bd9Sstevel@tonic-gate 
75*d2d5cf7cSAli Bahrami static long mksymtab(ARFILEP **, int *);
767c478bd9Sstevel@tonic-gate static int writesymtab(char *, long, ARFILEP *);
777c478bd9Sstevel@tonic-gate static void savename(char *);
787c478bd9Sstevel@tonic-gate static void savelongname(ARFILE *, char *);
797c478bd9Sstevel@tonic-gate static void sputl(long, char *);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static char *writelargefile(Cmd_info *cmd_info, long long_tab_size,
827c478bd9Sstevel@tonic-gate     int longnames, ARFILEP *symlist, long nsyms, int found_obj,
837c478bd9Sstevel@tonic-gate     int new_archive);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static int sizeofmembers();
867c478bd9Sstevel@tonic-gate static int sizeofnewarchive(int, int);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static int search_sym_tab(ARFILE *, Elf *, Elf_Scn *,
897c478bd9Sstevel@tonic-gate 	long *, ARFILEP **, int *);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate int
937c478bd9Sstevel@tonic-gate getaf(Cmd_info *cmd_info)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate 	Elf_Cmd cmd;
967c478bd9Sstevel@tonic-gate 	int fd;
977c478bd9Sstevel@tonic-gate 	char *arnam = cmd_info->arnam;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
1007c478bd9Sstevel@tonic-gate 		error_message(ELF_VERSION_ERROR,
101*d2d5cf7cSAli Bahrami 		    LIBELF_ERROR, elf_errmsg(-1));
1027c478bd9Sstevel@tonic-gate 		exit(1);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if ((cmd_info->afd = fd = open(arnam, O_RDONLY)) == -1) {
1067c478bd9Sstevel@tonic-gate 		if (errno == ENOENT) {
1077c478bd9Sstevel@tonic-gate 			/* archive does not exist yet, may have to create one */
1087c478bd9Sstevel@tonic-gate 			return (fd);
1097c478bd9Sstevel@tonic-gate 		} else {
1107c478bd9Sstevel@tonic-gate 			/* problem other than "does not exist" */
1117c478bd9Sstevel@tonic-gate 			error_message(SYS_OPEN_ERROR,
112*d2d5cf7cSAli Bahrami 			    SYSTEM_ERROR, strerror(errno), arnam);
1137c478bd9Sstevel@tonic-gate 			exit(1);
1147c478bd9Sstevel@tonic-gate 		}
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	cmd = ELF_C_READ;
1187c478bd9Sstevel@tonic-gate 	cmd_info->arf = elf_begin(fd, cmd, (Elf *)0);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if (elf_kind(cmd_info->arf) != ELF_K_AR) {
1217c478bd9Sstevel@tonic-gate 		error_message(NOT_ARCHIVE_ERROR,
122*d2d5cf7cSAli Bahrami 		    PLAIN_ERROR, (char *)0, arnam);
1237c478bd9Sstevel@tonic-gate 		if (opt_FLAG(cmd_info, a_FLAG) || opt_FLAG(cmd_info, b_FLAG))
124*d2d5cf7cSAli Bahrami 			error_message(USAGE_06_ERROR,
125*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0, cmd_info->ponam);
1267c478bd9Sstevel@tonic-gate 		exit(1);
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 	return (fd);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
13130a4e2aaSab /*
1329d6538abSab  * Given a size, return the number of bytes required to round it
1339d6538abSab  * up to the next PADSZ boundary.
1349d6538abSab  */
1359d6538abSab static int
1369d6538abSab pad(int n)
1379d6538abSab {
1389d6538abSab 	int r;
1399d6538abSab 
1409d6538abSab 	r = n % PADSZ;
1419d6538abSab 	if (r)
1429d6538abSab 		r = PADSZ - r;
1439d6538abSab 
1449d6538abSab 	return (r);
1459d6538abSab }
1469d6538abSab 
1479d6538abSab /*
1489d6538abSab  * If the current archive item is an object, then ar(1) may have added
1499d6538abSab  * newline padding at the end in order to bring the following object
1509d6538abSab  * into PADSZ alignment within the file. This padding cannot be
1519d6538abSab  * distinguished from data using the information kept in the ar headers.
1529d6538abSab  * This routine examines the objects, using knowledge of
15330a4e2aaSab  * ELF and how our tools lay out objects to determine whether padding was
15430a4e2aaSab  * added to an archive item. If so, it adjusts the st_size and
15530a4e2aaSab  * st_padding fields of the file argument to reflect it.
15630a4e2aaSab  */
15730a4e2aaSab static void
15830a4e2aaSab recover_padding(Elf *elf, ARFILE *file)
15930a4e2aaSab {
16030a4e2aaSab 	long extent;
16130a4e2aaSab 	long padding;
16230a4e2aaSab 	GElf_Ehdr ehdr;
16330a4e2aaSab 
16430a4e2aaSab 
16530a4e2aaSab 	/* ar(1) only pads objects, so bail if not looking at one */
16630a4e2aaSab 	if (gelf_getclass(elf) == ELFCLASSNONE)
16730a4e2aaSab 		return;
16830a4e2aaSab 
16930a4e2aaSab 	/*
170*d2d5cf7cSAli Bahrami 	 * libelf always puts the section header array at the end
17130a4e2aaSab 	 * of the object, and all of our compilers and other tools
172*d2d5cf7cSAli Bahrami 	 * use libelf or follow this convention. So, it is extremely
17330a4e2aaSab 	 * likely that the section header array is at the end of this
17430a4e2aaSab 	 * object: Find the address at the end of the array and compare
1759d6538abSab 	 * it to the archive ar_size. If they are within PADSZ bytes, then
1769d6538abSab 	 * we've found the end, and the difference is padding (We assume
1779d6538abSab 	 * that no ELF section can fit into PADSZ bytes).
17830a4e2aaSab 	 */
17930a4e2aaSab 	extent = gelf_getehdr(elf, &ehdr)
180*d2d5cf7cSAli Bahrami 	    ? (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) : 0;
18130a4e2aaSab 	padding = file->ar_size - extent;
18230a4e2aaSab 
1839d6538abSab 	if ((padding < 0) || (padding >= PADSZ)) {
18430a4e2aaSab 		/*
18530a4e2aaSab 		 * The section header array is not at the end of the object.
18630a4e2aaSab 		 * Traverse the section headers and look for the one with
18730a4e2aaSab 		 * the highest used address. If this address is within
1889d6538abSab 		 * PADSZ bytes of ar_size, then this is the end of the object.
18930a4e2aaSab 		 */
19030a4e2aaSab 		Elf_Scn *scn = 0;
19130a4e2aaSab 
19230a4e2aaSab 		do {
19330a4e2aaSab 			scn = elf_nextscn(elf, scn);
19430a4e2aaSab 			if (scn) {
19530a4e2aaSab 				GElf_Shdr shdr;
19630a4e2aaSab 
19730a4e2aaSab 				if (gelf_getshdr(scn, &shdr)) {
19830a4e2aaSab 					long t = shdr.sh_offset + shdr.sh_size;
19930a4e2aaSab 					if (t > extent)
20030a4e2aaSab 						extent = t;
20130a4e2aaSab 				}
20230a4e2aaSab 			}
20330a4e2aaSab 		} while (scn);
20430a4e2aaSab 	}
20530a4e2aaSab 
20630a4e2aaSab 	/*
20730a4e2aaSab 	 * Now, test the padding. We only act on padding in the range
2089d6538abSab 	 * (0 < pad < PADSZ) (ar(1) will never add more than this). A pad
2099d6538abSab 	 * of 0 requires no action, and any other size above (PADSZ-1) means
21030a4e2aaSab 	 * that we don't understand the layout of this object, and as such,
21130a4e2aaSab 	 * cannot do anything.
21230a4e2aaSab 	 *
2139d6538abSab 	 * If the padding is in range, and the raw data for the
21430a4e2aaSab 	 * object is available, then we perform one additional sanity
21530a4e2aaSab 	 * check before moving forward: ar(1) always pads with newline
21630a4e2aaSab 	 * characters. If anything else is seen, it is not padding so
21730a4e2aaSab 	 * leave it alone.
21830a4e2aaSab 	 */
2199d6538abSab 	if ((padding > 0) && (padding < PADSZ)) {
22030a4e2aaSab 		if (file->ar_contents) {
22130a4e2aaSab 			long cnt = padding;
22230a4e2aaSab 			char *p = file->ar_contents + extent;
22330a4e2aaSab 
22430a4e2aaSab 			while (cnt--) {
22530a4e2aaSab 				if (*p++ != '\n') {   /* No padding */
22630a4e2aaSab 					padding = 0;
22730a4e2aaSab 					break;
22830a4e2aaSab 				}
22930a4e2aaSab 			}
23030a4e2aaSab 		}
23130a4e2aaSab 
23230a4e2aaSab 		/* Remove the padding from the size */
23330a4e2aaSab 		file->ar_size -= padding;
23430a4e2aaSab 		file->ar_padding = padding;
23530a4e2aaSab 	}
23630a4e2aaSab }
23730a4e2aaSab 
2387c478bd9Sstevel@tonic-gate ARFILE *
2397c478bd9Sstevel@tonic-gate getfile(Cmd_info *cmd_info)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	Elf_Arhdr *mem_header;
2427c478bd9Sstevel@tonic-gate 	ARFILE	*file;
2437c478bd9Sstevel@tonic-gate 	char *tmp_rawname, *file_rawname;
2447c478bd9Sstevel@tonic-gate 	Elf *elf;
2457c478bd9Sstevel@tonic-gate 	char *arnam = cmd_info->arnam;
2467c478bd9Sstevel@tonic-gate 	int fd = cmd_info->afd;
2477c478bd9Sstevel@tonic-gate 	Elf *arf = cmd_info->arf;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (fd == -1)
2507c478bd9Sstevel@tonic-gate 		return (NULL); /* the archive doesn't exist */
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
2537c478bd9Sstevel@tonic-gate 		return (NULL);  /* the archive is empty or have hit the end */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if ((mem_header = elf_getarhdr(elf)) == NULL) {
2567c478bd9Sstevel@tonic-gate 		error_message(ELF_MALARCHIVE_ERROR,
257*d2d5cf7cSAli Bahrami 		    LIBELF_ERROR, elf_errmsg(-1),
258*d2d5cf7cSAli Bahrami 		    arnam, elf_getbase(elf));
2597c478bd9Sstevel@tonic-gate 		exit(1);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	/* zip past special members like the symbol and string table members */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	while (strncmp(mem_header->ar_name, "/", 1) == 0 ||
265*d2d5cf7cSAli Bahrami 	    strncmp(mem_header->ar_name, "//", 2) == 0) {
2667c478bd9Sstevel@tonic-gate 		(void) elf_next(elf);
2677c478bd9Sstevel@tonic-gate 		(void) elf_end(elf);
2687c478bd9Sstevel@tonic-gate 		if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
2697c478bd9Sstevel@tonic-gate 			return (NULL);
2707c478bd9Sstevel@tonic-gate 			/* the archive is empty or have hit the end */
2717c478bd9Sstevel@tonic-gate 		if ((mem_header = elf_getarhdr(elf)) == NULL) {
2727c478bd9Sstevel@tonic-gate 			error_message(ELF_MALARCHIVE_ERROR,
273*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1),
274*d2d5cf7cSAli Bahrami 			    arnam, elf_getbase(elf));
2757c478bd9Sstevel@tonic-gate 			exit(0);
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	/*
2807c478bd9Sstevel@tonic-gate 	 * NOTE:
2817c478bd9Sstevel@tonic-gate 	 *	The mem_header->ar_name[] is set to a NULL string
2827c478bd9Sstevel@tonic-gate 	 *	if the archive member header has some error.
2837c478bd9Sstevel@tonic-gate 	 *	(See elf_getarhdr() man page.)
2847c478bd9Sstevel@tonic-gate 	 *	It is set to NULL for example, the ar command reads
2857c478bd9Sstevel@tonic-gate 	 *	the archive files created by SunOS 4.1 system.
2867c478bd9Sstevel@tonic-gate 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
2877c478bd9Sstevel@tonic-gate 	 */
2887c478bd9Sstevel@tonic-gate 	file = newfile();
2897c478bd9Sstevel@tonic-gate 	(void) strncpy(file->ar_name, mem_header->ar_name, SNAME);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if ((file->ar_longname
2927c478bd9Sstevel@tonic-gate 	    = malloc(strlen(mem_header->ar_name) + 1))
2937c478bd9Sstevel@tonic-gate 	    == NULL) {
2947c478bd9Sstevel@tonic-gate 		error_message(MALLOC_ERROR,
295*d2d5cf7cSAli Bahrami 		    PLAIN_ERROR, (char *)0);
2967c478bd9Sstevel@tonic-gate 		exit(1);
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 	(void) strcpy(file->ar_longname, mem_header->ar_name);
2997c478bd9Sstevel@tonic-gate 	if ((file->ar_rawname
3007c478bd9Sstevel@tonic-gate 	    = malloc(strlen(mem_header->ar_rawname) + 1))
3017c478bd9Sstevel@tonic-gate 	    == NULL) {
3027c478bd9Sstevel@tonic-gate 		error_message(MALLOC_ERROR,
303*d2d5cf7cSAli Bahrami 		    PLAIN_ERROR, (char *)0);
3047c478bd9Sstevel@tonic-gate 		exit(1);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 	tmp_rawname = mem_header->ar_rawname;
3077c478bd9Sstevel@tonic-gate 	file_rawname = file->ar_rawname;
3087c478bd9Sstevel@tonic-gate 	while (!isspace(*tmp_rawname) &&
309*d2d5cf7cSAli Bahrami 	    ((*file_rawname = *tmp_rawname) != '\0')) {
3107c478bd9Sstevel@tonic-gate 		file_rawname++;
3117c478bd9Sstevel@tonic-gate 		tmp_rawname++;
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 	if (!(*tmp_rawname == '\0'))
3147c478bd9Sstevel@tonic-gate 		*file_rawname = '\0';
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	file->ar_date = mem_header->ar_date;
3177c478bd9Sstevel@tonic-gate 	file->ar_uid  = mem_header->ar_uid;
3187c478bd9Sstevel@tonic-gate 	file->ar_gid  = mem_header->ar_gid;
3197c478bd9Sstevel@tonic-gate 	file->ar_mode = (unsigned long) mem_header->ar_mode;
3207c478bd9Sstevel@tonic-gate 	file->ar_size = mem_header->ar_size;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* reverse logic */
3237c478bd9Sstevel@tonic-gate 	if (!(opt_FLAG(cmd_info, t_FLAG) && !opt_FLAG(cmd_info, s_FLAG))) {
3247c478bd9Sstevel@tonic-gate 		size_t ptr;
3257c478bd9Sstevel@tonic-gate 		file->ar_flag = F_ELFRAW;
3267c478bd9Sstevel@tonic-gate 		if ((file->ar_contents = elf_rawfile(elf, &ptr))
3277c478bd9Sstevel@tonic-gate 		    == NULL) {
3287c478bd9Sstevel@tonic-gate 			if (ptr != 0) {
3297c478bd9Sstevel@tonic-gate 				error_message(ELF_RAWFILE_ERROR,
330*d2d5cf7cSAli Bahrami 				    LIBELF_ERROR, elf_errmsg(-1));
3317c478bd9Sstevel@tonic-gate 				exit(1);
3327c478bd9Sstevel@tonic-gate 			}
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 		file->ar_elf = elf;
3357c478bd9Sstevel@tonic-gate 	}
33630a4e2aaSab 
33730a4e2aaSab 	recover_padding(elf, file);
33830a4e2aaSab 
3397c478bd9Sstevel@tonic-gate 	(void) elf_next(elf);
3407c478bd9Sstevel@tonic-gate 	return (file);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate ARFILE *
344d6555420Smike_s newfile(void)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	static ARFILE	*buffer =  NULL;
3477c478bd9Sstevel@tonic-gate 	static int	count = 0;
3487c478bd9Sstevel@tonic-gate 	ARFILE	*fileptr;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (count == 0) {
3517c478bd9Sstevel@tonic-gate 		if ((buffer = (ARFILE *) calloc(CHUNK, sizeof (ARFILE)))
3527c478bd9Sstevel@tonic-gate 		    == NULL) {
3537c478bd9Sstevel@tonic-gate 			error_message(MALLOC_ERROR,
354*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
3557c478bd9Sstevel@tonic-gate 			exit(1);
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 		count = CHUNK;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	count--;
3607c478bd9Sstevel@tonic-gate 	fileptr = buffer++;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (listhead)
3637c478bd9Sstevel@tonic-gate 		listend->ar_next = fileptr;
3647c478bd9Sstevel@tonic-gate 	else
3657c478bd9Sstevel@tonic-gate 		listhead = fileptr;
3667c478bd9Sstevel@tonic-gate 	listend = fileptr;
3677c478bd9Sstevel@tonic-gate 	return (fileptr);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate static char *
3717c478bd9Sstevel@tonic-gate trimslash(char *s)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	static char buf[SNAME];
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, trim(s), SNAME - 2);
3767c478bd9Sstevel@tonic-gate 	buf[SNAME - 2] = '\0';
3777c478bd9Sstevel@tonic-gate 	return (strcat(buf, "/"));
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate char *
3817c478bd9Sstevel@tonic-gate trim(char *s)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	char *p1, *p2;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	for (p1 = s; *p1; p1++)
3867c478bd9Sstevel@tonic-gate 		;
3877c478bd9Sstevel@tonic-gate 	while (p1 > s) {
3887c478bd9Sstevel@tonic-gate 		if (*--p1 != '/')
3897c478bd9Sstevel@tonic-gate 			break;
3907c478bd9Sstevel@tonic-gate 		*p1 = 0;
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 	p2 = s;
3937c478bd9Sstevel@tonic-gate 	for (p1 = s; *p1; p1++)
3947c478bd9Sstevel@tonic-gate 		if (*p1 == '/')
3957c478bd9Sstevel@tonic-gate 			p2 = p1 + 1;
3967c478bd9Sstevel@tonic-gate 	return (p2);
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate static long
401*d2d5cf7cSAli Bahrami mksymtab(ARFILEP **symlist, int *found_obj)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	ARFILE	*fptr;
4047c478bd9Sstevel@tonic-gate 	long	mem_offset = 0;
4057c478bd9Sstevel@tonic-gate 	Elf *elf;
4067c478bd9Sstevel@tonic-gate 	Elf_Scn	*scn;
4077c478bd9Sstevel@tonic-gate 	GElf_Ehdr ehdr;
4087c478bd9Sstevel@tonic-gate 	int newfd;
4097c478bd9Sstevel@tonic-gate 	long nsyms = 0;
4107c478bd9Sstevel@tonic-gate 	int class = 0;
4117c478bd9Sstevel@tonic-gate 	Elf_Data *data;
4127c478bd9Sstevel@tonic-gate 	int num_errs = 0;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	newfd = 0;
4157c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
4167c478bd9Sstevel@tonic-gate 		/* determine if file is coming from the archive or not */
4177c478bd9Sstevel@tonic-gate 		if ((fptr->ar_elf != 0) && (fptr->ar_pathname == NULL)) {
4187c478bd9Sstevel@tonic-gate 			/*
4197c478bd9Sstevel@tonic-gate 			 * I can use the saved elf descriptor.
4207c478bd9Sstevel@tonic-gate 			 */
4217c478bd9Sstevel@tonic-gate 			elf = fptr->ar_elf;
4227c478bd9Sstevel@tonic-gate 		} else if ((fptr->ar_elf == 0) &&
4237c478bd9Sstevel@tonic-gate 		    (fptr->ar_pathname != NULL)) {
4247c478bd9Sstevel@tonic-gate 			if ((newfd  =
4257c478bd9Sstevel@tonic-gate 			    open(fptr->ar_pathname, O_RDONLY)) == -1) {
4267c478bd9Sstevel@tonic-gate 				error_message(SYS_OPEN_ERROR,
427*d2d5cf7cSAli Bahrami 				    SYSTEM_ERROR, strerror(errno),
428*d2d5cf7cSAli Bahrami 				    fptr->ar_pathname);
4297c478bd9Sstevel@tonic-gate 				num_errs++;
4307c478bd9Sstevel@tonic-gate 				continue;
4317c478bd9Sstevel@tonic-gate 			}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 			if ((elf = elf_begin(newfd,
434*d2d5cf7cSAli Bahrami 			    ELF_C_READ, (Elf *)0)) == 0) {
4357c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
4367c478bd9Sstevel@tonic-gate 					error_message(ELF_BEGIN_02_ERROR,
437*d2d5cf7cSAli Bahrami 					    LIBELF_ERROR, elf_errmsg(-1),
438*d2d5cf7cSAli Bahrami 					    fptr->ar_pathname);
4397c478bd9Sstevel@tonic-gate 				else
4407c478bd9Sstevel@tonic-gate 					error_message(ELF_BEGIN_03_ERROR,
441*d2d5cf7cSAli Bahrami 					    LIBELF_ERROR, elf_errmsg(-1));
4427c478bd9Sstevel@tonic-gate 				(void) close(newfd);
4437c478bd9Sstevel@tonic-gate 				newfd = 0;
4447c478bd9Sstevel@tonic-gate 				num_errs++;
4457c478bd9Sstevel@tonic-gate 				continue;
4467c478bd9Sstevel@tonic-gate 			}
4477c478bd9Sstevel@tonic-gate 			if (elf_kind(elf) == ELF_K_AR) {
4487c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
4497c478bd9Sstevel@tonic-gate 					error_message(ARCHIVE_IN_ARCHIVE_ERROR,
450*d2d5cf7cSAli Bahrami 					    PLAIN_ERROR, (char *)0,
451*d2d5cf7cSAli Bahrami 					    fptr->ar_pathname);
4527c478bd9Sstevel@tonic-gate 				else
4537c478bd9Sstevel@tonic-gate 					error_message(ARCHIVE_USAGE_ERROR,
454*d2d5cf7cSAli Bahrami 					    PLAIN_ERROR, (char *)0);
4557c478bd9Sstevel@tonic-gate 				if (newfd) {
4567c478bd9Sstevel@tonic-gate 					(void) close(newfd);
4577c478bd9Sstevel@tonic-gate 					newfd = 0;
4587c478bd9Sstevel@tonic-gate 				}
4597c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
4607c478bd9Sstevel@tonic-gate 				continue;
4617c478bd9Sstevel@tonic-gate 			}
4627c478bd9Sstevel@tonic-gate 		} else {
4637c478bd9Sstevel@tonic-gate 			error_message(INTERNAL_01_ERROR,
464*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
4657c478bd9Sstevel@tonic-gate 			exit(1);
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 		if (gelf_getehdr(elf, &ehdr) != 0) {
4687c478bd9Sstevel@tonic-gate 			if ((class = gelf_getclass(elf)) == ELFCLASS64) {
4697c478bd9Sstevel@tonic-gate 				fptr->ar_flag |= F_CLASS64;
4707c478bd9Sstevel@tonic-gate 			} else if (class == ELFCLASS32)
4717c478bd9Sstevel@tonic-gate 				fptr->ar_flag |= F_CLASS32;
4727c478bd9Sstevel@tonic-gate 			scn = elf_getscn(elf, ehdr.e_shstrndx);
4737c478bd9Sstevel@tonic-gate 			if (scn == NULL) {
4747c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
4757c478bd9Sstevel@tonic-gate 					error_message(ELF_GETSCN_01_ERROR,
476*d2d5cf7cSAli Bahrami 					    LIBELF_ERROR, elf_errmsg(-1),
477*d2d5cf7cSAli Bahrami 					    fptr->ar_pathname);
4787c478bd9Sstevel@tonic-gate 				else
4797c478bd9Sstevel@tonic-gate 					error_message(ELF_GETSCN_02_ERROR,
480*d2d5cf7cSAli Bahrami 					    LIBELF_ERROR, elf_errmsg(-1));
4817c478bd9Sstevel@tonic-gate 				num_errs++;
4827c478bd9Sstevel@tonic-gate 				if (newfd) {
4837c478bd9Sstevel@tonic-gate 					(void) close(newfd);
4847c478bd9Sstevel@tonic-gate 					newfd = 0;
4857c478bd9Sstevel@tonic-gate 				}
4867c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
4877c478bd9Sstevel@tonic-gate 				continue;
4887c478bd9Sstevel@tonic-gate 			}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 			data = 0;
4917c478bd9Sstevel@tonic-gate 			data = elf_getdata(scn, data);
4927c478bd9Sstevel@tonic-gate 			if (data == NULL) {
4937c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
4947c478bd9Sstevel@tonic-gate 					error_message(ELF_GETDATA_01_ERROR,
495*d2d5cf7cSAli Bahrami 					    LIBELF_ERROR, elf_errmsg(-1),
496*d2d5cf7cSAli Bahrami 					    fptr->ar_pathname);
4977c478bd9Sstevel@tonic-gate 				else
4987c478bd9Sstevel@tonic-gate 					error_message(ELF_GETDATA_02_ERROR,
499*d2d5cf7cSAli Bahrami 					    LIBELF_ERROR, elf_errmsg(-1));
5007c478bd9Sstevel@tonic-gate 				num_errs++;
5017c478bd9Sstevel@tonic-gate 				if (newfd) {
5027c478bd9Sstevel@tonic-gate 					(void) close(newfd);
5037c478bd9Sstevel@tonic-gate 					newfd = 0;
5047c478bd9Sstevel@tonic-gate 				}
5057c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
5067c478bd9Sstevel@tonic-gate 				continue;
5077c478bd9Sstevel@tonic-gate 			}
5087c478bd9Sstevel@tonic-gate 			if (data->d_size == 0) {
5097c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
5107c478bd9Sstevel@tonic-gate 					error_message(W_ELF_NO_DATA_01_ERROR,
511*d2d5cf7cSAli Bahrami 					    PLAIN_ERROR, (char *)0,
512*d2d5cf7cSAli Bahrami 					    fptr->ar_pathname);
5137c478bd9Sstevel@tonic-gate 				else
5147c478bd9Sstevel@tonic-gate 					error_message(W_ELF_NO_DATA_02_ERROR,
515*d2d5cf7cSAli Bahrami 					    PLAIN_ERROR, (char *)0);
5167c478bd9Sstevel@tonic-gate 				if (newfd) {
5177c478bd9Sstevel@tonic-gate 					(void) close(newfd);
5187c478bd9Sstevel@tonic-gate 					newfd = 0;
5197c478bd9Sstevel@tonic-gate 				}
5207c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
5217c478bd9Sstevel@tonic-gate 				num_errs++;
5227c478bd9Sstevel@tonic-gate 				continue;
5237c478bd9Sstevel@tonic-gate 			}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 			/* loop through sections to find symbol table */
5267c478bd9Sstevel@tonic-gate 			scn = 0;
5277c478bd9Sstevel@tonic-gate 			while ((scn = elf_nextscn(elf, scn)) != 0) {
5287c478bd9Sstevel@tonic-gate 				GElf_Shdr shdr;
5297c478bd9Sstevel@tonic-gate 				if (gelf_getshdr(scn, &shdr) == NULL) {
5307c478bd9Sstevel@tonic-gate 					if (fptr->ar_pathname != NULL)
5317c478bd9Sstevel@tonic-gate 						error_message(
532*d2d5cf7cSAli Bahrami 						    ELF_GETDATA_01_ERROR,
533*d2d5cf7cSAli Bahrami 						    LIBELF_ERROR,
534*d2d5cf7cSAli Bahrami 						    elf_errmsg(-1),
535*d2d5cf7cSAli Bahrami 						    fptr->ar_pathname);
5367c478bd9Sstevel@tonic-gate 					else
5377c478bd9Sstevel@tonic-gate 						error_message(
538*d2d5cf7cSAli Bahrami 						    ELF_GETDATA_02_ERROR,
539*d2d5cf7cSAli Bahrami 						    LIBELF_ERROR,
540*d2d5cf7cSAli Bahrami 						    elf_errmsg(-1));
5417c478bd9Sstevel@tonic-gate 					if (newfd) {
5427c478bd9Sstevel@tonic-gate 						(void) close(newfd);
5437c478bd9Sstevel@tonic-gate 						newfd = 0;
5447c478bd9Sstevel@tonic-gate 					}
5457c478bd9Sstevel@tonic-gate 					num_errs++;
5467c478bd9Sstevel@tonic-gate 					(void) elf_end(elf);
5477c478bd9Sstevel@tonic-gate 					continue;
5487c478bd9Sstevel@tonic-gate 				}
5497c478bd9Sstevel@tonic-gate 				*found_obj = 1;
5507c478bd9Sstevel@tonic-gate 				if (shdr.sh_type == SHT_SYMTAB)
551*d2d5cf7cSAli Bahrami 					if (search_sym_tab(fptr, elf,
552*d2d5cf7cSAli Bahrami 					    scn, &nsyms, symlist,
553*d2d5cf7cSAli Bahrami 					    &num_errs) == -1) {
554*d2d5cf7cSAli Bahrami 						if (newfd) {
555*d2d5cf7cSAli Bahrami 							(void) close(newfd);
556*d2d5cf7cSAli Bahrami 							newfd = 0;
557*d2d5cf7cSAli Bahrami 						}
558*d2d5cf7cSAli Bahrami 						continue;
5597c478bd9Sstevel@tonic-gate 					}
5607c478bd9Sstevel@tonic-gate 			}
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 		mem_offset += sizeof (struct ar_hdr) + fptr->ar_size;
5637c478bd9Sstevel@tonic-gate 		if (fptr->ar_size & 01)
5647c478bd9Sstevel@tonic-gate 			mem_offset++;
5657c478bd9Sstevel@tonic-gate 		(void) elf_end(elf);
5667c478bd9Sstevel@tonic-gate 		if (newfd) {
5677c478bd9Sstevel@tonic-gate 			(void) close(newfd);
5687c478bd9Sstevel@tonic-gate 			newfd = 0;
5697c478bd9Sstevel@tonic-gate 		}
5707c478bd9Sstevel@tonic-gate 	} /* for */
5717c478bd9Sstevel@tonic-gate 	if (num_errs)
5727c478bd9Sstevel@tonic-gate 		exit(1);
5737c478bd9Sstevel@tonic-gate 	return (nsyms);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate  * This routine writes an archive symbol table for the
5787c478bd9Sstevel@tonic-gate  * output archive file. The symbol table is built if
5797c478bd9Sstevel@tonic-gate  * there was at least one object file specified.
5807c478bd9Sstevel@tonic-gate  * In rare case, there could be no symbol.
5817c478bd9Sstevel@tonic-gate  * In this case, str_top and str_base can not be used to
5827c478bd9Sstevel@tonic-gate  * make the string table. So the routine adjust the size
5837c478bd9Sstevel@tonic-gate  * and make a dummy string table. String table is needed
5847c478bd9Sstevel@tonic-gate  * by elf_getarsym().
5857c478bd9Sstevel@tonic-gate  */
5867c478bd9Sstevel@tonic-gate static int
5877c478bd9Sstevel@tonic-gate writesymtab(char *dst, long nsyms, ARFILEP *symlist)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	char	buf1[sizeof (struct ar_hdr) + 1];
5907c478bd9Sstevel@tonic-gate 	char	*buf2, *bptr;
5917c478bd9Sstevel@tonic-gate 	int	i, j;
5927c478bd9Sstevel@tonic-gate 	ARFILEP	*ptr;
5937c478bd9Sstevel@tonic-gate 	long	sym_tab_size = 0;
5947c478bd9Sstevel@tonic-gate 	int sum = 0;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	/*
5977c478bd9Sstevel@tonic-gate 	 * patch up archive pointers and write the symbol entries
5987c478bd9Sstevel@tonic-gate 	 */
5997c478bd9Sstevel@tonic-gate 	while ((str_top - str_base) & 03)	/* round up string table */
6007c478bd9Sstevel@tonic-gate 		*str_top++ = '\0';
6017c478bd9Sstevel@tonic-gate 	sym_tab_size = (nsyms +1) * 4 + sizeof (char) * (str_top - str_base);
6027c478bd9Sstevel@tonic-gate 	if (nsyms == 0)
6037c478bd9Sstevel@tonic-gate 		sym_tab_size += 4;
6047c478bd9Sstevel@tonic-gate 	sym_tab_size += pad_symtab;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	(void) sprintf(buf1, FORMAT, SYMDIRNAME, time(0), (unsigned)0,
607*d2d5cf7cSAli Bahrami 	    (unsigned)0, (unsigned)0, (long)sym_tab_size, ARFMAG);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (strlen(buf1) != sizeof (struct ar_hdr)) {
6107c478bd9Sstevel@tonic-gate 		error_message(INTERNAL_02_ERROR);
6117c478bd9Sstevel@tonic-gate 		exit(1);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	if ((buf2 = malloc(4 * (nsyms + 1))) == NULL) {
6157c478bd9Sstevel@tonic-gate 		error_message(MALLOC_ERROR);
6167c478bd9Sstevel@tonic-gate 		error_message(DIAG_01_ERROR, errno);
6177c478bd9Sstevel@tonic-gate 		exit(1);
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 	sputl(nsyms, buf2);
6207c478bd9Sstevel@tonic-gate 	bptr = buf2 + 4;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	for (i = 0, j = SYMCHUNK, ptr = symlist; i < nsyms; i++, j--, ptr++) {
6237c478bd9Sstevel@tonic-gate 		if (!j) {
6247c478bd9Sstevel@tonic-gate 			j = SYMCHUNK;
6257c478bd9Sstevel@tonic-gate 			ptr = (ARFILEP *)*ptr;
6267c478bd9Sstevel@tonic-gate 		}
6277c478bd9Sstevel@tonic-gate 		sputl((*ptr)->ar_offset, bptr);
6287c478bd9Sstevel@tonic-gate 		bptr += 4;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 	(void) memcpy(dst, buf1, sizeof (struct ar_hdr));
6317c478bd9Sstevel@tonic-gate 	dst += sizeof (struct ar_hdr);
6327c478bd9Sstevel@tonic-gate 	sum += sizeof (struct ar_hdr);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	(void) memcpy(dst, buf2, (nsyms + 1) * 4);
6357c478bd9Sstevel@tonic-gate 	dst += (nsyms + 1)*4;
6367c478bd9Sstevel@tonic-gate 	sum += (nsyms + 1)*4;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (nsyms != 0) {
6397c478bd9Sstevel@tonic-gate 		(void) memcpy(dst, str_base, (str_top - str_base));
6407c478bd9Sstevel@tonic-gate 		dst += str_top - str_base;
6417c478bd9Sstevel@tonic-gate 		sum += str_top - str_base;
6427c478bd9Sstevel@tonic-gate 	} else {
6437c478bd9Sstevel@tonic-gate 		/*
6447c478bd9Sstevel@tonic-gate 		 * Writing a dummy string table.
6457c478bd9Sstevel@tonic-gate 		 */
6467c478bd9Sstevel@tonic-gate 		int i;
6477c478bd9Sstevel@tonic-gate 		for (i = 0; i < 4; i++)
6487c478bd9Sstevel@tonic-gate 			*dst++ = 0;
6497c478bd9Sstevel@tonic-gate 		sum += 4;
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/*
6539d6538abSab 	 * The first member file is an ELF object. We need to make
6549d6538abSab 	 * sure it will be placed at the PADSZ byte boundary.
6557c478bd9Sstevel@tonic-gate 	 */
6567c478bd9Sstevel@tonic-gate 	if (pad_symtab) {
6577c478bd9Sstevel@tonic-gate 		int i;
6589d6538abSab 		for (i = 0; i < pad_symtab; i++)
6597c478bd9Sstevel@tonic-gate 			*dst++ = 0;
6609d6538abSab 		sum += pad_symtab;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	free(buf2);
6647c478bd9Sstevel@tonic-gate 	return (sum);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate static void
6687c478bd9Sstevel@tonic-gate savename(char *symbol)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	static int str_length = BUFSIZ * 5;
6717c478bd9Sstevel@tonic-gate 	char *p, *s;
6727c478bd9Sstevel@tonic-gate 	unsigned int i;
6737c478bd9Sstevel@tonic-gate 	int diff;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	diff = 0;
6767c478bd9Sstevel@tonic-gate 	if (str_base == (char *)0) {
6777c478bd9Sstevel@tonic-gate 		/* no space allocated yet */
678*d2d5cf7cSAli Bahrami 		if ((str_base = malloc((unsigned)str_length)) == NULL) {
6797c478bd9Sstevel@tonic-gate 			error_message(MALLOC_ERROR,
680*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
6817c478bd9Sstevel@tonic-gate 			exit(1);
6827c478bd9Sstevel@tonic-gate 		}
6837c478bd9Sstevel@tonic-gate 		str_top = str_base;
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	p = str_top;
6877c478bd9Sstevel@tonic-gate 	str_top += strlen(symbol) + 1;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if (str_top > str_base + str_length) {
6907c478bd9Sstevel@tonic-gate 		char *old_base = str_base;
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 		do
6937c478bd9Sstevel@tonic-gate 			str_length += BUFSIZ * 2;
694*d2d5cf7cSAli Bahrami 		while (str_top > str_base + str_length)
695*d2d5cf7cSAli Bahrami 			;
6967c478bd9Sstevel@tonic-gate 		if ((str_base = (char *)realloc(str_base, str_length)) ==
6977c478bd9Sstevel@tonic-gate 		    NULL) {
6987c478bd9Sstevel@tonic-gate 			error_message(MALLOC_ERROR,
699*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
7007c478bd9Sstevel@tonic-gate 			exit(1);
7017c478bd9Sstevel@tonic-gate 		}
7027c478bd9Sstevel@tonic-gate 		/*
7037c478bd9Sstevel@tonic-gate 		 * Re-adjust other pointers
7047c478bd9Sstevel@tonic-gate 		 */
7057c478bd9Sstevel@tonic-gate 		diff = str_base - old_base;
7067c478bd9Sstevel@tonic-gate 		p += diff;
7077c478bd9Sstevel@tonic-gate 	}
708*d2d5cf7cSAli Bahrami 	for (i = 0, s = symbol; i < strlen(symbol) && *s != '\0'; i++) {
7097c478bd9Sstevel@tonic-gate 		*p++ = *s++;
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 	*p++ = '\0';
7127c478bd9Sstevel@tonic-gate 	str_top = p;
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate static void
7167c478bd9Sstevel@tonic-gate savelongname(ARFILE *fptr, char *ptr_index)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	static int str_length = BUFSIZ * 5;
7197c478bd9Sstevel@tonic-gate 	char *p, *s;
7207c478bd9Sstevel@tonic-gate 	unsigned int i;
7217c478bd9Sstevel@tonic-gate 	int diff;
7227c478bd9Sstevel@tonic-gate 	static int bytes_used;
7237c478bd9Sstevel@tonic-gate 	int index;
7247c478bd9Sstevel@tonic-gate 	char	ptr_index1[SNAME-1];
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	diff = 0;
7277c478bd9Sstevel@tonic-gate 	if (str_base1 == (char *)0) {
7287c478bd9Sstevel@tonic-gate 		/* no space allocated yet */
7297c478bd9Sstevel@tonic-gate 		if ((str_base1 = malloc((unsigned)str_length))
7307c478bd9Sstevel@tonic-gate 		    == NULL) {
7317c478bd9Sstevel@tonic-gate 			error_message(MALLOC_ERROR,
732*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
7337c478bd9Sstevel@tonic-gate 			exit(1);
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 		str_top1 = str_base1;
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	p = str_top1;
7397c478bd9Sstevel@tonic-gate 	str_top1 += strlen(fptr->ar_longname) + 2;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	index = bytes_used;
7427c478bd9Sstevel@tonic-gate 	(void) sprintf(ptr_index1, "%d", index); /* holds digits */
7437c478bd9Sstevel@tonic-gate 	(void) sprintf(ptr_index, FNFORMAT, SYMDIRNAME);
7447c478bd9Sstevel@tonic-gate 	ptr_index[1] = '\0';
7457c478bd9Sstevel@tonic-gate 	(void) strcat(ptr_index, ptr_index1);
7467c478bd9Sstevel@tonic-gate 	(void) strcpy(fptr->ar_name, ptr_index);
7477c478bd9Sstevel@tonic-gate 	bytes_used += strlen(fptr->ar_longname) + 2;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	if (str_top1 > str_base1 + str_length) {
7507c478bd9Sstevel@tonic-gate 		char *old_base = str_base1;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 		do
7537c478bd9Sstevel@tonic-gate 			str_length += BUFSIZ * 2;
754*d2d5cf7cSAli Bahrami 		while (str_top1 > str_base1 + str_length)
755*d2d5cf7cSAli Bahrami 			;
7567c478bd9Sstevel@tonic-gate 		if ((str_base1 = (char *)realloc(str_base1, str_length))
7577c478bd9Sstevel@tonic-gate 		    == NULL) {
7587c478bd9Sstevel@tonic-gate 			error_message(MALLOC_ERROR,
759*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
7607c478bd9Sstevel@tonic-gate 			exit(1);
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 		/*
7637c478bd9Sstevel@tonic-gate 		 * Re-adjust other pointers
7647c478bd9Sstevel@tonic-gate 		 */
7657c478bd9Sstevel@tonic-gate 		diff = str_base1 - old_base;
7667c478bd9Sstevel@tonic-gate 		p += diff;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	for (i = 0, s = fptr->ar_longname;
769*d2d5cf7cSAli Bahrami 	    i < strlen(fptr->ar_longname) && *s != '\0'; i++) {
7707c478bd9Sstevel@tonic-gate 		*p++ = *s++;
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 	*p++ = '/';
7737c478bd9Sstevel@tonic-gate 	*p++ = '\n';
7747c478bd9Sstevel@tonic-gate 	str_top1 = p;
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate char *
7787c478bd9Sstevel@tonic-gate writefile(Cmd_info *cmd_info)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	ARFILE	* fptr;
7817c478bd9Sstevel@tonic-gate 	ARFILEP *symlist = 0;
7827c478bd9Sstevel@tonic-gate 	int i;
7837c478bd9Sstevel@tonic-gate 	int longnames = 0;
7847c478bd9Sstevel@tonic-gate 	long long_tab_size = 0;
7857c478bd9Sstevel@tonic-gate 	long nsyms;
7867c478bd9Sstevel@tonic-gate 	int new_archive = 0;
7877c478bd9Sstevel@tonic-gate 	char *name = cmd_info->arnam;
7887c478bd9Sstevel@tonic-gate 	int arsize;
7897c478bd9Sstevel@tonic-gate 	char *dst;
7907c478bd9Sstevel@tonic-gate 	char *tmp_dst;
7917c478bd9Sstevel@tonic-gate 	int nfd;
7927c478bd9Sstevel@tonic-gate 	int found_obj = 0;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	long_tab_size = mklong_tab(&longnames);
795*d2d5cf7cSAli Bahrami 	nsyms = mksymtab(&symlist, &found_obj);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	for (i = 0; signum[i]; i++)
7987c478bd9Sstevel@tonic-gate 		/* started writing, cannot interrupt */
7997c478bd9Sstevel@tonic-gate 		(void) signal(signum[i], SIG_IGN);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	/* Is this a new archive? */
8037c478bd9Sstevel@tonic-gate 	if ((access(cmd_info->arnam,  0)  < 0) && (errno == ENOENT)) {
804*d2d5cf7cSAli Bahrami 		new_archive = 1;
805*d2d5cf7cSAli Bahrami 		if (!opt_FLAG(cmd_info, c_FLAG)) {
806*d2d5cf7cSAli Bahrami 			error_message(BER_MES_CREATE_ERROR,
807*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0, cmd_info->arnam);
808*d2d5cf7cSAli Bahrami 		}
809*d2d5cf7cSAli Bahrami 	} else
810*d2d5cf7cSAli Bahrami 		new_archive = 0;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/*
8137c478bd9Sstevel@tonic-gate 	 * Calculate the size of the new archive
8147c478bd9Sstevel@tonic-gate 	 */
8157c478bd9Sstevel@tonic-gate 	arsize = sizeofnewarchive(nsyms, longnames);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	/*
8187c478bd9Sstevel@tonic-gate 	 * Dummy symtab ?
8197c478bd9Sstevel@tonic-gate 	 */
8207c478bd9Sstevel@tonic-gate 	if (nsyms == 0 && found_obj != 0)
8217c478bd9Sstevel@tonic-gate 		/*
8227c478bd9Sstevel@tonic-gate 		 * 4 + 4 = First 4 bytes to keep the number of symbols.
8237c478bd9Sstevel@tonic-gate 		 *	   The second 4 bytes for string table.
8247c478bd9Sstevel@tonic-gate 		 */
8257c478bd9Sstevel@tonic-gate 		arsize += sizeof (struct ar_hdr) + 4 + 4;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	if (arsize > AR_MAX_BYTES_IN_MEM) {
8287c478bd9Sstevel@tonic-gate 		tmp_dst = dst = NULL;
8297c478bd9Sstevel@tonic-gate 	} else {
8307c478bd9Sstevel@tonic-gate 		tmp_dst = dst = malloc(arsize);
8317c478bd9Sstevel@tonic-gate 	}
8327c478bd9Sstevel@tonic-gate 	if (dst == NULL) {
8337c478bd9Sstevel@tonic-gate 		return writelargefile(cmd_info, long_tab_size,
834*d2d5cf7cSAli Bahrami 		    longnames, symlist, nsyms, found_obj, new_archive);
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	(void) memcpy(tmp_dst, ARMAG, SARMAG);
8387c478bd9Sstevel@tonic-gate 	tmp_dst += SARMAG;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	if (nsyms || found_obj != 0) {
8417c478bd9Sstevel@tonic-gate 		int diff;
8427c478bd9Sstevel@tonic-gate 		diff = writesymtab(tmp_dst, nsyms, symlist);
8437c478bd9Sstevel@tonic-gate 		tmp_dst += diff;
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	if (longnames) {
8477c478bd9Sstevel@tonic-gate 		(void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0),
848*d2d5cf7cSAli Bahrami 		    (unsigned)0, (unsigned)0, (unsigned)0,
849*d2d5cf7cSAli Bahrami 		    (long)long_tab_size, ARFMAG);
8507c478bd9Sstevel@tonic-gate 		tmp_dst += sizeof (struct ar_hdr);
8517c478bd9Sstevel@tonic-gate 		(void) memcpy(tmp_dst, str_base1, str_top1 - str_base1);
8527c478bd9Sstevel@tonic-gate 		tmp_dst += str_top1 - str_base1;
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/*
8577c478bd9Sstevel@tonic-gate 	 * NOTE:
8587c478bd9Sstevel@tonic-gate 	 *	The mem_header->ar_name[] is set to a NULL string
8597c478bd9Sstevel@tonic-gate 	 *	if the archive member header has some error.
8607c478bd9Sstevel@tonic-gate 	 *	(See elf_getarhdr() man page.)
8617c478bd9Sstevel@tonic-gate 	 *	It is set to NULL for example, the ar command reads
8627c478bd9Sstevel@tonic-gate 	 *	the archive files created by SunOS 4.1 system.
8637c478bd9Sstevel@tonic-gate 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
8647c478bd9Sstevel@tonic-gate 	 */
8657c478bd9Sstevel@tonic-gate 		if (fptr->ar_name[0] == 0) {
8667c478bd9Sstevel@tonic-gate 			fptr->ar_longname = fptr->ar_rawname;
8677c478bd9Sstevel@tonic-gate 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 		if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2)
8707c478bd9Sstevel@tonic-gate 			(void) sprintf(tmp_dst, FNFORMAT,
871*d2d5cf7cSAli Bahrami 			    trimslash(fptr->ar_longname));
8727c478bd9Sstevel@tonic-gate 		else
8737c478bd9Sstevel@tonic-gate 			(void) sprintf(tmp_dst, FNFORMAT, fptr->ar_name);
8747c478bd9Sstevel@tonic-gate 		(void) sprintf(tmp_dst+16, TLFORMAT, fptr->ar_date,
8757c478bd9Sstevel@tonic-gate 		    (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid,
8767c478bd9Sstevel@tonic-gate 		    (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding,
8777c478bd9Sstevel@tonic-gate 		    ARFMAG);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		tmp_dst += sizeof (struct ar_hdr);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 		if (!(fptr->ar_flag & F_MALLOCED) &&
8827c478bd9Sstevel@tonic-gate 		    !(fptr->ar_flag & F_MMAPED) &&
8837c478bd9Sstevel@tonic-gate 		    !(fptr->ar_flag & F_ELFRAW)) {
8847c478bd9Sstevel@tonic-gate 		/* file was not read in fptr->ar_contents during 'cmd' */
8857c478bd9Sstevel@tonic-gate 		/* do it now */
8867c478bd9Sstevel@tonic-gate 			FILE *f;
8877c478bd9Sstevel@tonic-gate 			f = fopen(fptr->ar_pathname, "r");
8887c478bd9Sstevel@tonic-gate 			if (f == NULL) {
8897c478bd9Sstevel@tonic-gate 				error_message(SYS_OPEN_ERROR,
8907c478bd9Sstevel@tonic-gate 				    SYSTEM_ERROR, strerror(errno),
8917c478bd9Sstevel@tonic-gate 				    fptr->ar_longname);
8927c478bd9Sstevel@tonic-gate 				exit(1);
8937c478bd9Sstevel@tonic-gate 			} else {
894*d2d5cf7cSAli Bahrami 				if (fread(tmp_dst, sizeof (char),
8957c478bd9Sstevel@tonic-gate 				    fptr->ar_size, f) != fptr->ar_size) {
8967c478bd9Sstevel@tonic-gate 					error_message(SYS_READ_ERROR,
897*d2d5cf7cSAli Bahrami 					    SYSTEM_ERROR, strerror(errno),
898*d2d5cf7cSAli Bahrami 					    fptr->ar_longname);
8997c478bd9Sstevel@tonic-gate 					exit(1);
9007c478bd9Sstevel@tonic-gate 				}
9017c478bd9Sstevel@tonic-gate 			}
902d6555420Smike_s 			(void) fclose(f);
9037c478bd9Sstevel@tonic-gate 		} else {
9047c478bd9Sstevel@tonic-gate 			(void) memcpy(tmp_dst, fptr->ar_contents,
905*d2d5cf7cSAli Bahrami 			    fptr->ar_size);
9067c478bd9Sstevel@tonic-gate 			if (fptr->ar_flag & F_MALLOCED) {
9077c478bd9Sstevel@tonic-gate 				(void) free(fptr->ar_contents);
9087c478bd9Sstevel@tonic-gate 				fptr->ar_flag &= ~(F_MALLOCED);
9097c478bd9Sstevel@tonic-gate 			}
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 		tmp_dst += fptr->ar_size;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 		if (fptr->ar_size & 0x1) {
9147c478bd9Sstevel@tonic-gate 			(void) memcpy(tmp_dst, "\n", 1);
9157c478bd9Sstevel@tonic-gate 			tmp_dst++;
9167c478bd9Sstevel@tonic-gate 		}
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 		if (fptr->ar_padding) {
9197c478bd9Sstevel@tonic-gate 			int i = fptr->ar_padding;
9207c478bd9Sstevel@tonic-gate 			while (i) {
9217c478bd9Sstevel@tonic-gate 				*tmp_dst++ = '\n';
9227c478bd9Sstevel@tonic-gate 				--i;
9237c478bd9Sstevel@tonic-gate 			}
9247c478bd9Sstevel@tonic-gate 		}
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/*
9287c478bd9Sstevel@tonic-gate 	 * All preparation for writing is done.
9297c478bd9Sstevel@tonic-gate 	 */
9307c478bd9Sstevel@tonic-gate 	(void) elf_end(cmd_info->arf);
9317c478bd9Sstevel@tonic-gate 	(void) close(cmd_info->afd);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/*
9347c478bd9Sstevel@tonic-gate 	 * Write out to the file
9357c478bd9Sstevel@tonic-gate 	 */
9367c478bd9Sstevel@tonic-gate 	if (new_archive) {
9377c478bd9Sstevel@tonic-gate 		/*
9387c478bd9Sstevel@tonic-gate 		 * create a new file
9397c478bd9Sstevel@tonic-gate 		 */
9407c478bd9Sstevel@tonic-gate 		nfd = creat(name, 0666);
9417c478bd9Sstevel@tonic-gate 		if (nfd == -1) {
9427c478bd9Sstevel@tonic-gate 			error_message(SYS_CREATE_01_ERROR,
943*d2d5cf7cSAli Bahrami 			    SYSTEM_ERROR, strerror(errno), name);
9447c478bd9Sstevel@tonic-gate 			exit(1);
9457c478bd9Sstevel@tonic-gate 		}
9467c478bd9Sstevel@tonic-gate 	} else {
9477c478bd9Sstevel@tonic-gate 		/*
9487c478bd9Sstevel@tonic-gate 		 * Open the new file
9497c478bd9Sstevel@tonic-gate 		 */
9507c478bd9Sstevel@tonic-gate 		nfd = open(name, O_RDWR|O_TRUNC);
9517c478bd9Sstevel@tonic-gate 		if (nfd == -1) {
9527c478bd9Sstevel@tonic-gate 			error_message(SYS_WRITE_02_ERROR,
953*d2d5cf7cSAli Bahrami 			    SYSTEM_ERROR, strerror(errno), name);
9547c478bd9Sstevel@tonic-gate 			exit(1);
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate #ifndef XPG4
9587c478bd9Sstevel@tonic-gate 	if (opt_FLAG(cmd_info, v_FLAG)) {
959*d2d5cf7cSAli Bahrami 		error_message(BER_MES_WRITE_ERROR,
960*d2d5cf7cSAli Bahrami 		    PLAIN_ERROR, (char *)0, cmd_info->arnam);
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate #endif
9637c478bd9Sstevel@tonic-gate 	if (write(nfd, dst, arsize) != arsize) {
9647c478bd9Sstevel@tonic-gate 		error_message(SYS_WRITE_04_ERROR,
965*d2d5cf7cSAli Bahrami 		    SYSTEM_ERROR, strerror(errno), name);
9667c478bd9Sstevel@tonic-gate 		if (!new_archive)
9677c478bd9Sstevel@tonic-gate 			error_message(WARN_USER_ERROR,
968*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
9697c478bd9Sstevel@tonic-gate 		exit(2);
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 	return (dst);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate static long
9757c478bd9Sstevel@tonic-gate mklong_tab(int *longnames)
9767c478bd9Sstevel@tonic-gate {
9777c478bd9Sstevel@tonic-gate 	ARFILE  *fptr;
9787c478bd9Sstevel@tonic-gate 	char ptr_index[SNAME+1];
9797c478bd9Sstevel@tonic-gate 	long ret = 0;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
9827c478bd9Sstevel@tonic-gate 		if (strlen(fptr->ar_longname) >= (unsigned)SNAME-1) {
9837c478bd9Sstevel@tonic-gate 			(*longnames)++;
9847c478bd9Sstevel@tonic-gate 			savelongname(fptr, ptr_index);
9857c478bd9Sstevel@tonic-gate 			(void) strcpy(fptr->ar_name, ptr_index);
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 	if (*longnames) {
9897c478bd9Sstevel@tonic-gate 		/* round up table that keeps the long filenames */
9907c478bd9Sstevel@tonic-gate 		while ((str_top1 - str_base1) & 03)
9917c478bd9Sstevel@tonic-gate 			*str_top1++ = '\n';
9927c478bd9Sstevel@tonic-gate 		ret = sizeof (char) * (str_top1 - str_base1);
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 	return (ret);
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate /* Put bytes in archive header in machine independent order.  */
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate static void
10007c478bd9Sstevel@tonic-gate sputl(long n, char *cp)
10017c478bd9Sstevel@tonic-gate {
10027c478bd9Sstevel@tonic-gate 	*cp++ = n >> 24;
10037c478bd9Sstevel@tonic-gate 	*cp++ = n >> 16;
10047c478bd9Sstevel@tonic-gate 	*cp++ = n >> 8;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	*cp++ = n & 255;
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate static int
10107c478bd9Sstevel@tonic-gate search_sym_tab(ARFILE *fptr, Elf *elf, Elf_Scn *scn,
10117c478bd9Sstevel@tonic-gate 	long *nsyms, ARFILEP **symlist, int *num_errs)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate 	Elf_Data *str_data, *sym_data; /* string table, symbol table */
10147c478bd9Sstevel@tonic-gate 	Elf_Scn *str_scn;
10157c478bd9Sstevel@tonic-gate 	GElf_Sxword no_of_symbols;
10167c478bd9Sstevel@tonic-gate 	GElf_Shdr shdr;
10177c478bd9Sstevel@tonic-gate 	int counter;
10187c478bd9Sstevel@tonic-gate 	int str_shtype;
10197c478bd9Sstevel@tonic-gate 	char *symname;
10207c478bd9Sstevel@tonic-gate 	static ARFILEP *sym_ptr = 0;
10217c478bd9Sstevel@tonic-gate 	static ARFILEP *nextsym = NULL;
10227c478bd9Sstevel@tonic-gate 	static int syms_left = 0;
10237c478bd9Sstevel@tonic-gate 	char *fname = fptr->ar_pathname;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	(void) gelf_getshdr(scn, &shdr);
10267c478bd9Sstevel@tonic-gate 	str_scn = elf_getscn(elf, shdr.sh_link); /* index for string table */
10277c478bd9Sstevel@tonic-gate 	if (str_scn == NULL) {
10287c478bd9Sstevel@tonic-gate 		if (fname != NULL)
10297c478bd9Sstevel@tonic-gate 			error_message(ELF_GETDATA_01_ERROR,
1030*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1),
1031*d2d5cf7cSAli Bahrami 			    fname);
10327c478bd9Sstevel@tonic-gate 		else
10337c478bd9Sstevel@tonic-gate 			error_message(ELF_GETDATA_02_ERROR,
1034*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1));
10357c478bd9Sstevel@tonic-gate 		(*num_errs)++;
10367c478bd9Sstevel@tonic-gate 		return (-1);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	no_of_symbols = shdr.sh_size / shdr.sh_entsize;
10407c478bd9Sstevel@tonic-gate 	if (no_of_symbols == -1) {
10417c478bd9Sstevel@tonic-gate 		error_message(SYMTAB_01_ERROR,
1042*d2d5cf7cSAli Bahrami 		    PLAIN_ERROR, (char *)0);
10437c478bd9Sstevel@tonic-gate 		return (-1);
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	(void) gelf_getshdr(str_scn, &shdr);
10477c478bd9Sstevel@tonic-gate 	str_shtype = shdr.sh_type;
10487c478bd9Sstevel@tonic-gate 	if (str_shtype == -1) {
10497c478bd9Sstevel@tonic-gate 		if (fname != NULL)
10507c478bd9Sstevel@tonic-gate 			error_message(ELF_GETDATA_01_ERROR,
1051*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1), fname);
10527c478bd9Sstevel@tonic-gate 		else
10537c478bd9Sstevel@tonic-gate 			error_message(ELF_GETDATA_02_ERROR,
1054*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1));
10557c478bd9Sstevel@tonic-gate 		(*num_errs)++;
10567c478bd9Sstevel@tonic-gate 		return (-1);
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/* This test must happen before testing the string table. */
10607c478bd9Sstevel@tonic-gate 	if (no_of_symbols == 1)
10617c478bd9Sstevel@tonic-gate 		return (0);	/* no symbols; 0th symbol is the non-symbol */
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	if (str_shtype != SHT_STRTAB) {
10647c478bd9Sstevel@tonic-gate 		if (fname != NULL)
10657c478bd9Sstevel@tonic-gate 			error_message(SYMTAB_02_ERROR,
1066*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0,
1067*d2d5cf7cSAli Bahrami 			    fname);
10687c478bd9Sstevel@tonic-gate 		else
10697c478bd9Sstevel@tonic-gate 			error_message(SYMTAB_03_ERROR,
1070*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
10717c478bd9Sstevel@tonic-gate 		return (0);
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 	str_data = 0;
10747c478bd9Sstevel@tonic-gate 	if ((str_data = elf_getdata(str_scn, str_data)) == 0) {
10757c478bd9Sstevel@tonic-gate 		if (fname != NULL)
10767c478bd9Sstevel@tonic-gate 			error_message(SYMTAB_04_ERROR,
1077*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0,
1078*d2d5cf7cSAli Bahrami 			    fname);
10797c478bd9Sstevel@tonic-gate 		else
10807c478bd9Sstevel@tonic-gate 			error_message(SYMTAB_05_ERROR,
1081*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
10827c478bd9Sstevel@tonic-gate 		return (0);
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 	if (str_data->d_size == 0) {
10857c478bd9Sstevel@tonic-gate 		if (fname != NULL)
10867c478bd9Sstevel@tonic-gate 			error_message(SYMTAB_06_ERROR,
1087*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0,
1088*d2d5cf7cSAli Bahrami 			    fname);
10897c478bd9Sstevel@tonic-gate 		else
10907c478bd9Sstevel@tonic-gate 			error_message(SYMTAB_07_ERROR,
1091*d2d5cf7cSAli Bahrami 			    PLAIN_ERROR, (char *)0);
10927c478bd9Sstevel@tonic-gate 		return (0);
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 	sym_data = 0;
10957c478bd9Sstevel@tonic-gate 	if ((sym_data = elf_getdata(scn, sym_data)) == NULL) {
10967c478bd9Sstevel@tonic-gate 		if (fname != NULL)
10977c478bd9Sstevel@tonic-gate 			error_message(ELF_01_ERROR,
1098*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1),
1099*d2d5cf7cSAli Bahrami 			    fname, elf_errmsg(-1));
11007c478bd9Sstevel@tonic-gate 		else
11017c478bd9Sstevel@tonic-gate 			error_message(ELF_02_ERROR,
1102*d2d5cf7cSAli Bahrami 			    LIBELF_ERROR, elf_errmsg(-1),
1103*d2d5cf7cSAli Bahrami 			    elf_errmsg(-1));
11047c478bd9Sstevel@tonic-gate 		return (0);
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/* start at 1, first symbol entry is ignored */
11087c478bd9Sstevel@tonic-gate 	for (counter = 1; counter < no_of_symbols; counter++) {
11097c478bd9Sstevel@tonic-gate 		GElf_Sym sym;
11107c478bd9Sstevel@tonic-gate 		(void) gelf_getsym(sym_data, counter, &sym);
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 		symname = (char *)(str_data->d_buf) + sym.st_name;
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 		if (((GELF_ST_BIND(sym.st_info) == STB_GLOBAL) ||
1115*d2d5cf7cSAli Bahrami 		    (GELF_ST_BIND(sym.st_info) == STB_WEAK)) &&
1116*d2d5cf7cSAli Bahrami 		    (sym.st_shndx != SHN_UNDEF)) {
11177c478bd9Sstevel@tonic-gate 			if (!syms_left) {
11187c478bd9Sstevel@tonic-gate 				sym_ptr = malloc((SYMCHUNK+1)
1119*d2d5cf7cSAli Bahrami 				    * sizeof (ARFILEP));
11207c478bd9Sstevel@tonic-gate 				if (sym_ptr == NULL) {
11217c478bd9Sstevel@tonic-gate 					error_message(MALLOC_ERROR,
1122*d2d5cf7cSAli Bahrami 					    PLAIN_ERROR, (char *)0);
11237c478bd9Sstevel@tonic-gate 					exit(1);
11247c478bd9Sstevel@tonic-gate 				}
11257c478bd9Sstevel@tonic-gate 				syms_left = SYMCHUNK;
11267c478bd9Sstevel@tonic-gate 				if (nextsym)
11277c478bd9Sstevel@tonic-gate 					*nextsym = (ARFILEP)sym_ptr;
11287c478bd9Sstevel@tonic-gate 				else
11297c478bd9Sstevel@tonic-gate 					*symlist = sym_ptr;
11307c478bd9Sstevel@tonic-gate 				nextsym = sym_ptr;
11317c478bd9Sstevel@tonic-gate 			}
11327c478bd9Sstevel@tonic-gate 			sym_ptr = nextsym;
11337c478bd9Sstevel@tonic-gate 			nextsym++;
11347c478bd9Sstevel@tonic-gate 			syms_left--;
11357c478bd9Sstevel@tonic-gate 			(*nsyms)++;
11367c478bd9Sstevel@tonic-gate 			*sym_ptr = fptr;
11377c478bd9Sstevel@tonic-gate 			savename(symname);	/* put name in the archiver's */
11387c478bd9Sstevel@tonic-gate 						/* symbol table string table */
11397c478bd9Sstevel@tonic-gate 		}
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 	return (0);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate  * Get the output file size
11467c478bd9Sstevel@tonic-gate  */
11477c478bd9Sstevel@tonic-gate static int
11487c478bd9Sstevel@tonic-gate sizeofmembers(int psum)
11497c478bd9Sstevel@tonic-gate {
11507c478bd9Sstevel@tonic-gate 	int sum = 0;
11517c478bd9Sstevel@tonic-gate 	ARFILE *fptr;
11527c478bd9Sstevel@tonic-gate 	int hdrsize = sizeof (struct ar_hdr);
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
11557c478bd9Sstevel@tonic-gate 		fptr->ar_offset = psum + sum;
11567c478bd9Sstevel@tonic-gate 		sum += fptr->ar_size;
11577c478bd9Sstevel@tonic-gate 		if (fptr->ar_size & 01)
11587c478bd9Sstevel@tonic-gate 			sum++;
11597c478bd9Sstevel@tonic-gate 		sum += hdrsize;
11607c478bd9Sstevel@tonic-gate 
116160fc76daSab 		/*
116260fc76daSab 		 * If the current item, and the next item are both ELF
116360fc76daSab 		 * objects, then add padding to current item so that the
116460fc76daSab 		 * next item will have PADSZ alignment.
116560fc76daSab 		 *
116660fc76daSab 		 * In any other case, set the padding to 0. If the
116760fc76daSab 		 * item comes from another archive, it may be carrying
116860fc76daSab 		 * a non-zero padding value from that archive that does
116960fc76daSab 		 * not apply to the one we are about to build.
117060fc76daSab 		 */
11717c478bd9Sstevel@tonic-gate 		if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) &&
11729d6538abSab 		    fptr->ar_next &&
11739d6538abSab 		    (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) {
11749d6538abSab 			fptr->ar_padding = pad(psum + sum + hdrsize);
11759d6538abSab 			sum += fptr->ar_padding;
117660fc76daSab 		} else {
117760fc76daSab 			fptr->ar_padding = 0;
11787c478bd9Sstevel@tonic-gate 		}
11797c478bd9Sstevel@tonic-gate 	}
11807c478bd9Sstevel@tonic-gate 	return (sum);
11817c478bd9Sstevel@tonic-gate }
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate static int
11849d6538abSab sizeofnewarchiveheader(int nsyms, int longnames)
11857c478bd9Sstevel@tonic-gate {
11867c478bd9Sstevel@tonic-gate 	int sum = 0;
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	sum += SARMAG;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if (nsyms) {
11917c478bd9Sstevel@tonic-gate 		char *top = (char *)str_top;
11927c478bd9Sstevel@tonic-gate 		char *base = (char *)str_base;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 		while ((top - base) & 03)
11957c478bd9Sstevel@tonic-gate 			top++;
11967c478bd9Sstevel@tonic-gate 		sum += sizeof (struct ar_hdr);
11977c478bd9Sstevel@tonic-gate 		sum += (nsyms + 1) * 4;
11987c478bd9Sstevel@tonic-gate 		sum += top - base;
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	if (longnames) {
12027c478bd9Sstevel@tonic-gate 		sum += sizeof (struct ar_hdr);
12037c478bd9Sstevel@tonic-gate 		sum += str_top1 - str_base1;
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	/*
12079d6538abSab 	 * If the first member file is an ELF object,
12087c478bd9Sstevel@tonic-gate 	 * we have to ensure the member contents will align
12099d6538abSab 	 * on PADSZ byte boundary.
12107c478bd9Sstevel@tonic-gate 	 */
12119d6538abSab 	if (listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64))) {
12129d6538abSab 		pad_symtab = pad(sum + sizeof (struct ar_hdr));
12139d6538abSab 		sum += pad_symtab;
12147c478bd9Sstevel@tonic-gate 	}
12159d6538abSab 
12169d6538abSab 	return (sum);
12179d6538abSab }
12189d6538abSab 
12199d6538abSab static int
12209d6538abSab sizeofnewarchive(int nsyms, int longnames)
12219d6538abSab {
12229d6538abSab 	int sum;
12239d6538abSab 
12249d6538abSab 	sum = sizeofnewarchiveheader(nsyms, longnames);
12257c478bd9Sstevel@tonic-gate 	sum += sizeofmembers(sum);
12267c478bd9Sstevel@tonic-gate 	return (sum);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate static void
12307c478bd9Sstevel@tonic-gate arwrite(char *name, int nfd, char *dst, int size) {
12317c478bd9Sstevel@tonic-gate 	if (write(nfd, dst, size) != size) {
12327c478bd9Sstevel@tonic-gate 		error_message(SYS_WRITE_04_ERROR,
1233*d2d5cf7cSAli Bahrami 		    SYSTEM_ERROR, strerror(errno), name);
12347c478bd9Sstevel@tonic-gate 		exit(2);
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate }
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate static char *
12397c478bd9Sstevel@tonic-gate make_tmpname(char *filename) {
12407c478bd9Sstevel@tonic-gate 	static char template[] = "arXXXXXX";
12417c478bd9Sstevel@tonic-gate 	char *tmpname;
12427c478bd9Sstevel@tonic-gate 	char *slash = strrchr(filename, '/');
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (slash != (char *)NULL) {
12457c478bd9Sstevel@tonic-gate 		char c;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 		c = *slash;
12487c478bd9Sstevel@tonic-gate 		*slash = 0;
12497c478bd9Sstevel@tonic-gate 		tmpname = (char *)malloc(strlen(filename) +
12507c478bd9Sstevel@tonic-gate 			sizeof (template) + 2);
1251d6555420Smike_s 		(void) strcpy(tmpname, filename);
1252d6555420Smike_s 		(void) strcat(tmpname, "/");
1253d6555420Smike_s 		(void) strcat(tmpname, template);
1254d6555420Smike_s 		(void) mktemp(tmpname);
12557c478bd9Sstevel@tonic-gate 		*slash = c;
12567c478bd9Sstevel@tonic-gate 	} else {
12577c478bd9Sstevel@tonic-gate 		tmpname = malloc(sizeof (template));
1258d6555420Smike_s 		(void) strcpy(tmpname, template);
1259d6555420Smike_s 		(void) mktemp(tmpname);
12607c478bd9Sstevel@tonic-gate 	}
12617c478bd9Sstevel@tonic-gate 	return (tmpname);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate static int
12657c478bd9Sstevel@tonic-gate ar_copy(char *from, char *to) {
12667c478bd9Sstevel@tonic-gate 	int fromfd, tofd, nread;
12677c478bd9Sstevel@tonic-gate 	int saved;
12687c478bd9Sstevel@tonic-gate 	char buf[8192];
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	fromfd = open(from, O_RDONLY);
12717c478bd9Sstevel@tonic-gate 	if (fromfd < 0)
12727c478bd9Sstevel@tonic-gate 		return (-1);
12737c478bd9Sstevel@tonic-gate 	tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, 0777);
12747c478bd9Sstevel@tonic-gate 	if (tofd < 0) {
12757c478bd9Sstevel@tonic-gate 		saved = errno;
1276d6555420Smike_s 		(void) close(fromfd);
12777c478bd9Sstevel@tonic-gate 		errno = saved;
12787c478bd9Sstevel@tonic-gate 		return (-1);
12797c478bd9Sstevel@tonic-gate 	}
12807c478bd9Sstevel@tonic-gate 	while ((nread = read(fromfd, buf, sizeof (buf))) > 0) {
12817c478bd9Sstevel@tonic-gate 		if (write(tofd, buf, nread) != nread) {
12827c478bd9Sstevel@tonic-gate 			saved = errno;
1283d6555420Smike_s 			(void) close(fromfd);
1284d6555420Smike_s 			(void) close(tofd);
12857c478bd9Sstevel@tonic-gate 			errno = saved;
12867c478bd9Sstevel@tonic-gate 			return (-1);
12877c478bd9Sstevel@tonic-gate 		}
12887c478bd9Sstevel@tonic-gate 	}
12897c478bd9Sstevel@tonic-gate 	saved = errno;
1290d6555420Smike_s 	(void) close(fromfd);
1291d6555420Smike_s 	(void) close(tofd);
12927c478bd9Sstevel@tonic-gate 	if (nread < 0) {
12937c478bd9Sstevel@tonic-gate 		errno = saved;
12947c478bd9Sstevel@tonic-gate 		return (-1);
12957c478bd9Sstevel@tonic-gate 	}
12967c478bd9Sstevel@tonic-gate 	return (0);
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate static int
1300d6555420Smike_s ar_rename(char *from, char *to)
1301d6555420Smike_s {
13027c478bd9Sstevel@tonic-gate 	int exists;
13037c478bd9Sstevel@tonic-gate 	struct stat s;
13047c478bd9Sstevel@tonic-gate 	int ret = 0;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	exists = lstat(to, &s) == 0;
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	if (! exists || (!S_ISLNK(s.st_mode) && s.st_nlink == 1)) {
13097c478bd9Sstevel@tonic-gate 		ret = rename(from, to);
13107c478bd9Sstevel@tonic-gate 		if (ret == 0) {
13117c478bd9Sstevel@tonic-gate 			if (exists) {
1312d6555420Smike_s 				(void) chmod(to, s.st_mode & 0777);
13137c478bd9Sstevel@tonic-gate 				if (chown(to, s.st_uid, s.st_gid) >= 0)
1314d6555420Smike_s 					(void) chmod(to, s.st_mode & 07777);
13157c478bd9Sstevel@tonic-gate 				}
13167c478bd9Sstevel@tonic-gate 		} else {
1317d6555420Smike_s 			(void) unlink(from);
13187c478bd9Sstevel@tonic-gate 		}
13197c478bd9Sstevel@tonic-gate 	} else {
13207c478bd9Sstevel@tonic-gate 		ret = ar_copy(from, to);
1321d6555420Smike_s 		(void) unlink(from);
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 	return (ret);
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate static char *
13277c478bd9Sstevel@tonic-gate writelargefile(Cmd_info *cmd_info, long long_tab_size, int longnames,
13287c478bd9Sstevel@tonic-gate 	ARFILEP *symlist, long nsyms, int found_obj, int new_archive)
13297c478bd9Sstevel@tonic-gate {
1330d6555420Smike_s 	ARFILE	* fptr;
13317c478bd9Sstevel@tonic-gate 	char *name = cmd_info->arnam;
13327c478bd9Sstevel@tonic-gate 	int arsize;
13337c478bd9Sstevel@tonic-gate 	char *dst;
13347c478bd9Sstevel@tonic-gate 	char *tmp_dst;
13357c478bd9Sstevel@tonic-gate 	int nfd;
13367c478bd9Sstevel@tonic-gate 	char  *new_name;
13377c478bd9Sstevel@tonic-gate 	FILE *f;
13387c478bd9Sstevel@tonic-gate 	struct stat stbuf;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	new_name = make_tmpname(name);
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	if (new_archive) {
13437c478bd9Sstevel@tonic-gate 		nfd = open(name, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
13447c478bd9Sstevel@tonic-gate 		if (nfd == -1) {
13457c478bd9Sstevel@tonic-gate 			error_message(SYS_CREATE_01_ERROR,
1346*d2d5cf7cSAli Bahrami 			    SYSTEM_ERROR, strerror(errno), name);
13477c478bd9Sstevel@tonic-gate 			exit(1);
13487c478bd9Sstevel@tonic-gate 		}
13497c478bd9Sstevel@tonic-gate 	} else {
13507c478bd9Sstevel@tonic-gate 		nfd = open(new_name, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
13517c478bd9Sstevel@tonic-gate 		if (nfd == -1) {
13527c478bd9Sstevel@tonic-gate 			error_message(SYS_WRITE_02_ERROR,
1353*d2d5cf7cSAli Bahrami 			    SYSTEM_ERROR, strerror(errno), name);
13547c478bd9Sstevel@tonic-gate 			exit(1);
13557c478bd9Sstevel@tonic-gate 		}
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	arsize = sizeofnewarchiveheader(nsyms, longnames);
13597c478bd9Sstevel@tonic-gate 	if (nsyms == 0 && found_obj != 0)
13607c478bd9Sstevel@tonic-gate 		arsize += sizeof (struct ar_hdr) + 4 + 4;
13617c478bd9Sstevel@tonic-gate 	if (arsize < 2048) {
13627c478bd9Sstevel@tonic-gate 		arsize = 2048;
13637c478bd9Sstevel@tonic-gate 	}
13647c478bd9Sstevel@tonic-gate 	dst = tmp_dst = (char *)malloc(arsize);
13657c478bd9Sstevel@tonic-gate 	(void) memcpy(tmp_dst, ARMAG, SARMAG);
13667c478bd9Sstevel@tonic-gate 	tmp_dst += SARMAG;
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 	if (nsyms || found_obj != 0) {
13697c478bd9Sstevel@tonic-gate 		int diff;
13707c478bd9Sstevel@tonic-gate 		diff = writesymtab(tmp_dst, nsyms, symlist);
13717c478bd9Sstevel@tonic-gate 		tmp_dst += diff;
13727c478bd9Sstevel@tonic-gate 	}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	if (longnames) {
13757c478bd9Sstevel@tonic-gate 		(void) sprintf(tmp_dst, FORMAT, LONGDIRNAME, time(0),
1376*d2d5cf7cSAli Bahrami 		    (unsigned)0, (unsigned)0, (unsigned)0,
1377*d2d5cf7cSAli Bahrami 		    (long)long_tab_size, ARFMAG);
13787c478bd9Sstevel@tonic-gate 		tmp_dst += sizeof (struct ar_hdr);
13797c478bd9Sstevel@tonic-gate 		(void) memcpy(tmp_dst, str_base1, str_top1 - str_base1);
13807c478bd9Sstevel@tonic-gate 		tmp_dst += str_top1 - str_base1;
13817c478bd9Sstevel@tonic-gate 	}
13827c478bd9Sstevel@tonic-gate #ifndef XPG4
13837c478bd9Sstevel@tonic-gate 	if (opt_FLAG(cmd_info, v_FLAG)) {
1384*d2d5cf7cSAli Bahrami 		error_message(BER_MES_WRITE_ERROR,
1385*d2d5cf7cSAli Bahrami 		    PLAIN_ERROR, (char *)0,
1386*d2d5cf7cSAli Bahrami 		    cmd_info->arnam);
13877c478bd9Sstevel@tonic-gate 	}
13887c478bd9Sstevel@tonic-gate #endif
13897c478bd9Sstevel@tonic-gate 	arwrite(name, nfd, dst, (int)(tmp_dst - dst));
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
13927c478bd9Sstevel@tonic-gate 		if (fptr->ar_name[0] == 0) {
13937c478bd9Sstevel@tonic-gate 			fptr->ar_longname = fptr->ar_rawname;
13947c478bd9Sstevel@tonic-gate 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
13957c478bd9Sstevel@tonic-gate 		}
13967c478bd9Sstevel@tonic-gate 		if (strlen(fptr->ar_longname) <= (unsigned)SNAME-2)
13977c478bd9Sstevel@tonic-gate 			(void) sprintf(dst, FNFORMAT,
1398*d2d5cf7cSAli Bahrami 			    trimslash(fptr->ar_longname));
13997c478bd9Sstevel@tonic-gate 		else
14007c478bd9Sstevel@tonic-gate 			(void) sprintf(dst, FNFORMAT, fptr->ar_name);
14017c478bd9Sstevel@tonic-gate 		(void) sprintf(dst+16, TLFORMAT, fptr->ar_date,
14027c478bd9Sstevel@tonic-gate 		    (unsigned)fptr->ar_uid, (unsigned)fptr->ar_gid,
14037c478bd9Sstevel@tonic-gate 		    (unsigned)fptr->ar_mode, fptr->ar_size + fptr->ar_padding,
14047c478bd9Sstevel@tonic-gate 		    ARFMAG);
14057c478bd9Sstevel@tonic-gate 		arwrite(name, nfd, dst, sizeof (struct ar_hdr));
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 		if (!(fptr->ar_flag & F_MALLOCED) &&
14087c478bd9Sstevel@tonic-gate 		    !(fptr->ar_flag & F_MMAPED) &&
14097c478bd9Sstevel@tonic-gate 		    !(fptr->ar_flag & F_ELFRAW)) {
14107c478bd9Sstevel@tonic-gate 			f = fopen(fptr->ar_pathname, "r");
14117c478bd9Sstevel@tonic-gate 			if (stat(fptr->ar_pathname, &stbuf) < 0) {
14127c478bd9Sstevel@tonic-gate 				(void) fclose(f);
14137c478bd9Sstevel@tonic-gate 				f = NULL;
14147c478bd9Sstevel@tonic-gate 			}
14157c478bd9Sstevel@tonic-gate 			if (f == NULL) {
14167c478bd9Sstevel@tonic-gate 				error_message(SYS_OPEN_ERROR,
1417*d2d5cf7cSAli Bahrami 				    SYSTEM_ERROR, strerror(errno),
1418*d2d5cf7cSAli Bahrami 				    fptr->ar_longname);
14197c478bd9Sstevel@tonic-gate 				exit(1);
14207c478bd9Sstevel@tonic-gate 			} else {
14217c478bd9Sstevel@tonic-gate 				if ((fptr->ar_contents = (char *)
14227c478bd9Sstevel@tonic-gate 				    malloc(ROUNDUP(stbuf.st_size))) == NULL) {
14237c478bd9Sstevel@tonic-gate 					error_message(MALLOC_ERROR,
1424*d2d5cf7cSAli Bahrami 					    PLAIN_ERROR, (char *)0);
14257c478bd9Sstevel@tonic-gate 					exit(1);
14267c478bd9Sstevel@tonic-gate 				}
14277c478bd9Sstevel@tonic-gate 				if (fread(fptr->ar_contents,
14287c478bd9Sstevel@tonic-gate 				    sizeof (char),
14297c478bd9Sstevel@tonic-gate 				    stbuf.st_size, f) != stbuf.st_size) {
14307c478bd9Sstevel@tonic-gate 					error_message(SYS_READ_ERROR,
1431*d2d5cf7cSAli Bahrami 					    SYSTEM_ERROR, strerror(errno),
1432*d2d5cf7cSAli Bahrami 					    fptr->ar_longname);
14337c478bd9Sstevel@tonic-gate 					exit(1);
14347c478bd9Sstevel@tonic-gate 				}
14357c478bd9Sstevel@tonic-gate 			}
14367c478bd9Sstevel@tonic-gate 			arwrite(name, nfd, fptr->ar_contents, fptr->ar_size);
1437d6555420Smike_s 			(void) fclose(f);
14387c478bd9Sstevel@tonic-gate 			free(fptr->ar_contents);
14397c478bd9Sstevel@tonic-gate 		} else {
14407c478bd9Sstevel@tonic-gate 			arwrite(name, nfd, fptr->ar_contents, fptr->ar_size);
14417c478bd9Sstevel@tonic-gate 			if (fptr->ar_flag & F_MALLOCED) {
14427c478bd9Sstevel@tonic-gate 				(void) free(fptr->ar_contents);
14437c478bd9Sstevel@tonic-gate 				fptr->ar_flag &= ~(F_MALLOCED);
14447c478bd9Sstevel@tonic-gate 			}
14457c478bd9Sstevel@tonic-gate 		}
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 		if (fptr->ar_size & 0x1) {
14487c478bd9Sstevel@tonic-gate 			arwrite(name, nfd, "\n", 1);
14497c478bd9Sstevel@tonic-gate 		}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 		if (fptr->ar_padding) {
14527c478bd9Sstevel@tonic-gate 			int i = fptr->ar_padding;
14537c478bd9Sstevel@tonic-gate 			while (i) {
14547c478bd9Sstevel@tonic-gate 				arwrite(name, nfd, "\n", 1);
14557c478bd9Sstevel@tonic-gate 				--i;
14567c478bd9Sstevel@tonic-gate 			}
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	/*
14617c478bd9Sstevel@tonic-gate 	 * All preparation for writing is done.
14627c478bd9Sstevel@tonic-gate 	 */
14637c478bd9Sstevel@tonic-gate 	(void) elf_end(cmd_info->arf);
14647c478bd9Sstevel@tonic-gate 	(void) close(cmd_info->afd);
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	if (!new_archive) {
1467d6555420Smike_s 		(void) ar_rename(new_name, name);
14687c478bd9Sstevel@tonic-gate 	}
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	return (dst);
14717c478bd9Sstevel@tonic-gate }
1472