xref: /illumos-gate/usr/src/cmd/sgs/ar/common/file.c (revision 11029d9d)
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  */
21ba7866cdSAli Bahrami 
227c478bd9Sstevel@tonic-gate /*
23ba7866cdSAli Bahrami  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
24*11029d9dSRobert Mustacchi  * Copyright 2022 Oxide Computer Company
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
297c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
33ba7866cdSAli Bahrami #include <sys/sendfile.h>
347c478bd9Sstevel@tonic-gate #include "inc.h"
35ba7866cdSAli Bahrami #include "gelf.h"
36ba7866cdSAli Bahrami 
37ba7866cdSAli Bahrami /*
38ba7866cdSAli Bahrami  * List of archive members, accessed globally by cmd and file.
39ba7866cdSAli Bahrami  */
40ba7866cdSAli Bahrami ARFILE	*listhead, *listend;
41ba7866cdSAli Bahrami 
42ba7866cdSAli Bahrami /*
43ba7866cdSAli Bahrami  * Type used to manage string tables. Archives can have two of these:
44ba7866cdSAli Bahrami  *
45ba7866cdSAli Bahrami  * sym_strtbl: String table included at the end of the symbol table
46ba7866cdSAli Bahrami  *	archive member, following the offset array.
47ba7866cdSAli Bahrami  *
48ba7866cdSAli Bahrami  * long_strtbl: String table used to hold member names that exceed 15
49ba7866cdSAli Bahrami  *	characters in length, found in the long names archive member.
50ba7866cdSAli Bahrami  */
51ba7866cdSAli Bahrami typedef struct {
52ba7866cdSAli Bahrami 	char	*base;		/* Base of string table memory */
53ba7866cdSAli Bahrami 	size_t	used;		/* # bytes used from allocation */
54ba7866cdSAli Bahrami 	size_t	size;		/* Size of allocation */
55ba7866cdSAli Bahrami } ARSTRTBL;
567c478bd9Sstevel@tonic-gate 
57ba7866cdSAli Bahrami static ARSTRTBL	sym_strtbl;
58ba7866cdSAli Bahrami static ARSTRTBL	long_strtbl;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 
61ba7866cdSAli Bahrami /*
62ba7866cdSAli Bahrami  * Name and file descriptor used when creating a new archive.
63ba7866cdSAli Bahrami  * If this variable references an open file when exit_cleanup()
64ba7866cdSAli Bahrami  * executes, it will close and remove the file, preventing incomplete
65ba7866cdSAli Bahrami  * temporary files from being left behind in the case of a failure
66ba7866cdSAli Bahrami  * or interruption.
67ba7866cdSAli Bahrami  */
68ba7866cdSAli Bahrami static struct {
69ba7866cdSAli Bahrami 	int		fd;	/* -1, or open file descriptor */
70ba7866cdSAli Bahrami 	const char	*path;	/* Path to open file */
71ba7866cdSAli Bahrami } ar_outfile;
72ba7866cdSAli Bahrami 
739d6538abSab /*
749d6538abSab  * The ar file format requires objects to be padded to an even size.
759d6538abSab  * We do that, but it turns out to be beneficial to go farther.
769d6538abSab  *
779d6538abSab  * ld(1) accesses archives by mmapping them into memory. If the mapped
78ba7866cdSAli Bahrami  * objects (member data) have the proper alignment, we can access them
79ba7866cdSAli Bahrami  * directly. If the data alignment is wrong, libelf "slides" them over the
80ba7866cdSAli Bahrami  * archive header to correct the misalignment. This is expensive in time
81ba7866cdSAli Bahrami  * (to copy memory) and space (it causes swap to be allocated by the system
82ba7866cdSAli Bahrami  * to back the now-modified pages). Hence, we really want to ensure that
83ba7866cdSAli Bahrami  * the alignment is right.
849d6538abSab  *
859d6538abSab  * We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects
869d6538abSab  * at 8-byte. More recently, an elf section type has appeared that has
879d6538abSab  * 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So,
889d6538abSab  * the current strategy is to align all objects to 8-bytes.
899d6538abSab  *
909d6538abSab  * There are two important things to consider when setting this value:
919d6538abSab  *	1) If a new elf section that ld(1) accesses in memory appears
929d6538abSab  *	   with a greater than 8-byte alignment requirement, this value
939d6538abSab  *	   will need to be raised. Or, alternatively, the entire approach may
949d6538abSab  *	   need reconsideration.
959d6538abSab  *	2) The size of this padding must be smaller than the size of the
969d6538abSab  *	   smallest possible ELF section. Otherwise, the logic contained
979d6538abSab  *	   in recover_padding() can be tricked.
989d6538abSab  */
999d6538abSab #define	PADSZ 8
1009d6538abSab 
1017c478bd9Sstevel@tonic-gate /*
102ba7866cdSAli Bahrami  * Forward Declarations
1037c478bd9Sstevel@tonic-gate  */
104ba7866cdSAli Bahrami static void		arwrite(const char *, int, const char *, size_t);
105ba7866cdSAli Bahrami static size_t		mklong_tab();
106ba7866cdSAli Bahrami static size_t		mksymtab(const char *, ARFILEP **, int *);
107ba7866cdSAli Bahrami static const char	*make_tmpname(const char *);
108ba7866cdSAli Bahrami static size_t		sizeof_symtbl(size_t, int, size_t);
109ba7866cdSAli Bahrami static void		savelongname(ARFILE *);
110ba7866cdSAli Bahrami static void		savename(char *);
111ba7866cdSAli Bahrami static int		search_sym_tab(const char *, ARFILE *, Elf *,
112ba7866cdSAli Bahrami 			    Elf_Scn *, size_t *, ARFILEP **, size_t *);
113ba7866cdSAli Bahrami static size_t		sizeofmembers(size_t);
114ba7866cdSAli Bahrami static char		*sputl32(uint32_t, char *);
115ba7866cdSAli Bahrami static char		*sputl64(uint64_t, char *);
116ba7866cdSAli Bahrami static void		strtbl_pad(ARSTRTBL *, size_t, int);
117ba7866cdSAli Bahrami static char		*trimslash(char *s);
118ba7866cdSAli Bahrami static void		writesymtab(const char *, int fd, size_t, ARFILEP *,
119ba7866cdSAli Bahrami 			    size_t);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 
122ba7866cdSAli Bahrami /*
123ba7866cdSAli Bahrami  * Function to be called on exit to clean up incomplete new archive.
124ba7866cdSAli Bahrami  */
125ba7866cdSAli Bahrami static void
exit_cleanup(void)126ba7866cdSAli Bahrami exit_cleanup(void)
127ba7866cdSAli Bahrami {
128ba7866cdSAli Bahrami 	if (ar_outfile.fd != -1) {
129ba7866cdSAli Bahrami 		/* Both of these system calls are Async-Signal-Safe */
130ba7866cdSAli Bahrami 		(void)  close(ar_outfile.fd);
131ba7866cdSAli Bahrami 		(void) unlink(ar_outfile.path);
132ba7866cdSAli Bahrami 	}
133ba7866cdSAli Bahrami }
1347c478bd9Sstevel@tonic-gate 
135ba7866cdSAli Bahrami /*
136ba7866cdSAli Bahrami  * Open an existing archive.
137ba7866cdSAli Bahrami  */
1387c478bd9Sstevel@tonic-gate int
getaf(Cmd_info * cmd_info)1397c478bd9Sstevel@tonic-gate getaf(Cmd_info *cmd_info)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	Elf_Cmd cmd;
1427c478bd9Sstevel@tonic-gate 	int fd;
1437c478bd9Sstevel@tonic-gate 	char *arnam = cmd_info->arnam;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
146ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_VERSION),
147ba7866cdSAli Bahrami 		    elf_errmsg(-1));
1487c478bd9Sstevel@tonic-gate 		exit(1);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if ((cmd_info->afd = fd = open(arnam, O_RDONLY)) == -1) {
152ba7866cdSAli Bahrami 		int err = errno;
153ba7866cdSAli Bahrami 
154ba7866cdSAli Bahrami 		if (err == ENOENT) {
1557c478bd9Sstevel@tonic-gate 			/* archive does not exist yet, may have to create one */
1567c478bd9Sstevel@tonic-gate 			return (fd);
1577c478bd9Sstevel@tonic-gate 		} else {
1587c478bd9Sstevel@tonic-gate 			/* problem other than "does not exist" */
159ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
160ba7866cdSAli Bahrami 			    arnam, strerror(err));
1617c478bd9Sstevel@tonic-gate 			exit(1);
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	cmd = ELF_C_READ;
1667c478bd9Sstevel@tonic-gate 	cmd_info->arf = elf_begin(fd, cmd, (Elf *)0);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	if (elf_kind(cmd_info->arf) != ELF_K_AR) {
169ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_NOT_ARCHIVE), arnam);
170ba7866cdSAli Bahrami 		if (cmd_info->opt_flgs & (a_FLAG | b_FLAG))
171fb25420bSRobert Mustacchi 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_POSNAME),
172ba7866cdSAli Bahrami 			    cmd_info->ponam);
1737c478bd9Sstevel@tonic-gate 		exit(1);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 	return (fd);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
17830a4e2aaSab /*
179ba7866cdSAli Bahrami  * Given a value, and a pad alignment, return the number of bytes
180ba7866cdSAli Bahrami  * required to pad the value to the next alignment boundary.
1819d6538abSab  */
182ba7866cdSAli Bahrami static size_t
pad(size_t n,size_t align)183ba7866cdSAli Bahrami pad(size_t n, size_t align)
1849d6538abSab {
185ba7866cdSAli Bahrami 	size_t r;
1869d6538abSab 
187ba7866cdSAli Bahrami 	r = n % align;
1889d6538abSab 	if (r)
189ba7866cdSAli Bahrami 		r = align - r;
1909d6538abSab 
1919d6538abSab 	return (r);
1929d6538abSab }
1939d6538abSab 
1949d6538abSab /*
195ba7866cdSAli Bahrami  * If the current archive item is an ELF object, then ar(1) may have added
1969d6538abSab  * newline padding at the end in order to bring the following object
1979d6538abSab  * into PADSZ alignment within the file. This padding cannot be
198ba7866cdSAli Bahrami  * distinguished from data using the information kept in the member header.
1999d6538abSab  * This routine examines the objects, using knowledge of
20030a4e2aaSab  * ELF and how our tools lay out objects to determine whether padding was
20130a4e2aaSab  * added to an archive item. If so, it adjusts the st_size and
20230a4e2aaSab  * st_padding fields of the file argument to reflect it.
20330a4e2aaSab  */
20430a4e2aaSab static void
recover_padding(Elf * elf,ARFILE * file)20530a4e2aaSab recover_padding(Elf *elf, ARFILE *file)
20630a4e2aaSab {
207ba7866cdSAli Bahrami 	size_t		extent;
208ba7866cdSAli Bahrami 	size_t		padding;
209f0a0736fSRichard Lowe 	size_t		shnum;
210ba7866cdSAli Bahrami 	GElf_Ehdr	ehdr;
21130a4e2aaSab 
21230a4e2aaSab 
21330a4e2aaSab 	/* ar(1) only pads objects, so bail if not looking at one */
21430a4e2aaSab 	if (gelf_getclass(elf) == ELFCLASSNONE)
21530a4e2aaSab 		return;
21630a4e2aaSab 
21730a4e2aaSab 	/*
218d2d5cf7cSAli Bahrami 	 * libelf always puts the section header array at the end
21930a4e2aaSab 	 * of the object, and all of our compilers and other tools
220d2d5cf7cSAli Bahrami 	 * use libelf or follow this convention. So, it is extremely
22130a4e2aaSab 	 * likely that the section header array is at the end of this
22230a4e2aaSab 	 * object: Find the address at the end of the array and compare
2239d6538abSab 	 * it to the archive ar_size. If they are within PADSZ bytes, then
2249d6538abSab 	 * we've found the end, and the difference is padding (We assume
2259d6538abSab 	 * that no ELF section can fit into PADSZ bytes).
22630a4e2aaSab 	 */
227f0a0736fSRichard Lowe 	if (elf_getshdrnum(elf, &shnum) == -1)
228f0a0736fSRichard Lowe 		return;
229f0a0736fSRichard Lowe 
23030a4e2aaSab 	extent = gelf_getehdr(elf, &ehdr)
231f0a0736fSRichard Lowe 	    ? (ehdr.e_shoff + (shnum * ehdr.e_shentsize)) : 0;
23230a4e2aaSab 
233ba7866cdSAli Bahrami 	/*
234ba7866cdSAli Bahrami 	 * If the extent exceeds the end of the archive member
235ba7866cdSAli Bahrami 	 * (negative padding), then we don't know what is going on
236ba7866cdSAli Bahrami 	 * and simply leave things alone.
237ba7866cdSAli Bahrami 	 */
238ba7866cdSAli Bahrami 	if (extent > file->ar_size)
239ba7866cdSAli Bahrami 		return;
240ba7866cdSAli Bahrami 
241ba7866cdSAli Bahrami 	padding = file->ar_size - extent;
242ba7866cdSAli Bahrami 	if (padding >= PADSZ) {
24330a4e2aaSab 		/*
24430a4e2aaSab 		 * The section header array is not at the end of the object.
24530a4e2aaSab 		 * Traverse the section headers and look for the one with
24630a4e2aaSab 		 * the highest used address. If this address is within
2479d6538abSab 		 * PADSZ bytes of ar_size, then this is the end of the object.
24830a4e2aaSab 		 */
249ba7866cdSAli Bahrami 		Elf_Scn *scn = NULL;
25030a4e2aaSab 
25130a4e2aaSab 		do {
25230a4e2aaSab 			scn = elf_nextscn(elf, scn);
25330a4e2aaSab 			if (scn) {
25430a4e2aaSab 				GElf_Shdr shdr;
25530a4e2aaSab 
25630a4e2aaSab 				if (gelf_getshdr(scn, &shdr)) {
257ba7866cdSAli Bahrami 					size_t t;
258ba7866cdSAli Bahrami 
259ba7866cdSAli Bahrami 					t = shdr.sh_offset + shdr.sh_size;
26030a4e2aaSab 					if (t > extent)
26130a4e2aaSab 						extent = t;
26230a4e2aaSab 				}
26330a4e2aaSab 			}
26430a4e2aaSab 		} while (scn);
265ba7866cdSAli Bahrami 
266ba7866cdSAli Bahrami 		if (extent > file->ar_size)
267ba7866cdSAli Bahrami 			return;
268ba7866cdSAli Bahrami 		padding = file->ar_size - extent;
26930a4e2aaSab 	}
27030a4e2aaSab 
27130a4e2aaSab 	/*
27230a4e2aaSab 	 * Now, test the padding. We only act on padding in the range
2739d6538abSab 	 * (0 < pad < PADSZ) (ar(1) will never add more than this). A pad
2749d6538abSab 	 * of 0 requires no action, and any other size above (PADSZ-1) means
27530a4e2aaSab 	 * that we don't understand the layout of this object, and as such,
27630a4e2aaSab 	 * cannot do anything.
27730a4e2aaSab 	 *
2789d6538abSab 	 * If the padding is in range, and the raw data for the
27930a4e2aaSab 	 * object is available, then we perform one additional sanity
28030a4e2aaSab 	 * check before moving forward: ar(1) always pads with newline
28130a4e2aaSab 	 * characters. If anything else is seen, it is not padding so
28230a4e2aaSab 	 * leave it alone.
28330a4e2aaSab 	 */
284ba7866cdSAli Bahrami 	if (padding < PADSZ) {
28530a4e2aaSab 		if (file->ar_contents) {
286ba7866cdSAli Bahrami 			size_t cnt = padding;
28730a4e2aaSab 			char *p = file->ar_contents + extent;
28830a4e2aaSab 
28930a4e2aaSab 			while (cnt--) {
29030a4e2aaSab 				if (*p++ != '\n') {   /* No padding */
29130a4e2aaSab 					padding = 0;
29230a4e2aaSab 					break;
29330a4e2aaSab 				}
29430a4e2aaSab 			}
29530a4e2aaSab 		}
29630a4e2aaSab 
29730a4e2aaSab 		/* Remove the padding from the size */
29830a4e2aaSab 		file->ar_size -= padding;
29930a4e2aaSab 		file->ar_padding = padding;
30030a4e2aaSab 	}
30130a4e2aaSab }
30230a4e2aaSab 
303ba7866cdSAli Bahrami /*
304ba7866cdSAli Bahrami  * Each call to getfile() returns the next unread archive member
305ba7866cdSAli Bahrami  * from the archive opened by getaf(). Returns NULL if no more
306ba7866cdSAli Bahrami  * archive members are left.
307ba7866cdSAli Bahrami  */
3087c478bd9Sstevel@tonic-gate ARFILE *
getfile(Cmd_info * cmd_info)3097c478bd9Sstevel@tonic-gate getfile(Cmd_info *cmd_info)
3107c478bd9Sstevel@tonic-gate {
311ba7866cdSAli Bahrami 	Elf_Arhdr *mem_header = NULL;
3127c478bd9Sstevel@tonic-gate 	ARFILE	*file;
3137c478bd9Sstevel@tonic-gate 	char *tmp_rawname, *file_rawname;
3147c478bd9Sstevel@tonic-gate 	Elf *elf;
3157c478bd9Sstevel@tonic-gate 	char *arnam = cmd_info->arnam;
3167c478bd9Sstevel@tonic-gate 	int fd = cmd_info->afd;
3177c478bd9Sstevel@tonic-gate 	Elf *arf = cmd_info->arf;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if (fd == -1)
3207c478bd9Sstevel@tonic-gate 		return (NULL); /* the archive doesn't exist */
3217c478bd9Sstevel@tonic-gate 
322ba7866cdSAli Bahrami 	while (mem_header == NULL) {
3237c478bd9Sstevel@tonic-gate 		if ((elf = elf_begin(fd, ELF_C_READ, arf)) == 0)
324ba7866cdSAli Bahrami 			return (NULL);  /* archive is empty or have hit end */
325ba7866cdSAli Bahrami 
3267c478bd9Sstevel@tonic-gate 		if ((mem_header = elf_getarhdr(elf)) == NULL) {
327ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_MALARCHIVE),
328ba7866cdSAli Bahrami 			    arnam, EC_XWORD(elf_getbase(elf)), elf_errmsg(-1));
329ba7866cdSAli Bahrami 			exit(1);
330ba7866cdSAli Bahrami 		}
331ba7866cdSAli Bahrami 
332ba7866cdSAli Bahrami 		/* Ignore special members like the symbol and string tables */
333ba7866cdSAli Bahrami 		if (mem_header->ar_name[0] == '/') {
334ba7866cdSAli Bahrami 			(void) elf_next(elf);
335ba7866cdSAli Bahrami 			(void) elf_end(elf);
336ba7866cdSAli Bahrami 			mem_header = NULL;
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/*
3417c478bd9Sstevel@tonic-gate 	 * NOTE:
3427c478bd9Sstevel@tonic-gate 	 *	The mem_header->ar_name[] is set to a NULL string
3437c478bd9Sstevel@tonic-gate 	 *	if the archive member header has some error.
3447c478bd9Sstevel@tonic-gate 	 *	(See elf_getarhdr() man page.)
3457c478bd9Sstevel@tonic-gate 	 *	It is set to NULL for example, the ar command reads
3467c478bd9Sstevel@tonic-gate 	 *	the archive files created by SunOS 4.1 system.
3477c478bd9Sstevel@tonic-gate 	 *	See c block comment in cmd.c, "Incompatible Archive Header".
3487c478bd9Sstevel@tonic-gate 	 */
3497c478bd9Sstevel@tonic-gate 	file = newfile();
3507c478bd9Sstevel@tonic-gate 	(void) strncpy(file->ar_name, mem_header->ar_name, SNAME);
3517c478bd9Sstevel@tonic-gate 
352ba7866cdSAli Bahrami 	if ((file->ar_longname = malloc(strlen(mem_header->ar_name) + 1))
3537c478bd9Sstevel@tonic-gate 	    == NULL) {
354ba7866cdSAli Bahrami 		int err = errno;
355ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
3567c478bd9Sstevel@tonic-gate 		exit(1);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	(void) strcpy(file->ar_longname, mem_header->ar_name);
359ba7866cdSAli Bahrami 	if ((file->ar_rawname = malloc(strlen(mem_header->ar_rawname) + 1))
3607c478bd9Sstevel@tonic-gate 	    == NULL) {
361ba7866cdSAli Bahrami 		int err = errno;
362ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
3637c478bd9Sstevel@tonic-gate 		exit(1);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 	tmp_rawname = mem_header->ar_rawname;
3667c478bd9Sstevel@tonic-gate 	file_rawname = file->ar_rawname;
3677c478bd9Sstevel@tonic-gate 	while (!isspace(*tmp_rawname) &&
368d2d5cf7cSAli Bahrami 	    ((*file_rawname = *tmp_rawname) != '\0')) {
3697c478bd9Sstevel@tonic-gate 		file_rawname++;
3707c478bd9Sstevel@tonic-gate 		tmp_rawname++;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 	if (!(*tmp_rawname == '\0'))
3737c478bd9Sstevel@tonic-gate 		*file_rawname = '\0';
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	file->ar_date = mem_header->ar_date;
3767c478bd9Sstevel@tonic-gate 	file->ar_uid  = mem_header->ar_uid;
3777c478bd9Sstevel@tonic-gate 	file->ar_gid  = mem_header->ar_gid;
3787c478bd9Sstevel@tonic-gate 	file->ar_mode = (unsigned long) mem_header->ar_mode;
3797c478bd9Sstevel@tonic-gate 	file->ar_size = mem_header->ar_size;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	/* reverse logic */
382ba7866cdSAli Bahrami 	if ((cmd_info->opt_flgs & (t_FLAG | s_FLAG)) != t_FLAG) {
3837c478bd9Sstevel@tonic-gate 		size_t ptr;
3847c478bd9Sstevel@tonic-gate 		file->ar_flag = F_ELFRAW;
3857c478bd9Sstevel@tonic-gate 		if ((file->ar_contents = elf_rawfile(elf, &ptr))
3867c478bd9Sstevel@tonic-gate 		    == NULL) {
3877c478bd9Sstevel@tonic-gate 			if (ptr != 0) {
388ba7866cdSAli Bahrami 				(void) fprintf(stderr,
389ba7866cdSAli Bahrami 				    MSG_INTL(MSG_ELF_RAWFILE), elf_errmsg(-1));
3907c478bd9Sstevel@tonic-gate 				exit(1);
3917c478bd9Sstevel@tonic-gate 			}
3927c478bd9Sstevel@tonic-gate 		}
3937c478bd9Sstevel@tonic-gate 		file->ar_elf = elf;
3947c478bd9Sstevel@tonic-gate 	}
39530a4e2aaSab 
39630a4e2aaSab 	recover_padding(elf, file);
39730a4e2aaSab 
3987c478bd9Sstevel@tonic-gate 	(void) elf_next(elf);
3997c478bd9Sstevel@tonic-gate 	return (file);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
402ba7866cdSAli Bahrami /*
403ba7866cdSAli Bahrami  * Allocate a new archive member descriptor and add it to the list.
404ba7866cdSAli Bahrami  */
4057c478bd9Sstevel@tonic-gate ARFILE *
newfile(void)406d6555420Smike_s newfile(void)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 	static ARFILE	*buffer =  NULL;
409ba7866cdSAli Bahrami 	static size_t	count = 0;
410ba7866cdSAli Bahrami 	ARFILE		*fileptr;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (count == 0) {
4137c478bd9Sstevel@tonic-gate 		if ((buffer = (ARFILE *) calloc(CHUNK, sizeof (ARFILE)))
4147c478bd9Sstevel@tonic-gate 		    == NULL) {
415ba7866cdSAli Bahrami 			int err = errno;
416ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_MALLOC),
417ba7866cdSAli Bahrami 			    strerror(err));
4187c478bd9Sstevel@tonic-gate 			exit(1);
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 		count = CHUNK;
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 	count--;
4237c478bd9Sstevel@tonic-gate 	fileptr = buffer++;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	if (listhead)
4267c478bd9Sstevel@tonic-gate 		listend->ar_next = fileptr;
4277c478bd9Sstevel@tonic-gate 	else
4287c478bd9Sstevel@tonic-gate 		listhead = fileptr;
4297c478bd9Sstevel@tonic-gate 	listend = fileptr;
4307c478bd9Sstevel@tonic-gate 	return (fileptr);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate static char *
trimslash(char * s)4347c478bd9Sstevel@tonic-gate trimslash(char *s)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	static char buf[SNAME];
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, trim(s), SNAME - 2);
4397c478bd9Sstevel@tonic-gate 	buf[SNAME - 2] = '\0';
440ba7866cdSAli Bahrami 	return (strcat(buf, MSG_ORIG(MSG_STR_SLASH)));
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate char *
trim(char * s)4447c478bd9Sstevel@tonic-gate trim(char *s)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	char *p1, *p2;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	for (p1 = s; *p1; p1++)
4497c478bd9Sstevel@tonic-gate 		;
4507c478bd9Sstevel@tonic-gate 	while (p1 > s) {
4517c478bd9Sstevel@tonic-gate 		if (*--p1 != '/')
4527c478bd9Sstevel@tonic-gate 			break;
4537c478bd9Sstevel@tonic-gate 		*p1 = 0;
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	p2 = s;
4567c478bd9Sstevel@tonic-gate 	for (p1 = s; *p1; p1++)
4577c478bd9Sstevel@tonic-gate 		if (*p1 == '/')
4587c478bd9Sstevel@tonic-gate 			p2 = p1 + 1;
4597c478bd9Sstevel@tonic-gate 	return (p2);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 
463ba7866cdSAli Bahrami /*
464ba7866cdSAli Bahrami  * Find all the global symbols exported by ELF archive members, and
465ba7866cdSAli Bahrami  * build a list associating each one with the archive member that
466ba7866cdSAli Bahrami  * provides it.
467ba7866cdSAli Bahrami  *
468ba7866cdSAli Bahrami  * exit:
469ba7866cdSAli Bahrami  *	*symlist is set to the list of symbols. If any ELF object was
470ba7866cdSAli Bahrami  *	found, *found_obj is set to TRUE (1). Returns the number of symbols
471ba7866cdSAli Bahrami  *	located.
472ba7866cdSAli Bahrami  */
473ba7866cdSAli Bahrami static size_t
mksymtab(const char * arname,ARFILEP ** symlist,int * found_obj)474ba7866cdSAli Bahrami mksymtab(const char *arname, ARFILEP **symlist, int *found_obj)
4757c478bd9Sstevel@tonic-gate {
476ba7866cdSAli Bahrami 	ARFILE		*fptr;
477ba7866cdSAli Bahrami 	size_t		mem_offset = 0;
478fb25420bSRobert Mustacchi 	Elf		*elf;
479ba7866cdSAli Bahrami 	Elf_Scn		*scn;
480ba7866cdSAli Bahrami 	GElf_Ehdr	ehdr;
481ba7866cdSAli Bahrami 	int		newfd;
482ba7866cdSAli Bahrami 	size_t		nsyms = 0;
483ba7866cdSAli Bahrami 	int		class = 0;
484ba7866cdSAli Bahrami 	Elf_Data	*data;
485ba7866cdSAli Bahrami 	size_t		num_errs = 0;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	newfd = 0;
4887c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
4897c478bd9Sstevel@tonic-gate 		/* determine if file is coming from the archive or not */
490ba7866cdSAli Bahrami 		if ((fptr->ar_elf != NULL) && (fptr->ar_pathname == NULL)) {
4917c478bd9Sstevel@tonic-gate 			/*
4927c478bd9Sstevel@tonic-gate 			 * I can use the saved elf descriptor.
4937c478bd9Sstevel@tonic-gate 			 */
4947c478bd9Sstevel@tonic-gate 			elf = fptr->ar_elf;
495ba7866cdSAli Bahrami 		} else if ((fptr->ar_elf == NULL) &&
4967c478bd9Sstevel@tonic-gate 		    (fptr->ar_pathname != NULL)) {
497ba7866cdSAli Bahrami #ifdef _LP64
498ba7866cdSAli Bahrami 			/*
499ba7866cdSAli Bahrami 			 * The archive member header ar_size field is 10
500ba7866cdSAli Bahrami 			 * decimal digits, sufficient to represent a 32-bit
501ba7866cdSAli Bahrami 			 * value, but not a 64-bit one. Hence, we reject
502ba7866cdSAli Bahrami 			 * attempts to insert a member larger than 4GB.
503ba7866cdSAli Bahrami 			 *
504ba7866cdSAli Bahrami 			 * One obvious way to extend the format without altering
505ba7866cdSAli Bahrami 			 * the ar_hdr struct is to use the same mechanism used
506ba7866cdSAli Bahrami 			 * for ar_name: Put the size string into the long name
507ba7866cdSAli Bahrami 			 * string table and write a string /xxx into ar_size,
508ba7866cdSAli Bahrami 			 * where xxx is the string table offset.
509ba7866cdSAli Bahrami 			 *
510ba7866cdSAli Bahrami 			 * At the time of this writing (June 2010), the largest
511ba7866cdSAli Bahrami 			 * relocatable objects are measured in 10s or 100s
512ba7866cdSAli Bahrami 			 * of megabytes, so we still have many years to go
513ba7866cdSAli Bahrami 			 * before this becomes limiting. By that time, it may
514ba7866cdSAli Bahrami 			 * turn out that a completely new archive format is
515ba7866cdSAli Bahrami 			 * a better solution, as the current format has many
516ba7866cdSAli Bahrami 			 * warts and inefficiencies. In the meantime, we
517ba7866cdSAli Bahrami 			 * won't burden the current implementation with support
518ba7866cdSAli Bahrami 			 * for a bandaid feature that will have little use.
519ba7866cdSAli Bahrami 			 */
520ba7866cdSAli Bahrami 			if (fptr->ar_size > 0xffffffff) {
521ba7866cdSAli Bahrami 				(void) fprintf(stderr,
522ba7866cdSAli Bahrami 				    MSG_INTL(MSG_ERR_MEMBER4G),
523ba7866cdSAli Bahrami 				    fptr->ar_pathname);
524ba7866cdSAli Bahrami 				num_errs++;
525ba7866cdSAli Bahrami 				continue;
526ba7866cdSAli Bahrami 			}
527ba7866cdSAli Bahrami #endif
5287c478bd9Sstevel@tonic-gate 			if ((newfd  =
5297c478bd9Sstevel@tonic-gate 			    open(fptr->ar_pathname, O_RDONLY)) == -1) {
530ba7866cdSAli Bahrami 				int err = errno;
531ba7866cdSAli Bahrami 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
532ba7866cdSAli Bahrami 				    fptr->ar_pathname, strerror(err));
5337c478bd9Sstevel@tonic-gate 				num_errs++;
5347c478bd9Sstevel@tonic-gate 				continue;
5357c478bd9Sstevel@tonic-gate 			}
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 			if ((elf = elf_begin(newfd,
538d2d5cf7cSAli Bahrami 			    ELF_C_READ, (Elf *)0)) == 0) {
539ba7866cdSAli Bahrami 				(void) fprintf(stderr,
540ba7866cdSAli Bahrami 				    MSG_INTL(MSG_ELF_BEGIN_FILE),
541ba7866cdSAli Bahrami 				    fptr->ar_pathname, elf_errmsg(-1));
5427c478bd9Sstevel@tonic-gate 				(void) close(newfd);
5437c478bd9Sstevel@tonic-gate 				newfd = 0;
5447c478bd9Sstevel@tonic-gate 				num_errs++;
5457c478bd9Sstevel@tonic-gate 				continue;
5467c478bd9Sstevel@tonic-gate 			}
5477c478bd9Sstevel@tonic-gate 			if (elf_kind(elf) == ELF_K_AR) {
5487c478bd9Sstevel@tonic-gate 				if (newfd) {
5497c478bd9Sstevel@tonic-gate 					(void) close(newfd);
5507c478bd9Sstevel@tonic-gate 					newfd = 0;
5517c478bd9Sstevel@tonic-gate 				}
5527c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
5537c478bd9Sstevel@tonic-gate 				continue;
5547c478bd9Sstevel@tonic-gate 			}
5557c478bd9Sstevel@tonic-gate 		} else {
556ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_INTERNAL_01));
5577c478bd9Sstevel@tonic-gate 			exit(1);
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 		if (gelf_getehdr(elf, &ehdr) != 0) {
560f0a0736fSRichard Lowe 			size_t shstrndx = 0;
5617c478bd9Sstevel@tonic-gate 			if ((class = gelf_getclass(elf)) == ELFCLASS64) {
5627c478bd9Sstevel@tonic-gate 				fptr->ar_flag |= F_CLASS64;
5637c478bd9Sstevel@tonic-gate 			} else if (class == ELFCLASS32)
5647c478bd9Sstevel@tonic-gate 				fptr->ar_flag |= F_CLASS32;
565f0a0736fSRichard Lowe 
566f0a0736fSRichard Lowe 			if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
567f0a0736fSRichard Lowe 				if (fptr->ar_pathname != NULL) {
568f0a0736fSRichard Lowe 					(void) fprintf(stderr,
569f0a0736fSRichard Lowe 					    MSG_INTL(MSG_ELF_GETSHSTRNDX_FILE),
570f0a0736fSRichard Lowe 					    fptr->ar_pathname, elf_errmsg(-1));
571f0a0736fSRichard Lowe 				} else {
572f0a0736fSRichard Lowe 					(void) fprintf(stderr,
573f0a0736fSRichard Lowe 					    MSG_INTL(MSG_ELF_GETSHSTRNDX_AR),
574f0a0736fSRichard Lowe 					    arname, fptr->ar_longname,
575f0a0736fSRichard Lowe 					    elf_errmsg(-1));
576f0a0736fSRichard Lowe 				}
577f0a0736fSRichard Lowe 				num_errs++;
578f0a0736fSRichard Lowe 				if (newfd) {
579f0a0736fSRichard Lowe 					(void) close(newfd);
580f0a0736fSRichard Lowe 					newfd = 0;
581f0a0736fSRichard Lowe 				}
582f0a0736fSRichard Lowe 				(void) elf_end(elf);
583f0a0736fSRichard Lowe 				continue;
584f0a0736fSRichard Lowe 			}
585f0a0736fSRichard Lowe 
586f0a0736fSRichard Lowe 			scn = elf_getscn(elf, shstrndx);
5877c478bd9Sstevel@tonic-gate 			if (scn == NULL) {
5887c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
589ba7866cdSAli Bahrami 					(void) fprintf(stderr,
590ba7866cdSAli Bahrami 					    MSG_INTL(MSG_ELF_GETSCN_FILE),
591ba7866cdSAli Bahrami 					    fptr->ar_pathname, elf_errmsg(-1));
5927c478bd9Sstevel@tonic-gate 				else
593ba7866cdSAli Bahrami 					(void) fprintf(stderr,
594ba7866cdSAli Bahrami 					    MSG_INTL(MSG_ELF_GETSCN_AR),
595ba7866cdSAli Bahrami 					    arname, fptr->ar_longname,
596ba7866cdSAli Bahrami 					    elf_errmsg(-1));
5977c478bd9Sstevel@tonic-gate 				num_errs++;
5987c478bd9Sstevel@tonic-gate 				if (newfd) {
5997c478bd9Sstevel@tonic-gate 					(void) close(newfd);
6007c478bd9Sstevel@tonic-gate 					newfd = 0;
6017c478bd9Sstevel@tonic-gate 				}
6027c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
6037c478bd9Sstevel@tonic-gate 				continue;
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 			data = 0;
6077c478bd9Sstevel@tonic-gate 			data = elf_getdata(scn, data);
6087c478bd9Sstevel@tonic-gate 			if (data == NULL) {
6097c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
610ba7866cdSAli Bahrami 					(void) fprintf(stderr,
611ba7866cdSAli Bahrami 					    MSG_INTL(MSG_ELF_GETDATA_FILE),
612ba7866cdSAli Bahrami 					    fptr->ar_pathname, elf_errmsg(-1));
6137c478bd9Sstevel@tonic-gate 				else
614ba7866cdSAli Bahrami 					(void) fprintf(stderr,
615ba7866cdSAli Bahrami 					    MSG_INTL(MSG_ELF_GETDATA_AR),
616ba7866cdSAli Bahrami 					    arname, fptr->ar_longname,
617ba7866cdSAli Bahrami 					    elf_errmsg(-1));
6187c478bd9Sstevel@tonic-gate 				num_errs++;
6197c478bd9Sstevel@tonic-gate 				if (newfd) {
6207c478bd9Sstevel@tonic-gate 					(void) close(newfd);
6217c478bd9Sstevel@tonic-gate 					newfd = 0;
6227c478bd9Sstevel@tonic-gate 				}
6237c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
6247c478bd9Sstevel@tonic-gate 				continue;
6257c478bd9Sstevel@tonic-gate 			}
6267c478bd9Sstevel@tonic-gate 			if (data->d_size == 0) {
6277c478bd9Sstevel@tonic-gate 				if (fptr->ar_pathname != NULL)
628ba7866cdSAli Bahrami 					(void) fprintf(stderr,
629ba7866cdSAli Bahrami 					    MSG_INTL(MSG_W_ELF_NODATA_FILE),
630d2d5cf7cSAli Bahrami 					    fptr->ar_pathname);
6317c478bd9Sstevel@tonic-gate 				else
632ba7866cdSAli Bahrami 					(void) fprintf(stderr,
633ba7866cdSAli Bahrami 					    MSG_INTL(MSG_W_ELF_NODATA_AR),
634ba7866cdSAli Bahrami 					    arname, fptr->ar_longname);
6357c478bd9Sstevel@tonic-gate 				if (newfd) {
6367c478bd9Sstevel@tonic-gate 					(void) close(newfd);
6377c478bd9Sstevel@tonic-gate 					newfd = 0;
6387c478bd9Sstevel@tonic-gate 				}
6397c478bd9Sstevel@tonic-gate 				(void) elf_end(elf);
6407c478bd9Sstevel@tonic-gate 				num_errs++;
6417c478bd9Sstevel@tonic-gate 				continue;
6427c478bd9Sstevel@tonic-gate 			}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 			/* loop through sections to find symbol table */
6457c478bd9Sstevel@tonic-gate 			scn = 0;
6467c478bd9Sstevel@tonic-gate 			while ((scn = elf_nextscn(elf, scn)) != 0) {
6477c478bd9Sstevel@tonic-gate 				GElf_Shdr shdr;
6487c478bd9Sstevel@tonic-gate 				if (gelf_getshdr(scn, &shdr) == NULL) {
649ba7866cdSAli Bahrami 					/* BEGIN CSTYLED */
6507c478bd9Sstevel@tonic-gate 					if (fptr->ar_pathname != NULL)
651ba7866cdSAli Bahrami 					    (void) fprintf(stderr,
652ba7866cdSAli Bahrami 						MSG_INTL(MSG_ELF_GETDATA_FILE),
653ba7866cdSAli Bahrami 						fptr->ar_pathname,
654ba7866cdSAli Bahrami 						elf_errmsg(-1));
6557c478bd9Sstevel@tonic-gate 					else
656ba7866cdSAli Bahrami 					    (void) fprintf(stderr,
657ba7866cdSAli Bahrami 						MSG_INTL(MSG_ELF_GETDATA_AR),
658ba7866cdSAli Bahrami 						arname, fptr->ar_longname,
659ba7866cdSAli Bahrami 						elf_errmsg(-1));
660ba7866cdSAli Bahrami 					/* END CSTYLED */
6617c478bd9Sstevel@tonic-gate 					if (newfd) {
6627c478bd9Sstevel@tonic-gate 						(void) close(newfd);
6637c478bd9Sstevel@tonic-gate 						newfd = 0;
6647c478bd9Sstevel@tonic-gate 					}
6657c478bd9Sstevel@tonic-gate 					num_errs++;
6667c478bd9Sstevel@tonic-gate 					(void) elf_end(elf);
6677c478bd9Sstevel@tonic-gate 					continue;
6687c478bd9Sstevel@tonic-gate 				}
6697c478bd9Sstevel@tonic-gate 				*found_obj = 1;
670f0a0736fSRichard Lowe 				if (shdr.sh_type == SHT_SYMTAB) {
671ba7866cdSAli Bahrami 					if (search_sym_tab(arname, fptr, elf,
672d2d5cf7cSAli Bahrami 					    scn, &nsyms, symlist,
673d2d5cf7cSAli Bahrami 					    &num_errs) == -1) {
674d2d5cf7cSAli Bahrami 						if (newfd) {
675d2d5cf7cSAli Bahrami 							(void) close(newfd);
676d2d5cf7cSAli Bahrami 							newfd = 0;
677d2d5cf7cSAli Bahrami 						}
678d2d5cf7cSAli Bahrami 						continue;
6797c478bd9Sstevel@tonic-gate 					}
680f0a0736fSRichard Lowe 				}
6817c478bd9Sstevel@tonic-gate 			}
6827c478bd9Sstevel@tonic-gate 		}
6837c478bd9Sstevel@tonic-gate 		mem_offset += sizeof (struct ar_hdr) + fptr->ar_size;
6847c478bd9Sstevel@tonic-gate 		if (fptr->ar_size & 01)
6857c478bd9Sstevel@tonic-gate 			mem_offset++;
6867c478bd9Sstevel@tonic-gate 		(void) elf_end(elf);
6877c478bd9Sstevel@tonic-gate 		if (newfd) {
6887c478bd9Sstevel@tonic-gate 			(void) close(newfd);
6897c478bd9Sstevel@tonic-gate 			newfd = 0;
6907c478bd9Sstevel@tonic-gate 		}
691ba7866cdSAli Bahrami 	}
6927c478bd9Sstevel@tonic-gate 	if (num_errs)
6937c478bd9Sstevel@tonic-gate 		exit(1);
694ba7866cdSAli Bahrami 
695ba7866cdSAli Bahrami 	if (found_obj) {
696ba7866cdSAli Bahrami 		if (nsyms == 0) {
697ba7866cdSAli Bahrami 			/*
698ba7866cdSAli Bahrami 			 * It is possible, though rare, to have ELF objects
699ba7866cdSAli Bahrami 			 * that do not export any global symbols. Presumably
700ba7866cdSAli Bahrami 			 * such objects operate via their .init/.fini
701ba7866cdSAli Bahrami 			 * sections. In this case, we produce an empty
702ba7866cdSAli Bahrami 			 * symbol table, so that applications that rely
703ba7866cdSAli Bahrami 			 * on a successful call to elf_getarsym() to determine
704ba7866cdSAli Bahrami 			 * if ELF objects are present will succeed. To do this,
705ba7866cdSAli Bahrami 			 * we require a small empty symbol string table.
706ba7866cdSAli Bahrami 			 */
707ba7866cdSAli Bahrami 			strtbl_pad(&sym_strtbl, 4, '\0');
708ba7866cdSAli Bahrami 		} else {
709ba7866cdSAli Bahrami 			/*
710ba7866cdSAli Bahrami 			 * Historical behavior is to pad string tables
711ba7866cdSAli Bahrami 			 * to a multiple of 4.
712ba7866cdSAli Bahrami 			 */
713ba7866cdSAli Bahrami 			strtbl_pad(&sym_strtbl, pad(sym_strtbl.used, 4), '\0');
714ba7866cdSAli Bahrami 		}
715ba7866cdSAli Bahrami 
716ba7866cdSAli Bahrami 	}
717ba7866cdSAli Bahrami 
7187c478bd9Sstevel@tonic-gate 	return (nsyms);
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate /*
722ba7866cdSAli Bahrami  * Output a member header.
7237c478bd9Sstevel@tonic-gate  */
724ba7866cdSAli Bahrami /*ARGSUSED*/
725ba7866cdSAli Bahrami static void
write_member_header(const char * filename,int fd,int is_elf,const char * name,time_t timestamp,uid_t uid,gid_t gid,mode_t mode,size_t size)726ba7866cdSAli Bahrami write_member_header(const char *filename, int fd, int is_elf,
727ba7866cdSAli Bahrami     const char *name, time_t timestamp, uid_t uid, gid_t gid, mode_t mode,
728ba7866cdSAli Bahrami     size_t size)
7297c478bd9Sstevel@tonic-gate {
730ba7866cdSAli Bahrami 	char	buf[sizeof (struct ar_hdr) + 1];
731ba7866cdSAli Bahrami 	int	len;
732ba7866cdSAli Bahrami 
733ba7866cdSAli Bahrami 	len = snprintf(buf, sizeof (buf), MSG_ORIG(MSG_MH_FORMAT), name,
734ba7866cdSAli Bahrami 	    EC_WORD(timestamp), EC_WORD(uid), EC_WORD(gid), EC_WORD(mode),
735ba7866cdSAli Bahrami 	    EC_XWORD(size), ARFMAG);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/*
738ba7866cdSAli Bahrami 	 * If snprintf() reports that it needed more space than we gave
739ba7866cdSAli Bahrami 	 * it, it means that the caller fed us a long name, which is a
740ba7866cdSAli Bahrami 	 * fatal internal error.
7417c478bd9Sstevel@tonic-gate 	 */
742ba7866cdSAli Bahrami 	if (len != sizeof (struct ar_hdr)) {
743ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_INTERNAL_02));
7447c478bd9Sstevel@tonic-gate 		exit(1);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
747ba7866cdSAli Bahrami 	arwrite(filename, fd, buf, len);
748ba7866cdSAli Bahrami 
749ba7866cdSAli Bahrami 	/*
750ba7866cdSAli Bahrami 	 * We inject inter-member padding to ensure that ELF object
751ba7866cdSAli Bahrami 	 * member data is aligned on PADSZ. If this is a debug build,
752ba7866cdSAli Bahrami 	 * verify that the computations were right.
753ba7866cdSAli Bahrami 	 */
754ba7866cdSAli Bahrami 	assert(!is_elf || (pad(lseek(fd, 0, SEEK_CUR), PADSZ) == 0));
755ba7866cdSAli Bahrami }
756ba7866cdSAli Bahrami 
757ba7866cdSAli Bahrami /*
758ba7866cdSAli Bahrami  * Write the archive symbol table member to the output archive file.
759ba7866cdSAli Bahrami  *
760ba7866cdSAli Bahrami  * note:
761ba7866cdSAli Bahrami  *	sizeofmembers() must have been called to establish member offset
762ba7866cdSAli Bahrami  *	and padding values before writesymtab() is used.
763ba7866cdSAli Bahrami  */
764ba7866cdSAli Bahrami static void
writesymtab(const char * filename,int fd,size_t nsyms,ARFILEP * symlist,size_t eltsize)765ba7866cdSAli Bahrami writesymtab(const char *filename, int fd, size_t nsyms, ARFILEP *symlist,
766ba7866cdSAli Bahrami     size_t eltsize)
767ba7866cdSAli Bahrami {
768ba7866cdSAli Bahrami 	size_t	i, j;
769ba7866cdSAli Bahrami 	ARFILEP	*ptr;
770ba7866cdSAli Bahrami 	size_t	tblsize;
771ba7866cdSAli Bahrami 	char	*buf, *dst;
772ba7866cdSAli Bahrami 	int	is64 = (eltsize == 8);
773ba7866cdSAli Bahrami 
774ba7866cdSAli Bahrami 	/*
775ba7866cdSAli Bahrami 	 * We require a buffer large enough to hold a symbol table count,
776ba7866cdSAli Bahrami 	 * plus one offset for each symbol.
777ba7866cdSAli Bahrami 	 */
778ba7866cdSAli Bahrami 	tblsize = (nsyms + 1) * eltsize;
779ba7866cdSAli Bahrami 	if ((buf = dst = malloc(tblsize)) == NULL) {
780ba7866cdSAli Bahrami 		int err = errno;
781ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
7827c478bd9Sstevel@tonic-gate 		exit(1);
7837c478bd9Sstevel@tonic-gate 	}
784ba7866cdSAli Bahrami 
785ba7866cdSAli Bahrami 	write_member_header(filename, fd, 0,
786ba7866cdSAli Bahrami 	    (is64 ? MSG_ORIG(MSG_STR_SYM64) : MSG_ORIG(MSG_STR_SLASH)),
787ba7866cdSAli Bahrami 	    time(0), 0, 0, 0, tblsize + sym_strtbl.used);
788ba7866cdSAli Bahrami 
789ba7866cdSAli Bahrami 	dst = is64 ? sputl64(nsyms, dst) : sputl32(nsyms, dst);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	for (i = 0, j = SYMCHUNK, ptr = symlist; i < nsyms; i++, j--, ptr++) {
7927c478bd9Sstevel@tonic-gate 		if (!j) {
7937c478bd9Sstevel@tonic-gate 			j = SYMCHUNK;
7947c478bd9Sstevel@tonic-gate 			ptr = (ARFILEP *)*ptr;
7957c478bd9Sstevel@tonic-gate 		}
796ba7866cdSAli Bahrami 		dst = is64 ? sputl64((*ptr)->ar_offset, dst) :
797ba7866cdSAli Bahrami 		    sputl32((*ptr)->ar_offset, dst);
7987c478bd9Sstevel@tonic-gate 	}
799ba7866cdSAli Bahrami 	arwrite(filename, fd, buf, tblsize);
800ba7866cdSAli Bahrami 	free(buf);
801ba7866cdSAli Bahrami 	arwrite(filename, fd, sym_strtbl.base, sym_strtbl.used);
802ba7866cdSAli Bahrami }
803ba7866cdSAli Bahrami 
804ba7866cdSAli Bahrami /*
805ba7866cdSAli Bahrami  * Grow the size of the given string table so that there is room
806ba7866cdSAli Bahrami  * for at least need bytes.
807ba7866cdSAli Bahrami  *
808ba7866cdSAli Bahrami  * entry:
809ba7866cdSAli Bahrami  *	strtbl - String table to grow
810ba7866cdSAli Bahrami  *	need - Amount of space required by caller
811ba7866cdSAli Bahrami  */
812ba7866cdSAli Bahrami static void
strtbl_alloc(ARSTRTBL * strtbl,size_t need)813ba7866cdSAli Bahrami strtbl_alloc(ARSTRTBL *strtbl, size_t need)
814ba7866cdSAli Bahrami {
815ba7866cdSAli Bahrami #define	STRTBL_INITSZ	8196
816ba7866cdSAli Bahrami 
817ba7866cdSAli Bahrami 	/*
818ba7866cdSAli Bahrami 	 * On 32-bit systems, we require a larger integer type in order
819ba7866cdSAli Bahrami 	 * to avoid overflow and wraparound when doing our computations.
820ba7866cdSAli Bahrami 	 */
821ba7866cdSAli Bahrami 	uint64_t	need64 = need;
822ba7866cdSAli Bahrami 	uint64_t	used64 = strtbl->used;
823ba7866cdSAli Bahrami 	uint64_t	size64 = strtbl->size;
824ba7866cdSAli Bahrami 	uint64_t	target = need64 + used64;
825ba7866cdSAli Bahrami 
826ba7866cdSAli Bahrami 	int		sys32, tbl32;
827ba7866cdSAli Bahrami 
828ba7866cdSAli Bahrami 	if (target <= size64)
829ba7866cdSAli Bahrami 		return;
830ba7866cdSAli Bahrami 
831ba7866cdSAli Bahrami 	/*
832ba7866cdSAli Bahrami 	 * Detect 32-bit system. We might usually do this with the preprocessor,
833ba7866cdSAli Bahrami 	 * but it can serve as a predicate in tests that also apply to 64-bit
834ba7866cdSAli Bahrami 	 * systems.
835ba7866cdSAli Bahrami 	 */
836ba7866cdSAli Bahrami 	sys32 = (sizeof (size_t) == 4);
837ba7866cdSAli Bahrami 
838ba7866cdSAli Bahrami 	/*
839ba7866cdSAli Bahrami 	 * The symbol string table can be larger than 32-bits on a 64-bit
840ba7866cdSAli Bahrami 	 * system. However, the long name table must stay below that limit.
841ba7866cdSAli Bahrami 	 * The reason for this is that there is not enough room in the ar_name
842ba7866cdSAli Bahrami 	 * field of the member header to represent 64-bit offsets.
843ba7866cdSAli Bahrami 	 */
844ba7866cdSAli Bahrami 	tbl32 = (strtbl == &long_strtbl);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	/*
847ba7866cdSAli Bahrami 	 * If request is larger than 4GB and we can't do it because we
848ba7866cdSAli Bahrami 	 * are a 32-bit program, or because the table is format limited,
849ba7866cdSAli Bahrami 	 * we can go no further.
8507c478bd9Sstevel@tonic-gate 	 */
851ba7866cdSAli Bahrami 	if ((target > 0xffffffff) && (sys32 || tbl32))
852ba7866cdSAli Bahrami 		goto limit_fail;
853ba7866cdSAli Bahrami 
854ba7866cdSAli Bahrami 	/* Default starting size */
855ba7866cdSAli Bahrami 	if (strtbl->base == NULL)
856ba7866cdSAli Bahrami 		size64 = STRTBL_INITSZ;
857ba7866cdSAli Bahrami 
858ba7866cdSAli Bahrami 	/*
859ba7866cdSAli Bahrami 	 * Our strategy is to double the size until we find a size that
860ba7866cdSAli Bahrami 	 * exceeds the request. However, if this table cannot exceed 4GB,
861ba7866cdSAli Bahrami 	 * then once we exceed 2GB, we switch to a strategy of taking the
862ba7866cdSAli Bahrami 	 * current request and rounding it up to STRTBL_INITSZ.
863ba7866cdSAli Bahrami 	 */
864ba7866cdSAli Bahrami 	while (target > size64) {
865ba7866cdSAli Bahrami 		if ((target > 0x7fffffff) && (sys32 || tbl32)) {
866ba7866cdSAli Bahrami 			size64 = ((target + STRTBL_INITSZ) / STRTBL_INITSZ) *
867ba7866cdSAli Bahrami 			    STRTBL_INITSZ;
868ba7866cdSAli Bahrami 
869ba7866cdSAli Bahrami 			/*
870ba7866cdSAli Bahrami 			 * If we are so close to the line that this small
871ba7866cdSAli Bahrami 			 * increment exceeds 4GB, give it up.
872ba7866cdSAli Bahrami 			 */
873ba7866cdSAli Bahrami 			if ((size64 > 0xffffffff) && (sys32 || tbl32))
874ba7866cdSAli Bahrami 				goto limit_fail;
875ba7866cdSAli Bahrami 
876ba7866cdSAli Bahrami 			break;
877ba7866cdSAli Bahrami 		}
878ba7866cdSAli Bahrami 
879ba7866cdSAli Bahrami 		size64 *= 2;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
882ba7866cdSAli Bahrami 	strtbl->base = realloc(strtbl->base, size64);
883ba7866cdSAli Bahrami 	if (strtbl->base == NULL) {
884ba7866cdSAli Bahrami 		int err = errno;
885ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
886ba7866cdSAli Bahrami 		exit(1);
887ba7866cdSAli Bahrami 	}
888ba7866cdSAli Bahrami 	strtbl->size = (size_t)size64;
889ba7866cdSAli Bahrami 	return;
890ba7866cdSAli Bahrami 
891ba7866cdSAli Bahrami limit_fail:
892ba7866cdSAli Bahrami 	/*
893ba7866cdSAli Bahrami 	 * Control comes here if we are unable to allocate more than 4GB of
894ba7866cdSAli Bahrami 	 * memory for the string table due to one of the following reasons:
895ba7866cdSAli Bahrami 	 *
896ba7866cdSAli Bahrami 	 * - A 32-bit process is attempting to be larger than 4GB
897ba7866cdSAli Bahrami 	 *
898ba7866cdSAli Bahrami 	 * - A 64-bit process is attempting to grow the long names string
899ba7866cdSAli Bahrami 	 *	table beyond the ar format limit of 32-bits.
900ba7866cdSAli Bahrami 	 */
901ba7866cdSAli Bahrami 	if (sys32)
902ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(ENOMEM));
903ba7866cdSAli Bahrami 	else
904ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_LONGSTRTBLSZ));
905ba7866cdSAli Bahrami 	exit(1);
906ba7866cdSAli Bahrami 
907ba7866cdSAli Bahrami #undef STRTBL_INITSZ
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate 
910ba7866cdSAli Bahrami /*
911ba7866cdSAli Bahrami  * Add the specified number of pad characters to the end of the
912ba7866cdSAli Bahrami  * given string table.
913ba7866cdSAli Bahrami  *
914ba7866cdSAli Bahrami  * entry:
915ba7866cdSAli Bahrami  *	strtbl - String table to pad
916ba7866cdSAli Bahrami  *	n - # of pad characters to add
917ba7866cdSAli Bahrami  *	ch - Pad character to use
918ba7866cdSAli Bahrami  */
9197c478bd9Sstevel@tonic-gate static void
strtbl_pad(ARSTRTBL * strtbl,size_t n,int ch)920ba7866cdSAli Bahrami strtbl_pad(ARSTRTBL *strtbl, size_t n, int ch)
9217c478bd9Sstevel@tonic-gate {
922ba7866cdSAli Bahrami 	if (n == 0)
923ba7866cdSAli Bahrami 		return;
9247c478bd9Sstevel@tonic-gate 
925ba7866cdSAli Bahrami 	if ((n + strtbl->used) > strtbl->size)
926ba7866cdSAli Bahrami 		strtbl_alloc(strtbl, n);
9277c478bd9Sstevel@tonic-gate 
928ba7866cdSAli Bahrami 	while (n--)
929ba7866cdSAli Bahrami 		strtbl->base[strtbl->used++] = ch;
930ba7866cdSAli Bahrami }
9317c478bd9Sstevel@tonic-gate 
932ba7866cdSAli Bahrami /*
933ba7866cdSAli Bahrami  * Enter a symbol name into the symbol string table.
934ba7866cdSAli Bahrami  */
935ba7866cdSAli Bahrami static void
savename(char * symbol)936ba7866cdSAli Bahrami savename(char *symbol)
937ba7866cdSAli Bahrami {
938ba7866cdSAli Bahrami 	size_t need;
939ba7866cdSAli Bahrami 
940ba7866cdSAli Bahrami 	need = strlen(symbol) + 1;
941ba7866cdSAli Bahrami 	if ((need + sym_strtbl.used) > sym_strtbl.size)
942ba7866cdSAli Bahrami 		strtbl_alloc(&sym_strtbl, need);
943ba7866cdSAli Bahrami 
944ba7866cdSAli Bahrami 	(void) strcpy(sym_strtbl.base + sym_strtbl.used, symbol);
945ba7866cdSAli Bahrami 	sym_strtbl.used += need;
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
948ba7866cdSAli Bahrami /*
949ba7866cdSAli Bahrami  * Prepare an archive member with a long (>15 characters) name for
950ba7866cdSAli Bahrami  * the output archive.
951ba7866cdSAli Bahrami  *
952ba7866cdSAli Bahrami  * entry:
953ba7866cdSAli Bahrami  *	fptr - pointer to archive member with long name
954ba7866cdSAli Bahrami  *
955ba7866cdSAli Bahrami  * exit:
956ba7866cdSAli Bahrami  *	The long name is entered into the long name string table,
957ba7866cdSAli Bahrami  *	and fptr->ar_name has been replaced with the special /xxx
958ba7866cdSAli Bahrami  *	name used to indicate that the real name is in the string table
959ba7866cdSAli Bahrami  *	at offset xxx.
960ba7866cdSAli Bahrami  */
9617c478bd9Sstevel@tonic-gate static void
savelongname(ARFILE * fptr)962ba7866cdSAli Bahrami savelongname(ARFILE *fptr)
9637c478bd9Sstevel@tonic-gate {
964ba7866cdSAli Bahrami 	size_t	len, need;
965ba7866cdSAli Bahrami 	char	*p;
9667c478bd9Sstevel@tonic-gate 
967ba7866cdSAli Bahrami 	/* Size of new item to add */
968ba7866cdSAli Bahrami 	len = strlen(fptr->ar_longname);
969ba7866cdSAli Bahrami 	need = len + 2;
970ba7866cdSAli Bahrami 
971ba7866cdSAli Bahrami 	/* Ensure there's room */
972ba7866cdSAli Bahrami 	if ((need + long_strtbl.used) > long_strtbl.size)
973ba7866cdSAli Bahrami 		strtbl_alloc(&long_strtbl, need);
974ba7866cdSAli Bahrami 
975ba7866cdSAli Bahrami 	/*
976ba7866cdSAli Bahrami 	 * Generate the index string to be written into the member header
977ba7866cdSAli Bahrami 	 *
978ba7866cdSAli Bahrami 	 * This will not overflow the ar_name field because that field is
979ba7866cdSAli Bahrami 	 * 16 characters in size, and a 32-bit unsigned value can be formatted
980ba7866cdSAli Bahrami 	 * in 10 characters. Allowing a character for the leading '/', and one
981ba7866cdSAli Bahrami 	 * for the NULL termination, that leaves us with 4 extra spaces.
982ba7866cdSAli Bahrami 	 */
983ba7866cdSAli Bahrami 	(void) snprintf(fptr->ar_name, sizeof (fptr->ar_name),
984ba7866cdSAli Bahrami 	    MSG_ORIG(MSG_FMT_LLINT), EC_XWORD(long_strtbl.used));
985ba7866cdSAli Bahrami 
986ba7866cdSAli Bahrami 	/*
987ba7866cdSAli Bahrami 	 * Enter long name into reserved spot, terminated with a slash
988ba7866cdSAli Bahrami 	 * and a newline character.
989ba7866cdSAli Bahrami 	 */
990ba7866cdSAli Bahrami 	p = long_strtbl.base + long_strtbl.used;
991ba7866cdSAli Bahrami 	long_strtbl.used += need;
992ba7866cdSAli Bahrami 	(void) strcpy(p, fptr->ar_longname);
993ba7866cdSAli Bahrami 	p += len;
9947c478bd9Sstevel@tonic-gate 	*p++ = '/';
9957c478bd9Sstevel@tonic-gate 	*p++ = '\n';
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
998ba7866cdSAli Bahrami /*
999ba7866cdSAli Bahrami  * Determine if the archive we're about to write will exceed the
1000ba7866cdSAli Bahrami  * 32-bit limit of 4GB.
1001ba7866cdSAli Bahrami  *
1002ba7866cdSAli Bahrami  * entry:
1003ba7866cdSAli Bahrami  *      mksymtab() and mklong_tab() have been called to set up
1004ba7866cdSAli Bahrami  *	the string tables.
1005ba7866cdSAli Bahrami  *
1006ba7866cdSAli Bahrami  * exit:
1007ba7866cdSAli Bahrami  *	Returns TRUE (1) if the 64-bit symbol table is needed, and
1008ba7866cdSAli Bahrami  *	FALSE (0) otherwise.
1009ba7866cdSAli Bahrami  *
1010ba7866cdSAli Bahrami  */
1011ba7866cdSAli Bahrami static int
require64(size_t nsyms,int found_obj,size_t longnames)1012ba7866cdSAli Bahrami require64(size_t nsyms, int found_obj, size_t longnames)
1013ba7866cdSAli Bahrami {
1014ba7866cdSAli Bahrami 	ARFILE		*fptr;
1015ba7866cdSAli Bahrami 	uint64_t	size;
1016ba7866cdSAli Bahrami 
1017ba7866cdSAli Bahrami 	/*
1018ba7866cdSAli Bahrami 	 * If there are more than 4GB symbols, we have to use
1019ba7866cdSAli Bahrami 	 * the 64-bit form. Note that longnames cannot exceed 4GB
1020ba7866cdSAli Bahrami 	 * because that symbol table is limited to a length of 4GB by
1021ba7866cdSAli Bahrami 	 * the archive format.
1022ba7866cdSAli Bahrami 	 */
1023ba7866cdSAli Bahrami 	if (nsyms > 0xffffffff)
1024ba7866cdSAli Bahrami 		return (1);
1025ba7866cdSAli Bahrami 
1026ba7866cdSAli Bahrami 	/*
1027ba7866cdSAli Bahrami 	 * Make a worst case estimate for the size of the resulting
1028ba7866cdSAli Bahrami 	 * archive by assuming full padding between members.
1029ba7866cdSAli Bahrami 	 */
1030fb25420bSRobert Mustacchi 	size = SARMAG;
1031ba7866cdSAli Bahrami 	if (longnames)
1032ba7866cdSAli Bahrami 		size += sizeof (struct ar_hdr) + long_strtbl.used + PADSZ;
1033ba7866cdSAli Bahrami 
1034ba7866cdSAli Bahrami 	if (found_obj)
1035ba7866cdSAli Bahrami 		size += sizeof_symtbl(nsyms, found_obj, 4) + PADSZ;
1036ba7866cdSAli Bahrami 
1037ba7866cdSAli Bahrami 	if (size > 0xffffffff)
1038ba7866cdSAli Bahrami 		return (1);
1039ba7866cdSAli Bahrami 
1040ba7866cdSAli Bahrami 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1041ba7866cdSAli Bahrami 		size += sizeof (struct ar_hdr) + fptr->ar_size + PADSZ;
1042ba7866cdSAli Bahrami 
1043ba7866cdSAli Bahrami 		if (size > 0xffffffff)
1044ba7866cdSAli Bahrami 			return (1);
1045ba7866cdSAli Bahrami 	}
1046ba7866cdSAli Bahrami 
1047ba7866cdSAli Bahrami 	/* 32-bit symbol table will suffice */
1048ba7866cdSAli Bahrami 	return (0);
1049ba7866cdSAli Bahrami }
1050ba7866cdSAli Bahrami 
1051ba7866cdSAli Bahrami void
writefile(Cmd_info * cmd_info)10527c478bd9Sstevel@tonic-gate writefile(Cmd_info *cmd_info)
10537c478bd9Sstevel@tonic-gate {
1054ba7866cdSAli Bahrami 	ARFILE		*fptr;
1055ba7866cdSAli Bahrami 	ARFILEP		*symlist = 0;
1056ba7866cdSAli Bahrami 	size_t		longnames;
1057ba7866cdSAli Bahrami 	size_t		nsyms;
1058ba7866cdSAli Bahrami 	int		new_archive = 0;
1059ba7866cdSAli Bahrami 	char		*name = cmd_info->arnam;
1060ba7866cdSAli Bahrami 	size_t		arsize;	/* Size of magic # and special members */
1061ba7866cdSAli Bahrami 	size_t		symtbl_eltsize = 4;
1062ba7866cdSAli Bahrami 	int		found_obj = 0;
1063ba7866cdSAli Bahrami 	int		fd;
1064ba7866cdSAli Bahrami 	off_t		off;
1065ba7866cdSAli Bahrami 	struct stat	stbuf, ar_stbuf;
1066ba7866cdSAli Bahrami 	char		pad_bytes[PADSZ];
1067ba7866cdSAli Bahrami 	size_t		pad_cnt;
1068ba7866cdSAli Bahrami 	int		is_elf;
1069ba7866cdSAli Bahrami 
1070ba7866cdSAli Bahrami 	/*
1071ba7866cdSAli Bahrami 	 * Gather the list of symbols and associate each one to the
1072ba7866cdSAli Bahrami 	 * ARFILE descriptor of the object it belongs to. At the same
1073ba7866cdSAli Bahrami 	 * time, tag each ELF object with the appropriate F_CLASSxx
1074ba7866cdSAli Bahrami 	 * flag.
1075ba7866cdSAli Bahrami 	 */
1076ba7866cdSAli Bahrami 	nsyms = mksymtab(name, &symlist, &found_obj);
1077ba7866cdSAli Bahrami 
1078ba7866cdSAli Bahrami 	/* Generate the string table for long member names */
1079ba7866cdSAli Bahrami 	longnames = mklong_tab();
1080ba7866cdSAli Bahrami 
1081ba7866cdSAli Bahrami 	/*
1082ba7866cdSAli Bahrami 	 * Will this archive exceed 4GB? If we're a 32-bit process, we can't
1083ba7866cdSAli Bahrami 	 * do it. If we're a 64-bit process, then we'll have to use a
1084ba7866cdSAli Bahrami 	 * 64-bit symbol table.
1085ba7866cdSAli Bahrami 	 */
1086ba7866cdSAli Bahrami 	if (require64(nsyms, found_obj, longnames)) {
1087ba7866cdSAli Bahrami #ifdef _LP64
1088ba7866cdSAli Bahrami 		symtbl_eltsize = 8;
1089ba7866cdSAli Bahrami #else
1090ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_TOOBIG4G));
1091ba7866cdSAli Bahrami 		exit(1);
1092ba7866cdSAli Bahrami #endif
1093ba7866cdSAli Bahrami 	}
1094ba7866cdSAli Bahrami 
1095ba7866cdSAli Bahrami 	/*
1096ba7866cdSAli Bahrami 	 * If the user requested it, use the 64-bit symbol table even if
1097ba7866cdSAli Bahrami 	 * a 32-bit one would suffice. 32-bit tables are more portable and
1098ba7866cdSAli Bahrami 	 * take up less room, so this feature is primarily for testing.
1099ba7866cdSAli Bahrami 	 */
1100ba7866cdSAli Bahrami 	if (cmd_info->opt_flgs & S_FLAG)
1101ba7866cdSAli Bahrami 		symtbl_eltsize = 8;
1102ba7866cdSAli Bahrami 
1103ba7866cdSAli Bahrami 	/*
1104ba7866cdSAli Bahrami 	 * If the first non-special archive member is an ELF object, then we
1105ba7866cdSAli Bahrami 	 * need to arrange for its data to have an alignment of PADSZ. The
1106ba7866cdSAli Bahrami 	 * preceeding special member will be the symbol table, or the long
1107ba7866cdSAli Bahrami 	 * name string table. We pad the string table that precedes the
1108ba7866cdSAli Bahrami 	 * ELF member in order to achive the desired alignment.
1109ba7866cdSAli Bahrami 	 */
1110ba7866cdSAli Bahrami 	is_elf = listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64));
1111ba7866cdSAli Bahrami 	arsize = SARMAG;
1112ba7866cdSAli Bahrami 	if (found_obj) {
1113ba7866cdSAli Bahrami 		arsize += sizeof_symtbl(nsyms, found_obj, symtbl_eltsize);
1114ba7866cdSAli Bahrami 		if (is_elf && (longnames == 0)) {
1115ba7866cdSAli Bahrami 			pad_cnt = pad(arsize + sizeof (struct ar_hdr), PADSZ);
1116ba7866cdSAli Bahrami 			strtbl_pad(&sym_strtbl, pad_cnt, '\0');
1117ba7866cdSAli Bahrami 			arsize += pad_cnt;
1118d2d5cf7cSAli Bahrami 		}
1119ba7866cdSAli Bahrami 	}
1120ba7866cdSAli Bahrami 	if (longnames > 0) {
1121ba7866cdSAli Bahrami 		arsize += sizeof (struct ar_hdr) + long_strtbl.used;
1122ba7866cdSAli Bahrami 		if (is_elf) {
1123ba7866cdSAli Bahrami 			pad_cnt = pad(arsize + sizeof (struct ar_hdr), PADSZ);
1124ba7866cdSAli Bahrami 			strtbl_pad(&long_strtbl, pad_cnt, '\0');
1125ba7866cdSAli Bahrami 			arsize += pad_cnt;
1126ba7866cdSAli Bahrami 		}
1127ba7866cdSAli Bahrami 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	/*
1130ba7866cdSAli Bahrami 	 * For each user visible (non-special) archive member, determine
1131ba7866cdSAli Bahrami 	 * the header offset, and the size of any required padding.
11327c478bd9Sstevel@tonic-gate 	 */
1133ba7866cdSAli Bahrami 	(void) sizeofmembers(arsize);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	/*
1136ba7866cdSAli Bahrami 	 * Is this a new archive, or are we updating an existing one?
1137ba7866cdSAli Bahrami 	 *
1138ba7866cdSAli Bahrami 	 * A subtlety here is that POSIX says we are not supposed
1139ba7866cdSAli Bahrami 	 * to replace a non-writable file. The only 100% reliable test
1140ba7866cdSAli Bahrami 	 * against this is to open the file for non-destructive
1141ba7866cdSAli Bahrami 	 * write access. If the open succeeds, we are clear to
1142ba7866cdSAli Bahrami 	 * replace it, and if not, then the error generated is
1143ba7866cdSAli Bahrami 	 * the error we need to report.
11447c478bd9Sstevel@tonic-gate 	 */
1145ba7866cdSAli Bahrami 	if ((fd = open(name, O_RDWR)) < 0) {
1146ba7866cdSAli Bahrami 		int	err = errno;
11477c478bd9Sstevel@tonic-gate 
1148ba7866cdSAli Bahrami 		if (err != ENOENT) {
1149ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1150ba7866cdSAli Bahrami 			    name, strerror(err));
1151ba7866cdSAli Bahrami 			exit(1);
1152ba7866cdSAli Bahrami 		}
1153ba7866cdSAli Bahrami 		new_archive = 1;
1154ba7866cdSAli Bahrami 		if ((cmd_info->opt_flgs & c_FLAG) == 0) {
1155ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_BER_MES_CREATE),
1156ba7866cdSAli Bahrami 			    cmd_info->arnam);
1157ba7866cdSAli Bahrami 		}
11587c478bd9Sstevel@tonic-gate 	} else {
1159ba7866cdSAli Bahrami 		/* Capture mode and owner information to apply to replacement */
1160ba7866cdSAli Bahrami 		if (fstat(fd, &ar_stbuf) < 0) {
1161ba7866cdSAli Bahrami 			int err = errno;
1162ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_STAT),
1163ba7866cdSAli Bahrami 			    name, strerror(err));
1164ba7866cdSAli Bahrami 			(void) close(fd);
1165ba7866cdSAli Bahrami 			exit(1);
1166ba7866cdSAli Bahrami 		}
1167ba7866cdSAli Bahrami 		(void) close(fd);
1168ba7866cdSAli Bahrami 		new_archive = 0;
11697c478bd9Sstevel@tonic-gate 	}
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 
1172ba7866cdSAli Bahrami 	/*
1173ba7866cdSAli Bahrami 	 * Register exit handler function to clean up after us if we exit
1174ba7866cdSAli Bahrami 	 * before completing the new archive. atexit() is defined as
1175ba7866cdSAli Bahrami 	 * only being able to fail due to memory exhaustion.
1176ba7866cdSAli Bahrami 	 */
1177ba7866cdSAli Bahrami 	if (atexit(exit_cleanup) != 0) {
1178ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(ENOMEM));
1179ba7866cdSAli Bahrami 		exit(1);
1180ba7866cdSAli Bahrami 	}
1181ba7866cdSAli Bahrami 
1182ba7866cdSAli Bahrami 	/*
1183ba7866cdSAli Bahrami 	 * If a new archive, create it in place. If updating an archive,
1184ba7866cdSAli Bahrami 	 * create the replacement under a temporary name and then rename it
1185ba7866cdSAli Bahrami 	 * into place.
1186ba7866cdSAli Bahrami 	 */
1187ba7866cdSAli Bahrami 	ar_outfile.path = new_archive ? name : make_tmpname(name);
1188ba7866cdSAli Bahrami 	ar_outfile.fd = open(ar_outfile.path, O_RDWR|O_CREAT|O_LARGEFILE, 0666);
1189ba7866cdSAli Bahrami 	if (ar_outfile.fd == -1) {
1190ba7866cdSAli Bahrami 		int err = errno;
1191*11029d9dSRobert Mustacchi 		(void) fprintf(stderr, new_archive ?
1192*11029d9dSRobert Mustacchi 		    MSG_INTL(MSG_BAD_CREATE) : MSG_INTL(MSG_SYS_OPEN),
1193ba7866cdSAli Bahrami 		    ar_outfile.path, strerror(err));
1194ba7866cdSAli Bahrami 		exit(1);
11957c478bd9Sstevel@tonic-gate 	}
11967c478bd9Sstevel@tonic-gate 
1197ba7866cdSAli Bahrami 	/* Output magic string */
1198ba7866cdSAli Bahrami 	arwrite(name, ar_outfile.fd, ARMAG, SARMAG);
1199ba7866cdSAli Bahrami 
1200ba7866cdSAli Bahrami 	/*
1201ba7866cdSAli Bahrami 	 * The symbol table member is always first if present. Note that
1202ba7866cdSAli Bahrami 	 * writesymtab() uses the member offsets computed by sizeofmembers()
1203ba7866cdSAli Bahrami 	 * above.
1204ba7866cdSAli Bahrami 	 */
1205ba7866cdSAli Bahrami 	if (found_obj)
1206ba7866cdSAli Bahrami 		writesymtab(name, ar_outfile.fd, nsyms, symlist,
1207ba7866cdSAli Bahrami 		    symtbl_eltsize);
1208ba7866cdSAli Bahrami 
12097c478bd9Sstevel@tonic-gate 	if (longnames) {
1210ba7866cdSAli Bahrami 		write_member_header(name, ar_outfile.fd, 0,
1211ba7866cdSAli Bahrami 		    MSG_ORIG(MSG_STR_DSLASH), time(0), 0, 0, 0,
1212ba7866cdSAli Bahrami 		    long_strtbl.used);
1213ba7866cdSAli Bahrami 		arwrite(name, ar_outfile.fd, long_strtbl.base,
1214ba7866cdSAli Bahrami 		    long_strtbl.used);
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	/*
1218ba7866cdSAli Bahrami 	 * The accuracy of the symbol table depends on our having calculated
1219ba7866cdSAli Bahrami 	 * the size of the archive accurately to this point. If this is a
1220ba7866cdSAli Bahrami 	 * debug build, verify it.
12217c478bd9Sstevel@tonic-gate 	 */
1222ba7866cdSAli Bahrami 	assert(arsize == lseek(ar_outfile.fd, 0, SEEK_CUR));
1223ba7866cdSAli Bahrami 
1224ba7866cdSAli Bahrami #ifndef XPG4
1225ba7866cdSAli Bahrami 	if (cmd_info->opt_flgs & v_FLAG) {
1226ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_BER_MES_WRITE),
1227ba7866cdSAli Bahrami 		    cmd_info->arnam);
1228ba7866cdSAli Bahrami 	}
1229ba7866cdSAli Bahrami #endif
1230ba7866cdSAli Bahrami 
1231ba7866cdSAli Bahrami 	/*
1232ba7866cdSAli Bahrami 	 * Fill pad_bytes array with newline characters. This array
1233ba7866cdSAli Bahrami 	 * is used to supply padding bytes at the end of ELF objects.
1234ba7866cdSAli Bahrami 	 * There can never be more tha PADSZ such bytes, so this number
1235ba7866cdSAli Bahrami 	 * will always suffice.
1236ba7866cdSAli Bahrami 	 */
1237ba7866cdSAli Bahrami 	for (pad_cnt = 0; pad_cnt < PADSZ; pad_cnt++)
1238ba7866cdSAli Bahrami 		pad_bytes[pad_cnt] = '\n';
1239ba7866cdSAli Bahrami 
1240ba7866cdSAli Bahrami 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
1241ba7866cdSAli Bahrami 		/*
1242ba7866cdSAli Bahrami 		 * We computed the expected offset for each ELF member and
1243ba7866cdSAli Bahrami 		 * used those offsets to fill the symbol table. If this is
1244ba7866cdSAli Bahrami 		 * a debug build, verify that the computed offset was right.
1245ba7866cdSAli Bahrami 		 */
1246ba7866cdSAli Bahrami 		is_elf = (fptr->ar_flag & (F_CLASS32 | F_CLASS64)) != 0;
1247ba7866cdSAli Bahrami 		assert(!is_elf ||
1248ba7866cdSAli Bahrami 		    (fptr->ar_offset == lseek(ar_outfile.fd, 0, SEEK_CUR)));
1249ba7866cdSAli Bahrami 
1250ba7866cdSAli Bahrami 		/*
1251ba7866cdSAli Bahrami 		 * NOTE:
1252ba7866cdSAli Bahrami 		 * The mem_header->ar_name[] is set to a NULL string
1253ba7866cdSAli Bahrami 		 * if the archive member header has some error.
1254ba7866cdSAli Bahrami 		 * (See elf_getarhdr() man page.)
1255ba7866cdSAli Bahrami 		 * It is set to NULL for example, the ar command reads
1256ba7866cdSAli Bahrami 		 * the archive files created by SunOS 4.1 system.
1257ba7866cdSAli Bahrami 		 * See c block comment in cmd.c, "Incompatible Archive Header".
1258ba7866cdSAli Bahrami 		 */
12597c478bd9Sstevel@tonic-gate 		if (fptr->ar_name[0] == 0) {
12607c478bd9Sstevel@tonic-gate 			fptr->ar_longname = fptr->ar_rawname;
12617c478bd9Sstevel@tonic-gate 			(void) strncpy(fptr->ar_name, fptr->ar_rawname, SNAME);
12627c478bd9Sstevel@tonic-gate 		}
1263ba7866cdSAli Bahrami 		write_member_header(name, ar_outfile.fd, is_elf,
1264ba7866cdSAli Bahrami 		    (strlen(fptr->ar_longname) <= (unsigned)SNAME-2) ?
1265ba7866cdSAli Bahrami 		    trimslash(fptr->ar_longname) : fptr->ar_name,
1266ba7866cdSAli Bahrami 		    EC_WORD(fptr->ar_date), fptr->ar_uid, fptr->ar_gid,
1267ba7866cdSAli Bahrami 		    fptr->ar_mode, fptr->ar_size + fptr->ar_padding);
1268ba7866cdSAli Bahrami 
1269ba7866cdSAli Bahrami 
1270ba7866cdSAli Bahrami 		if ((fptr->ar_flag & F_ELFRAW) == 0) {
1271ba7866cdSAli Bahrami 			/*
1272ba7866cdSAli Bahrami 			 * The file doesn't come from the archive, and is
1273ba7866cdSAli Bahrami 			 * therefore not already in memory(fptr->ar_contents)
1274ba7866cdSAli Bahrami 			 * so open it and do a direct file-to-file transfer of
1275ba7866cdSAli Bahrami 			 * its contents. We use the sendfile() system call
1276ba7866cdSAli Bahrami 			 * to make the kernel do the transfer, so we don't have
1277ba7866cdSAli Bahrami 			 * to buffer data in process, and we trust that the
1278ba7866cdSAli Bahrami 			 * kernel will use an optimal transfer strategy.
1279ba7866cdSAli Bahrami 			 */
1280ba7866cdSAli Bahrami 			if ((fd = open(fptr->ar_pathname, O_RDONLY)) == -1) {
1281ba7866cdSAli Bahrami 				int err = errno;
1282ba7866cdSAli Bahrami 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1283ba7866cdSAli Bahrami 				    fptr->ar_longname, strerror(err));
1284ba7866cdSAli Bahrami 				exit(1);
1285ba7866cdSAli Bahrami 			}
1286ba7866cdSAli Bahrami 			if (stat(fptr->ar_pathname, &stbuf) < 0) {
1287ba7866cdSAli Bahrami 				int err = errno;
1288ba7866cdSAli Bahrami 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
1289ba7866cdSAli Bahrami 				    fptr->ar_longname, strerror(err));
1290ba7866cdSAli Bahrami 				(void) close(fd);
12917c478bd9Sstevel@tonic-gate 				exit(1);
12927c478bd9Sstevel@tonic-gate 			}
1293ba7866cdSAli Bahrami 			off = 0;
1294ba7866cdSAli Bahrami 			if (sendfile(ar_outfile.fd, fd, &off,
1295ba7866cdSAli Bahrami 			    stbuf.st_size) != stbuf.st_size) {
1296ba7866cdSAli Bahrami 				int err = errno;
1297ba7866cdSAli Bahrami 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
1298ba7866cdSAli Bahrami 				    name, strerror(err));
1299ba7866cdSAli Bahrami 				exit(2);
1300ba7866cdSAli Bahrami 			}
1301ba7866cdSAli Bahrami 			(void) close(fd);
13027c478bd9Sstevel@tonic-gate 		} else {
1303ba7866cdSAli Bahrami 			/* Archive member is in memory. Write it out */
1304ba7866cdSAli Bahrami 			arwrite(name, ar_outfile.fd, fptr->ar_contents,
1305d2d5cf7cSAli Bahrami 			    fptr->ar_size);
13067c478bd9Sstevel@tonic-gate 		}
13077c478bd9Sstevel@tonic-gate 
1308ba7866cdSAli Bahrami 		/*
1309ba7866cdSAli Bahrami 		 * All archive members are padded to at least a boundary of 2.
1310ba7866cdSAli Bahrami 		 * The expression ((fptr->ar_size & 0x1) != 0) yields 1 for
1311ba7866cdSAli Bahrami 		 * odd boundaries, and 0 for even ones. To this, we add
1312ba7866cdSAli Bahrami 		 * whatever padding is needed for ELF objects.
1313ba7866cdSAli Bahrami 		 */
1314ba7866cdSAli Bahrami 		pad_cnt = ((fptr->ar_size & 0x1) != 0) + fptr->ar_padding;
1315ba7866cdSAli Bahrami 		if (pad_cnt > 0)
1316ba7866cdSAli Bahrami 			arwrite(name, ar_outfile.fd, pad_bytes, pad_cnt);
13177c478bd9Sstevel@tonic-gate 	}
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	/*
1320ba7866cdSAli Bahrami 	 * All archive output is done.
13217c478bd9Sstevel@tonic-gate 	 */
1322ba7866cdSAli Bahrami 	if (close(ar_outfile.fd) < 0) {
1323ba7866cdSAli Bahrami 		int err = errno;
1324ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_CLOSE), ar_outfile.path,
1325ba7866cdSAli Bahrami 		    strerror(err));
1326ba7866cdSAli Bahrami 		exit(1);
1327ba7866cdSAli Bahrami 	}
1328ba7866cdSAli Bahrami 	ar_outfile.fd = -1;	/* Prevent removal on exit */
13297c478bd9Sstevel@tonic-gate 	(void) elf_end(cmd_info->arf);
13307c478bd9Sstevel@tonic-gate 	(void) close(cmd_info->afd);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	/*
1333ba7866cdSAli Bahrami 	 * If updating an existing archive, rename the new version on
1334ba7866cdSAli Bahrami 	 * top of the original.
13357c478bd9Sstevel@tonic-gate 	 */
1336ba7866cdSAli Bahrami 	if (!new_archive) {
13377c478bd9Sstevel@tonic-gate 		/*
1338ba7866cdSAli Bahrami 		 * Prevent the replacement of the original archive from
1339ba7866cdSAli Bahrami 		 * being interrupted, to lower the possibility of an
1340ba7866cdSAli Bahrami 		 * interrupt destroying a pre-existing archive.
13417c478bd9Sstevel@tonic-gate 		 */
1342ba7866cdSAli Bahrami 		establish_sighandler(SIG_IGN);
1343ba7866cdSAli Bahrami 
1344ba7866cdSAli Bahrami 		if (rename(ar_outfile.path, name) < 0) {
1345ba7866cdSAli Bahrami 			int err = errno;
1346ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_RENAME),
1347ba7866cdSAli Bahrami 			    ar_outfile.path, name, strerror(err));
1348ba7866cdSAli Bahrami 			(void) unlink(ar_outfile.path);
13497c478bd9Sstevel@tonic-gate 			exit(1);
13507c478bd9Sstevel@tonic-gate 		}
1351ba7866cdSAli Bahrami 		(void) chmod(name, ar_stbuf.st_mode & 0777);
1352ba7866cdSAli Bahrami 		if (chown(name, ar_stbuf.st_uid, ar_stbuf.st_gid) >= 0)
1353ba7866cdSAli Bahrami 			(void) chmod(name, ar_stbuf.st_mode & 07777);
1354ba7866cdSAli Bahrami 
13557c478bd9Sstevel@tonic-gate 	}
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate 
1358ba7866cdSAli Bahrami /*
1359ba7866cdSAli Bahrami  * Examine all the archive members, enter any member names longer than
1360ba7866cdSAli Bahrami  * 15 characters into the long name string table, and count the number
1361ba7866cdSAli Bahrami  * of names found.
1362ba7866cdSAli Bahrami  *
1363ba7866cdSAli Bahrami  * Returns the size of the resulting archive member, including the
1364ba7866cdSAli Bahrami  * member header.
1365ba7866cdSAli Bahrami  */
1366ba7866cdSAli Bahrami static size_t
mklong_tab(void)1367ba7866cdSAli Bahrami mklong_tab(void)
13687c478bd9Sstevel@tonic-gate {
13697c478bd9Sstevel@tonic-gate 	ARFILE  *fptr;
1370ba7866cdSAli Bahrami 	size_t longnames = 0;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
13737c478bd9Sstevel@tonic-gate 		if (strlen(fptr->ar_longname) >= (unsigned)SNAME-1) {
1374ba7866cdSAli Bahrami 			longnames++;
1375ba7866cdSAli Bahrami 			savelongname(fptr);
13767c478bd9Sstevel@tonic-gate 		}
13777c478bd9Sstevel@tonic-gate 	}
1378ba7866cdSAli Bahrami 
1379ba7866cdSAli Bahrami 	/* round up table that keeps the long filenames */
1380ba7866cdSAli Bahrami 	if (longnames > 0)
1381ba7866cdSAli Bahrami 		strtbl_pad(&long_strtbl, pad(long_strtbl.used, 4), '\n');
1382ba7866cdSAli Bahrami 
1383ba7866cdSAli Bahrami 	return (longnames);
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate 
1386ba7866cdSAli Bahrami /*
1387ba7866cdSAli Bahrami  * Write 32/64-bit words into buffer in archive symbol table
1388ba7866cdSAli Bahrami  * standard byte order (MSB).
1389ba7866cdSAli Bahrami  */
1390ba7866cdSAli Bahrami static char *
sputl32(uint32_t n,char * cp)1391ba7866cdSAli Bahrami sputl32(uint32_t n, char *cp)
1392ba7866cdSAli Bahrami {
1393ba7866cdSAli Bahrami 	*cp++ = n >> 24;
1394ba7866cdSAli Bahrami 	*cp++ = n >> 16;
1395ba7866cdSAli Bahrami 	*cp++ = n >> 8;
13967c478bd9Sstevel@tonic-gate 
1397ba7866cdSAli Bahrami 	*cp++ = n & 255;
1398ba7866cdSAli Bahrami 
1399ba7866cdSAli Bahrami 	return (cp);
1400ba7866cdSAli Bahrami }
1401ba7866cdSAli Bahrami 
1402ba7866cdSAli Bahrami static char *
sputl64(uint64_t n,char * cp)1403ba7866cdSAli Bahrami sputl64(uint64_t n, char *cp)
14047c478bd9Sstevel@tonic-gate {
1405ba7866cdSAli Bahrami 	*cp++ = n >> 56;
1406ba7866cdSAli Bahrami 	*cp++ = n >> 48;
1407ba7866cdSAli Bahrami 	*cp++ = n >> 40;
1408ba7866cdSAli Bahrami 	*cp++ = n >> 32;
1409ba7866cdSAli Bahrami 
14107c478bd9Sstevel@tonic-gate 	*cp++ = n >> 24;
14117c478bd9Sstevel@tonic-gate 	*cp++ = n >> 16;
14127c478bd9Sstevel@tonic-gate 	*cp++ = n >> 8;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	*cp++ = n & 255;
1415ba7866cdSAli Bahrami 
1416ba7866cdSAli Bahrami 	return (cp);
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate static int
search_sym_tab(const char * arname,ARFILE * fptr,Elf * elf,Elf_Scn * scn,size_t * nsyms,ARFILEP ** symlist,size_t * num_errs)1420ba7866cdSAli Bahrami search_sym_tab(const char *arname, ARFILE *fptr, Elf *elf, Elf_Scn *scn,
1421fb25420bSRobert Mustacchi     size_t *nsyms, ARFILEP **symlist, size_t *num_errs)
14227c478bd9Sstevel@tonic-gate {
14237c478bd9Sstevel@tonic-gate 	Elf_Data *str_data, *sym_data; /* string table, symbol table */
14247c478bd9Sstevel@tonic-gate 	Elf_Scn *str_scn;
14257c478bd9Sstevel@tonic-gate 	GElf_Sxword no_of_symbols;
14267c478bd9Sstevel@tonic-gate 	GElf_Shdr shdr;
14277c478bd9Sstevel@tonic-gate 	int counter;
14287c478bd9Sstevel@tonic-gate 	int str_shtype;
14297c478bd9Sstevel@tonic-gate 	char *symname;
14307c478bd9Sstevel@tonic-gate 	static ARFILEP *sym_ptr = 0;
14317c478bd9Sstevel@tonic-gate 	static ARFILEP *nextsym = NULL;
14327c478bd9Sstevel@tonic-gate 	static int syms_left = 0;
14337c478bd9Sstevel@tonic-gate 	char *fname = fptr->ar_pathname;
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	(void) gelf_getshdr(scn, &shdr);
14367c478bd9Sstevel@tonic-gate 	str_scn = elf_getscn(elf, shdr.sh_link); /* index for string table */
14377c478bd9Sstevel@tonic-gate 	if (str_scn == NULL) {
14387c478bd9Sstevel@tonic-gate 		if (fname != NULL)
1439ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_FILE),
1440ba7866cdSAli Bahrami 			    fname, elf_errmsg(-1));
14417c478bd9Sstevel@tonic-gate 		else
1442ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_AR),
1443ba7866cdSAli Bahrami 			    arname, fptr->ar_longname, elf_errmsg(-1));
14447c478bd9Sstevel@tonic-gate 		(*num_errs)++;
14457c478bd9Sstevel@tonic-gate 		return (-1);
14467c478bd9Sstevel@tonic-gate 	}
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	no_of_symbols = shdr.sh_size / shdr.sh_entsize;
14497c478bd9Sstevel@tonic-gate 	if (no_of_symbols == -1) {
1450ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_01));
14517c478bd9Sstevel@tonic-gate 		return (-1);
14527c478bd9Sstevel@tonic-gate 	}
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	(void) gelf_getshdr(str_scn, &shdr);
14557c478bd9Sstevel@tonic-gate 	str_shtype = shdr.sh_type;
14567c478bd9Sstevel@tonic-gate 	if (str_shtype == -1) {
14577c478bd9Sstevel@tonic-gate 		if (fname != NULL)
1458ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_FILE),
1459ba7866cdSAli Bahrami 			    fname, elf_errmsg(-1));
14607c478bd9Sstevel@tonic-gate 		else
1461ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_GETDATA_AR),
1462ba7866cdSAli Bahrami 			    arname, fptr->ar_longname, elf_errmsg(-1));
14637c478bd9Sstevel@tonic-gate 		(*num_errs)++;
14647c478bd9Sstevel@tonic-gate 		return (-1);
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	/* This test must happen before testing the string table. */
14687c478bd9Sstevel@tonic-gate 	if (no_of_symbols == 1)
14697c478bd9Sstevel@tonic-gate 		return (0);	/* no symbols; 0th symbol is the non-symbol */
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	if (str_shtype != SHT_STRTAB) {
14727c478bd9Sstevel@tonic-gate 		if (fname != NULL)
1473ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NOSTR_FILE),
1474d2d5cf7cSAli Bahrami 			    fname);
14757c478bd9Sstevel@tonic-gate 		else
1476ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NOSTR_AR),
1477ba7866cdSAli Bahrami 			    arname, fptr->ar_longname);
14787c478bd9Sstevel@tonic-gate 		return (0);
14797c478bd9Sstevel@tonic-gate 	}
14807c478bd9Sstevel@tonic-gate 	str_data = 0;
14817c478bd9Sstevel@tonic-gate 	if ((str_data = elf_getdata(str_scn, str_data)) == 0) {
14827c478bd9Sstevel@tonic-gate 		if (fname != NULL)
1483ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NODAT_FILE),
1484d2d5cf7cSAli Bahrami 			    fname);
14857c478bd9Sstevel@tonic-gate 		else
1486ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_NODAT_AR),
1487ba7866cdSAli Bahrami 			    arname, fptr->ar_longname);
14887c478bd9Sstevel@tonic-gate 		return (0);
14897c478bd9Sstevel@tonic-gate 	}
14907c478bd9Sstevel@tonic-gate 	if (str_data->d_size == 0) {
14917c478bd9Sstevel@tonic-gate 		if (fname != NULL)
1492ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_ZDAT_FILE),
1493d2d5cf7cSAli Bahrami 			    fname);
14947c478bd9Sstevel@tonic-gate 		else
1495ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_SYMTAB_ZDAT_AR),
1496ba7866cdSAli Bahrami 			    arname, fptr->ar_longname);
14977c478bd9Sstevel@tonic-gate 		return (0);
14987c478bd9Sstevel@tonic-gate 	}
14997c478bd9Sstevel@tonic-gate 	sym_data = 0;
15007c478bd9Sstevel@tonic-gate 	if ((sym_data = elf_getdata(scn, sym_data)) == NULL) {
15017c478bd9Sstevel@tonic-gate 		if (fname != NULL)
1502ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIB_FILE),
1503d2d5cf7cSAli Bahrami 			    fname, elf_errmsg(-1));
15047c478bd9Sstevel@tonic-gate 		else
1505ba7866cdSAli Bahrami 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_LIB_AR),
1506ba7866cdSAli Bahrami 			    arname, fptr->ar_longname, elf_errmsg(-1));
15077c478bd9Sstevel@tonic-gate 		return (0);
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	/* start at 1, first symbol entry is ignored */
15117c478bd9Sstevel@tonic-gate 	for (counter = 1; counter < no_of_symbols; counter++) {
15127c478bd9Sstevel@tonic-gate 		GElf_Sym sym;
15137c478bd9Sstevel@tonic-gate 		(void) gelf_getsym(sym_data, counter, &sym);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 		symname = (char *)(str_data->d_buf) + sym.st_name;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		if (((GELF_ST_BIND(sym.st_info) == STB_GLOBAL) ||
1518d2d5cf7cSAli Bahrami 		    (GELF_ST_BIND(sym.st_info) == STB_WEAK)) &&
1519d2d5cf7cSAli Bahrami 		    (sym.st_shndx != SHN_UNDEF)) {
15207c478bd9Sstevel@tonic-gate 			if (!syms_left) {
15217c478bd9Sstevel@tonic-gate 				sym_ptr = malloc((SYMCHUNK+1)
1522d2d5cf7cSAli Bahrami 				    * sizeof (ARFILEP));
15237c478bd9Sstevel@tonic-gate 				if (sym_ptr == NULL) {
1524ba7866cdSAli Bahrami 					int err = errno;
1525ba7866cdSAli Bahrami 					(void) fprintf(stderr,
1526ba7866cdSAli Bahrami 					    MSG_INTL(MSG_MALLOC),
1527ba7866cdSAli Bahrami 					    strerror(err));
15287c478bd9Sstevel@tonic-gate 					exit(1);
15297c478bd9Sstevel@tonic-gate 				}
15307c478bd9Sstevel@tonic-gate 				syms_left = SYMCHUNK;
15317c478bd9Sstevel@tonic-gate 				if (nextsym)
15327c478bd9Sstevel@tonic-gate 					*nextsym = (ARFILEP)sym_ptr;
15337c478bd9Sstevel@tonic-gate 				else
15347c478bd9Sstevel@tonic-gate 					*symlist = sym_ptr;
15357c478bd9Sstevel@tonic-gate 				nextsym = sym_ptr;
15367c478bd9Sstevel@tonic-gate 			}
15377c478bd9Sstevel@tonic-gate 			sym_ptr = nextsym;
15387c478bd9Sstevel@tonic-gate 			nextsym++;
15397c478bd9Sstevel@tonic-gate 			syms_left--;
15407c478bd9Sstevel@tonic-gate 			(*nsyms)++;
15417c478bd9Sstevel@tonic-gate 			*sym_ptr = fptr;
15427c478bd9Sstevel@tonic-gate 			savename(symname);	/* put name in the archiver's */
15437c478bd9Sstevel@tonic-gate 						/* symbol table string table */
15447c478bd9Sstevel@tonic-gate 		}
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate 	return (0);
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate /*
15507c478bd9Sstevel@tonic-gate  * Get the output file size
15517c478bd9Sstevel@tonic-gate  */
1552ba7866cdSAli Bahrami static size_t
sizeofmembers(size_t psum)1553ba7866cdSAli Bahrami sizeofmembers(size_t psum)
15547c478bd9Sstevel@tonic-gate {
1555ba7866cdSAli Bahrami 	size_t	sum = 0;
1556ba7866cdSAli Bahrami 	ARFILE	*fptr;
1557ba7866cdSAli Bahrami 	size_t	hdrsize = sizeof (struct ar_hdr);
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	for (fptr = listhead; fptr; fptr = fptr->ar_next) {
15607c478bd9Sstevel@tonic-gate 		fptr->ar_offset = psum + sum;
15617c478bd9Sstevel@tonic-gate 		sum += fptr->ar_size;
15627c478bd9Sstevel@tonic-gate 		if (fptr->ar_size & 01)
15637c478bd9Sstevel@tonic-gate 			sum++;
15647c478bd9Sstevel@tonic-gate 		sum += hdrsize;
15657c478bd9Sstevel@tonic-gate 
156660fc76daSab 		/*
156760fc76daSab 		 * If the current item, and the next item are both ELF
156860fc76daSab 		 * objects, then add padding to current item so that the
1569ba7866cdSAli Bahrami 		 * data in the next item will have PADSZ alignment.
157060fc76daSab 		 *
157160fc76daSab 		 * In any other case, set the padding to 0. If the
157260fc76daSab 		 * item comes from another archive, it may be carrying
157360fc76daSab 		 * a non-zero padding value from that archive that does
157460fc76daSab 		 * not apply to the one we are about to build.
157560fc76daSab 		 */
15767c478bd9Sstevel@tonic-gate 		if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) &&
15779d6538abSab 		    fptr->ar_next &&
15789d6538abSab 		    (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) {
1579ba7866cdSAli Bahrami 			fptr->ar_padding = pad(psum + sum + hdrsize, PADSZ);
15809d6538abSab 			sum += fptr->ar_padding;
158160fc76daSab 		} else {
158260fc76daSab 			fptr->ar_padding = 0;
15837c478bd9Sstevel@tonic-gate 		}
15847c478bd9Sstevel@tonic-gate 	}
15857c478bd9Sstevel@tonic-gate 	return (sum);
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate 
1588ba7866cdSAli Bahrami /*
1589ba7866cdSAli Bahrami  * Compute the size of the symbol table archive member.
1590ba7866cdSAli Bahrami  *
1591ba7866cdSAli Bahrami  * entry:
1592ba7866cdSAli Bahrami  *	nsyms - # of symbols in the table
1593ba7866cdSAli Bahrami  *	found_obj - TRUE if the archive contains any ELF objects
1594ba7866cdSAli Bahrami  *	eltsize - Size of the integer type to use for the symbol
1595ba7866cdSAli Bahrami  *		table. 4 for 32-bit tables, and 8 for 64-bit tables.
1596ba7866cdSAli Bahrami  */
1597ba7866cdSAli Bahrami static size_t
sizeof_symtbl(size_t nsyms,int found_obj,size_t eltsize)1598ba7866cdSAli Bahrami sizeof_symtbl(size_t nsyms, int found_obj, size_t eltsize)
15997c478bd9Sstevel@tonic-gate {
1600ba7866cdSAli Bahrami 	size_t sum = 0;
16017c478bd9Sstevel@tonic-gate 
1602ba7866cdSAli Bahrami 	if (found_obj) {
1603ba7866cdSAli Bahrami 		/* Member header, symbol count, and one slot per symbol */
1604ba7866cdSAli Bahrami 		sum += sizeof (struct ar_hdr) + ((nsyms + 1) * eltsize);
1605ba7866cdSAli Bahrami 		sum += sym_strtbl.used;
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	return (sum);
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate static void
arwrite(const char * name,int nfd,const char * dst,size_t size)1612fb25420bSRobert Mustacchi arwrite(const char *name, int nfd, const char *dst, size_t size)
1613fb25420bSRobert Mustacchi {
16147c478bd9Sstevel@tonic-gate 	if (write(nfd, dst, size) != size) {
1615ba7866cdSAli Bahrami 		int err = errno;
1616ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
1617ba7866cdSAli Bahrami 		    name, strerror(err));
16187c478bd9Sstevel@tonic-gate 		exit(2);
16197c478bd9Sstevel@tonic-gate 	}
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate 
1622ba7866cdSAli Bahrami static const char *
make_tmpname(const char * filename)1623fb25420bSRobert Mustacchi make_tmpname(const char *filename)
1624fb25420bSRobert Mustacchi {
1625ba7866cdSAli Bahrami 	char	*slash, *tmpname;
1626ba7866cdSAli Bahrami 	size_t	prefix_cnt = 0;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	/*
1629ba7866cdSAli Bahrami 	 * If there is a path prefix in front of the filename, we
1630ba7866cdSAli Bahrami 	 * want to put the temporary file in the same directory.
1631ba7866cdSAli Bahrami 	 * Determine the length of the path.
16327c478bd9Sstevel@tonic-gate 	 */
1633ba7866cdSAli Bahrami 	slash = strrchr(filename, '/');
1634ba7866cdSAli Bahrami 	if (slash != NULL)
1635ba7866cdSAli Bahrami 		prefix_cnt = slash - filename + 1;
1636ba7866cdSAli Bahrami 	tmpname = malloc(prefix_cnt + MSG_STR_MKTEMP_SIZE + 1);
1637ba7866cdSAli Bahrami 	if (tmpname == NULL) {
1638ba7866cdSAli Bahrami 		int err = errno;
1639ba7866cdSAli Bahrami 		(void) fprintf(stderr, MSG_INTL(MSG_MALLOC), strerror(err));
1640ba7866cdSAli Bahrami 		exit(1);
16417c478bd9Sstevel@tonic-gate 	}
16427c478bd9Sstevel@tonic-gate 
1643ba7866cdSAli Bahrami 	if (prefix_cnt > 0)
1644ba7866cdSAli Bahrami 		(void) strncpy(tmpname, filename, prefix_cnt);
1645ba7866cdSAli Bahrami 	(void) strcpy(tmpname + prefix_cnt, MSG_ORIG(MSG_STR_MKTEMP));
1646ba7866cdSAli Bahrami 	(void) mktemp(tmpname);
1647ba7866cdSAli Bahrami 
1648ba7866cdSAli Bahrami 	return (tmpname);
16497c478bd9Sstevel@tonic-gate }
1650