Lines 1-952
Link Here
|
1 |
/*- |
1 |
/*- |
2 |
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
2 |
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
3 |
* |
3 |
* |
4 |
* Copyright (c) 2007 Kai Wang |
4 |
* Copyright (c) 2007 Kai Wang |
5 |
* All rights reserved. |
5 |
* All rights reserved. |
6 |
* |
6 |
* |
7 |
* Redistribution and use in source and binary forms, with or without |
7 |
* Redistribution and use in source and binary forms, with or without |
8 |
* modification, are permitted provided that the following conditions |
8 |
* modification, are permitted provided that the following conditions |
9 |
* are met: |
9 |
* are met: |
10 |
* 1. Redistributions of source code must retain the above copyright |
10 |
* 1. Redistributions of source code must retain the above copyright |
11 |
* notice, this list of conditions and the following disclaimer. |
11 |
* notice, this list of conditions and the following disclaimer. |
12 |
* 2. Redistributions in binary form must reproduce the above copyright |
12 |
* 2. Redistributions in binary form must reproduce the above copyright |
13 |
* notice, this list of conditions and the following disclaimer in the |
13 |
* notice, this list of conditions and the following disclaimer in the |
14 |
* documentation and/or other materials provided with the distribution. |
14 |
* documentation and/or other materials provided with the distribution. |
15 |
* |
15 |
* |
16 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 |
* SUCH DAMAGE. |
26 |
* SUCH DAMAGE. |
27 |
*/ |
27 |
*/ |
28 |
|
28 |
|
29 |
#include <sys/cdefs.h> |
29 |
#include <sys/cdefs.h> |
30 |
__FBSDID("$FreeBSD$"); |
30 |
__FBSDID("$FreeBSD$"); |
31 |
|
31 |
|
32 |
#include <sys/endian.h> |
32 |
#include <sys/endian.h> |
33 |
#include <sys/mman.h> |
33 |
#include <sys/mman.h> |
34 |
#include <sys/queue.h> |
34 |
#include <sys/queue.h> |
35 |
#include <sys/stat.h> |
35 |
#include <sys/stat.h> |
36 |
#include <archive.h> |
36 |
#include <archive.h> |
37 |
#include <archive_entry.h> |
37 |
#include <archive_entry.h> |
38 |
#include <errno.h> |
38 |
#include <errno.h> |
39 |
#include <fcntl.h> |
39 |
#include <fcntl.h> |
40 |
#include <gelf.h> |
40 |
#include <gelf.h> |
41 |
#include <libgen.h> |
41 |
#include <libgen.h> |
42 |
#include <stdio.h> |
42 |
#include <stdio.h> |
43 |
#include <stdlib.h> |
43 |
#include <stdlib.h> |
44 |
#include <string.h> |
44 |
#include <string.h> |
45 |
#include <sysexits.h> |
45 |
#include <sysexits.h> |
46 |
#include <unistd.h> |
46 |
#include <unistd.h> |
47 |
|
47 |
|
48 |
#include "ar.h" |
48 |
#include "ar.h" |
49 |
|
49 |
|
50 |
#define _ARMAG_LEN 8 /* length of ar magic string */ |
50 |
#define _ARMAG_LEN 8 /* length of ar magic string */ |
51 |
#define _ARHDR_LEN 60 /* length of ar header */ |
51 |
#define _ARHDR_LEN 60 /* length of ar header */ |
52 |
#define _INIT_AS_CAP 128 /* initial archive string table size */ |
52 |
#define _INIT_AS_CAP 128 /* initial archive string table size */ |
53 |
#define _INIT_SYMOFF_CAP (256*(sizeof(uint64_t))) /* initial so table size */ |
53 |
#define _INIT_SYMOFF_CAP (256*(sizeof(uint64_t))) /* initial so table size */ |
54 |
#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ |
54 |
#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ |
55 |
#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ |
55 |
#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ |
56 |
#define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */ |
56 |
#define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */ |
57 |
|
57 |
|
58 |
static void add_to_ar_str_table(struct bsdar *bsdar, const char *name); |
58 |
static void add_to_ar_str_table(struct bsdar *bsdar, const char *name); |
59 |
static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name); |
59 |
static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name); |
60 |
static struct ar_obj *create_obj_from_file(struct bsdar *bsdar, |
60 |
static struct ar_obj *create_obj_from_file(struct bsdar *bsdar, |
61 |
const char *name, time_t mtime); |
61 |
const char *name, time_t mtime); |
62 |
static void create_symtab_entry(struct bsdar *bsdar, void *maddr, |
62 |
static void create_symtab_entry(struct bsdar *bsdar, void *maddr, |
63 |
size_t size); |
63 |
size_t size); |
64 |
static void free_obj(struct bsdar *bsdar, struct ar_obj *obj); |
64 |
static void free_obj(struct bsdar *bsdar, struct ar_obj *obj); |
65 |
static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj, |
65 |
static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj, |
66 |
struct ar_obj *pos); |
66 |
struct ar_obj *pos); |
67 |
static void prefault_buffer(const char *buf, size_t s); |
67 |
static void prefault_buffer(const char *buf, size_t s); |
68 |
static void read_objs(struct bsdar *bsdar, const char *archive, |
68 |
static void read_objs(struct bsdar *bsdar, const char *archive, |
69 |
int checkargv); |
69 |
int checkargv); |
70 |
static void write_archive(struct bsdar *bsdar, char mode); |
70 |
static int write_archive(struct bsdar *bsdar, char mode); |
71 |
static void write_cleanup(struct bsdar *bsdar); |
71 |
static void write_cleanup(struct bsdar *bsdar); |
72 |
static void write_data(struct bsdar *bsdar, struct archive *a, |
72 |
static void write_data(struct bsdar *bsdar, struct archive *a, |
73 |
const void *buf, size_t s); |
73 |
const void *buf, size_t s); |
74 |
static void write_objs(struct bsdar *bsdar); |
74 |
static void write_objs(struct bsdar *bsdar); |
75 |
|
75 |
|
76 |
void |
76 |
int |
77 |
ar_mode_d(struct bsdar *bsdar) |
77 |
ar_mode_d(struct bsdar *bsdar) |
78 |
{ |
78 |
{ |
79 |
|
79 |
|
80 |
write_archive(bsdar, 'd'); |
80 |
return (write_archive(bsdar, 'd')); |
81 |
} |
81 |
} |
82 |
|
82 |
|
83 |
void |
83 |
int |
84 |
ar_mode_m(struct bsdar *bsdar) |
84 |
ar_mode_m(struct bsdar *bsdar) |
85 |
{ |
85 |
{ |
86 |
|
86 |
|
87 |
write_archive(bsdar, 'm'); |
87 |
return (write_archive(bsdar, 'm')); |
88 |
} |
88 |
} |
89 |
|
89 |
|
90 |
void |
90 |
int |
91 |
ar_mode_q(struct bsdar *bsdar) |
91 |
ar_mode_q(struct bsdar *bsdar) |
92 |
{ |
92 |
{ |
93 |
|
93 |
|
94 |
write_archive(bsdar, 'q'); |
94 |
return (write_archive(bsdar, 'q')); |
95 |
} |
95 |
} |
96 |
|
96 |
|
97 |
void |
97 |
int |
98 |
ar_mode_r(struct bsdar *bsdar) |
98 |
ar_mode_r(struct bsdar *bsdar) |
99 |
{ |
99 |
{ |
100 |
|
100 |
|
101 |
write_archive(bsdar, 'r'); |
101 |
return (write_archive(bsdar, 'r')); |
102 |
} |
102 |
} |
103 |
|
103 |
|
104 |
void |
104 |
int |
105 |
ar_mode_s(struct bsdar *bsdar) |
105 |
ar_mode_s(struct bsdar *bsdar) |
106 |
{ |
106 |
{ |
107 |
|
107 |
|
108 |
write_archive(bsdar, 's'); |
108 |
return (write_archive(bsdar, 's')); |
109 |
} |
109 |
} |
110 |
|
110 |
|
111 |
void |
111 |
int |
112 |
ar_mode_A(struct bsdar *bsdar) |
112 |
ar_mode_A(struct bsdar *bsdar) |
113 |
{ |
113 |
{ |
114 |
|
114 |
|
115 |
write_archive(bsdar, 'A'); |
115 |
return (write_archive(bsdar, 'A')); |
116 |
} |
116 |
} |
117 |
|
117 |
|
118 |
/* |
118 |
/* |
119 |
* Create object from file, return created obj upon success, or NULL |
119 |
* Create object from file, return created obj upon success, or NULL |
120 |
* when an error occurs or the member is not newer than existing |
120 |
* when an error occurs or the member is not newer than existing |
121 |
* one while -u is specified. |
121 |
* one while -u is specified. |
122 |
*/ |
122 |
*/ |
123 |
static struct ar_obj * |
123 |
static struct ar_obj * |
124 |
create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime) |
124 |
create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime) |
125 |
{ |
125 |
{ |
126 |
struct ar_obj *obj; |
126 |
struct ar_obj *obj; |
127 |
struct stat sb; |
127 |
struct stat sb; |
128 |
const char *bname; |
128 |
const char *bname; |
129 |
char *tmpname; |
129 |
char *tmpname; |
130 |
|
130 |
|
131 |
if (name == NULL) |
131 |
if (name == NULL) |
132 |
return (NULL); |
132 |
return (NULL); |
133 |
|
133 |
|
134 |
obj = malloc(sizeof(struct ar_obj)); |
134 |
obj = malloc(sizeof(struct ar_obj)); |
135 |
if (obj == NULL) |
135 |
if (obj == NULL) |
136 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
136 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
137 |
if ((obj->fd = open(name, O_RDONLY, 0)) < 0) { |
137 |
if ((obj->fd = open(name, O_RDONLY, 0)) < 0) { |
138 |
bsdar_warnc(bsdar, errno, "can't open file: %s", name); |
138 |
bsdar_warnc(bsdar, errno, "can't open file: %s", name); |
139 |
free(obj); |
139 |
free(obj); |
140 |
return (NULL); |
140 |
return (NULL); |
141 |
} |
141 |
} |
142 |
|
142 |
|
143 |
tmpname = strdup(name); |
143 |
tmpname = strdup(name); |
144 |
if (tmpname == NULL) |
144 |
if (tmpname == NULL) |
145 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); |
145 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); |
146 |
if ((bname = basename(tmpname)) == NULL) |
146 |
if ((bname = basename(tmpname)) == NULL) |
147 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "basename failed"); |
147 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "basename failed"); |
148 |
if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) { |
148 |
if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) { |
149 |
if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL) |
149 |
if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL) |
150 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
150 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
151 |
(void)strncpy(obj->name, bname, _TRUNCATE_LEN); |
151 |
(void)strncpy(obj->name, bname, _TRUNCATE_LEN); |
152 |
obj->name[_TRUNCATE_LEN] = '\0'; |
152 |
obj->name[_TRUNCATE_LEN] = '\0'; |
153 |
} else |
153 |
} else |
154 |
if ((obj->name = strdup(bname)) == NULL) |
154 |
if ((obj->name = strdup(bname)) == NULL) |
155 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); |
155 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); |
156 |
free(tmpname); |
156 |
free(tmpname); |
157 |
|
157 |
|
158 |
if (fstat(obj->fd, &sb) < 0) { |
158 |
if (fstat(obj->fd, &sb) < 0) { |
159 |
bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name); |
159 |
bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name); |
160 |
goto giveup; |
160 |
goto giveup; |
161 |
} |
161 |
} |
162 |
if (!S_ISREG(sb.st_mode)) { |
162 |
if (!S_ISREG(sb.st_mode)) { |
163 |
bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name); |
163 |
bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name); |
164 |
goto giveup; |
164 |
goto giveup; |
165 |
} |
165 |
} |
166 |
|
166 |
|
167 |
/* |
167 |
/* |
168 |
* When option '-u' is specified and member is not newer than the |
168 |
* When option '-u' is specified and member is not newer than the |
169 |
* existing one, the replace will not happen. While if mtime == 0, |
169 |
* existing one, the replace will not happen. While if mtime == 0, |
170 |
* which indicates that this is to "replace a none exist member", |
170 |
* which indicates that this is to "replace a none exist member", |
171 |
* the replace will proceed regardless of '-u'. |
171 |
* the replace will proceed regardless of '-u'. |
172 |
*/ |
172 |
*/ |
173 |
if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime) |
173 |
if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime) |
174 |
goto giveup; |
174 |
goto giveup; |
175 |
|
175 |
|
176 |
/* |
176 |
/* |
177 |
* When option '-D' is specified, mtime and UID / GID from the file |
177 |
* When option '-D' is specified, mtime and UID / GID from the file |
178 |
* will be replaced with 0, and file mode with 644. This ensures that |
178 |
* will be replaced with 0, and file mode with 644. This ensures that |
179 |
* checksums will match for two archives containing the exact same |
179 |
* checksums will match for two archives containing the exact same |
180 |
* files. |
180 |
* files. |
181 |
*/ |
181 |
*/ |
182 |
if (bsdar->options & AR_D) { |
182 |
if (bsdar->options & AR_D) { |
183 |
obj->uid = 0; |
183 |
obj->uid = 0; |
184 |
obj->gid = 0; |
184 |
obj->gid = 0; |
185 |
obj->mtime = 0; |
185 |
obj->mtime = 0; |
186 |
obj->md = S_IFREG | 0644; |
186 |
obj->md = S_IFREG | 0644; |
187 |
} else { |
187 |
} else { |
188 |
obj->uid = sb.st_uid; |
188 |
obj->uid = sb.st_uid; |
189 |
obj->gid = sb.st_gid; |
189 |
obj->gid = sb.st_gid; |
190 |
obj->mtime = sb.st_mtime; |
190 |
obj->mtime = sb.st_mtime; |
191 |
obj->md = sb.st_mode; |
191 |
obj->md = sb.st_mode; |
192 |
} |
192 |
} |
193 |
obj->size = sb.st_size; |
193 |
obj->size = sb.st_size; |
194 |
obj->dev = sb.st_dev; |
194 |
obj->dev = sb.st_dev; |
195 |
obj->ino = sb.st_ino; |
195 |
obj->ino = sb.st_ino; |
196 |
|
196 |
|
197 |
if (obj->size == 0) { |
197 |
if (obj->size == 0) { |
198 |
obj->maddr = NULL; |
198 |
obj->maddr = NULL; |
199 |
return (obj); |
199 |
return (obj); |
200 |
} |
200 |
} |
201 |
|
201 |
|
202 |
if ((obj->maddr = mmap(NULL, obj->size, PROT_READ, |
202 |
if ((obj->maddr = mmap(NULL, obj->size, PROT_READ, |
203 |
MAP_PRIVATE, obj->fd, (off_t)0)) == MAP_FAILED) { |
203 |
MAP_PRIVATE, obj->fd, (off_t)0)) == MAP_FAILED) { |
204 |
bsdar_warnc(bsdar, errno, "can't mmap file: %s", obj->name); |
204 |
bsdar_warnc(bsdar, errno, "can't mmap file: %s", obj->name); |
205 |
goto giveup; |
205 |
goto giveup; |
206 |
} |
206 |
} |
207 |
if (close(obj->fd) < 0) |
207 |
if (close(obj->fd) < 0) |
208 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "close failed: %s", |
208 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "close failed: %s", |
209 |
obj->name); |
209 |
obj->name); |
210 |
|
210 |
|
211 |
return (obj); |
211 |
return (obj); |
212 |
|
212 |
|
213 |
giveup: |
213 |
giveup: |
214 |
if (close(obj->fd) < 0) |
214 |
if (close(obj->fd) < 0) |
215 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "close failed: %s", |
215 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "close failed: %s", |
216 |
obj->name); |
216 |
obj->name); |
217 |
free(obj->name); |
217 |
free(obj->name); |
218 |
free(obj); |
218 |
free(obj); |
219 |
return (NULL); |
219 |
return (NULL); |
220 |
} |
220 |
} |
221 |
|
221 |
|
222 |
/* |
222 |
/* |
223 |
* Free object itself and its associated allocations. |
223 |
* Free object itself and its associated allocations. |
224 |
*/ |
224 |
*/ |
225 |
static void |
225 |
static void |
226 |
free_obj(struct bsdar *bsdar, struct ar_obj *obj) |
226 |
free_obj(struct bsdar *bsdar, struct ar_obj *obj) |
227 |
{ |
227 |
{ |
228 |
if (obj->fd == -1) |
228 |
if (obj->fd == -1) |
229 |
free(obj->maddr); |
229 |
free(obj->maddr); |
230 |
else |
230 |
else |
231 |
if (obj->maddr != NULL && munmap(obj->maddr, obj->size)) |
231 |
if (obj->maddr != NULL && munmap(obj->maddr, obj->size)) |
232 |
bsdar_warnc(bsdar, errno, |
232 |
bsdar_warnc(bsdar, errno, |
233 |
"can't munmap file: %s", obj->name); |
233 |
"can't munmap file: %s", obj->name); |
234 |
free(obj->name); |
234 |
free(obj->name); |
235 |
free(obj); |
235 |
free(obj); |
236 |
} |
236 |
} |
237 |
|
237 |
|
238 |
/* |
238 |
/* |
239 |
* Insert obj to the tail, or before/after the pos obj. |
239 |
* Insert obj to the tail, or before/after the pos obj. |
240 |
*/ |
240 |
*/ |
241 |
static void |
241 |
static void |
242 |
insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos) |
242 |
insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos) |
243 |
{ |
243 |
{ |
244 |
if (obj == NULL) |
244 |
if (obj == NULL) |
245 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, "try to insert a null obj"); |
245 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, "try to insert a null obj"); |
246 |
|
246 |
|
247 |
if (pos == NULL || obj == pos) |
247 |
if (pos == NULL || obj == pos) |
248 |
/* |
248 |
/* |
249 |
* If the object to move happens to be the position obj, |
249 |
* If the object to move happens to be the position obj, |
250 |
* or if there is not a pos obj, move it to tail. |
250 |
* or if there is not a pos obj, move it to tail. |
251 |
*/ |
251 |
*/ |
252 |
goto tail; |
252 |
goto tail; |
253 |
|
253 |
|
254 |
if (bsdar->options & AR_B) { |
254 |
if (bsdar->options & AR_B) { |
255 |
TAILQ_INSERT_BEFORE(pos, obj, objs); |
255 |
TAILQ_INSERT_BEFORE(pos, obj, objs); |
256 |
return; |
256 |
return; |
257 |
} |
257 |
} |
258 |
if (bsdar->options & AR_A) { |
258 |
if (bsdar->options & AR_A) { |
259 |
TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs); |
259 |
TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs); |
260 |
return; |
260 |
return; |
261 |
} |
261 |
} |
262 |
|
262 |
|
263 |
tail: |
263 |
tail: |
264 |
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); |
264 |
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); |
265 |
|
265 |
|
266 |
} |
266 |
} |
267 |
|
267 |
|
268 |
/* |
268 |
/* |
269 |
* Read objects from archive into v_obj list. Note that checkargv is |
269 |
* Read objects from archive into v_obj list. Note that checkargv is |
270 |
* set when read_objs is used to read objects from the target of |
270 |
* set when read_objs is used to read objects from the target of |
271 |
* ADDLIB command (ar script mode), in this case argv array possibly |
271 |
* ADDLIB command (ar script mode), in this case argv array possibly |
272 |
* specifies the members ADDLIB want. |
272 |
* specifies the members ADDLIB want. |
273 |
*/ |
273 |
*/ |
274 |
static void |
274 |
static void |
275 |
read_objs(struct bsdar *bsdar, const char *archive, int checkargv) |
275 |
read_objs(struct bsdar *bsdar, const char *archive, int checkargv) |
276 |
{ |
276 |
{ |
277 |
struct archive *a; |
277 |
struct archive *a; |
278 |
struct archive_entry *entry; |
278 |
struct archive_entry *entry; |
279 |
struct ar_obj *obj; |
279 |
struct ar_obj *obj; |
280 |
const char *name; |
280 |
const char *name; |
281 |
const char *bname; |
281 |
const char *bname; |
282 |
char *buff; |
282 |
char *buff; |
283 |
char **av; |
283 |
char **av; |
284 |
size_t size; |
284 |
size_t size; |
285 |
int i, r, find; |
285 |
int i, r, find; |
286 |
|
286 |
|
287 |
if ((a = archive_read_new()) == NULL) |
287 |
if ((a = archive_read_new()) == NULL) |
288 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed"); |
288 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_read_new failed"); |
289 |
archive_read_support_format_ar(a); |
289 |
archive_read_support_format_ar(a); |
290 |
AC(archive_read_open_filename(a, archive, DEF_BLKSZ)); |
290 |
AC(archive_read_open_filename(a, archive, DEF_BLKSZ)); |
291 |
for (;;) { |
291 |
for (;;) { |
292 |
r = archive_read_next_header(a, &entry); |
292 |
r = archive_read_next_header(a, &entry); |
293 |
if (r == ARCHIVE_FATAL) |
293 |
if (r == ARCHIVE_FATAL) |
294 |
bsdar_errc(bsdar, EX_DATAERR, archive_errno(a), "%s", |
294 |
bsdar_errc(bsdar, EX_DATAERR, archive_errno(a), "%s", |
295 |
archive_error_string(a)); |
295 |
archive_error_string(a)); |
296 |
if (r == ARCHIVE_EOF) |
296 |
if (r == ARCHIVE_EOF) |
297 |
break; |
297 |
break; |
298 |
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) |
298 |
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) |
299 |
bsdar_warnc(bsdar, archive_errno(a), "%s", |
299 |
bsdar_warnc(bsdar, archive_errno(a), "%s", |
300 |
archive_error_string(a)); |
300 |
archive_error_string(a)); |
301 |
if (r == ARCHIVE_RETRY) { |
301 |
if (r == ARCHIVE_RETRY) { |
302 |
bsdar_warnc(bsdar, 0, "Retrying..."); |
302 |
bsdar_warnc(bsdar, 0, "Retrying..."); |
303 |
continue; |
303 |
continue; |
304 |
} |
304 |
} |
305 |
|
305 |
|
306 |
name = archive_entry_pathname(entry); |
306 |
name = archive_entry_pathname(entry); |
307 |
|
307 |
|
308 |
/* |
308 |
/* |
309 |
* skip pseudo members. |
309 |
* skip pseudo members. |
310 |
*/ |
310 |
*/ |
311 |
if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) |
311 |
if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) |
312 |
continue; |
312 |
continue; |
313 |
|
313 |
|
314 |
/* |
314 |
/* |
315 |
* If checkargv is set, only read those members specified |
315 |
* If checkargv is set, only read those members specified |
316 |
* in argv. |
316 |
* in argv. |
317 |
*/ |
317 |
*/ |
318 |
if (checkargv && bsdar->argc > 0) { |
318 |
if (checkargv && bsdar->argc > 0) { |
319 |
find = 0; |
319 |
find = 0; |
320 |
for(i = 0; i < bsdar->argc; i++) { |
320 |
for(i = 0; i < bsdar->argc; i++) { |
321 |
av = &bsdar->argv[i]; |
321 |
av = &bsdar->argv[i]; |
322 |
if (*av == NULL) |
322 |
if (*av == NULL) |
323 |
continue; |
323 |
continue; |
324 |
if ((bname = basename(*av)) == NULL) |
324 |
if ((bname = basename(*av)) == NULL) |
325 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, |
325 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, |
326 |
"basename failed"); |
326 |
"basename failed"); |
327 |
if (strcmp(bname, name) != 0) |
327 |
if (strcmp(bname, name) != 0) |
328 |
continue; |
328 |
continue; |
329 |
|
329 |
|
330 |
*av = NULL; |
330 |
*av = NULL; |
331 |
find = 1; |
331 |
find = 1; |
332 |
break; |
332 |
break; |
333 |
} |
333 |
} |
334 |
if (!find) |
334 |
if (!find) |
335 |
continue; |
335 |
continue; |
336 |
} |
336 |
} |
337 |
|
337 |
|
338 |
size = archive_entry_size(entry); |
338 |
size = archive_entry_size(entry); |
339 |
|
339 |
|
340 |
if (size > 0) { |
340 |
if (size > 0) { |
341 |
if ((buff = malloc(size)) == NULL) |
341 |
if ((buff = malloc(size)) == NULL) |
342 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, |
342 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, |
343 |
"malloc failed"); |
343 |
"malloc failed"); |
344 |
if (archive_read_data(a, buff, size) != (ssize_t)size) { |
344 |
if (archive_read_data(a, buff, size) != (ssize_t)size) { |
345 |
bsdar_warnc(bsdar, archive_errno(a), "%s", |
345 |
bsdar_warnc(bsdar, archive_errno(a), "%s", |
346 |
archive_error_string(a)); |
346 |
archive_error_string(a)); |
347 |
free(buff); |
347 |
free(buff); |
348 |
continue; |
348 |
continue; |
349 |
} |
349 |
} |
350 |
} else |
350 |
} else |
351 |
buff = NULL; |
351 |
buff = NULL; |
352 |
|
352 |
|
353 |
obj = malloc(sizeof(struct ar_obj)); |
353 |
obj = malloc(sizeof(struct ar_obj)); |
354 |
if (obj == NULL) |
354 |
if (obj == NULL) |
355 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
355 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
356 |
obj->maddr = buff; |
356 |
obj->maddr = buff; |
357 |
if ((obj->name = strdup(name)) == NULL) |
357 |
if ((obj->name = strdup(name)) == NULL) |
358 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); |
358 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "strdup failed"); |
359 |
obj->size = size; |
359 |
obj->size = size; |
360 |
obj->uid = archive_entry_uid(entry); |
360 |
obj->uid = archive_entry_uid(entry); |
361 |
obj->gid = archive_entry_gid(entry); |
361 |
obj->gid = archive_entry_gid(entry); |
362 |
obj->md = archive_entry_mode(entry); |
362 |
obj->md = archive_entry_mode(entry); |
363 |
obj->mtime = archive_entry_mtime(entry); |
363 |
obj->mtime = archive_entry_mtime(entry); |
364 |
obj->dev = 0; |
364 |
obj->dev = 0; |
365 |
obj->ino = 0; |
365 |
obj->ino = 0; |
366 |
|
366 |
|
367 |
/* |
367 |
/* |
368 |
* Objects from archive have obj->fd set to -1, |
368 |
* Objects from archive have obj->fd set to -1, |
369 |
* for the ease of cleaning up. |
369 |
* for the ease of cleaning up. |
370 |
*/ |
370 |
*/ |
371 |
obj->fd = -1; |
371 |
obj->fd = -1; |
372 |
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); |
372 |
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs); |
373 |
} |
373 |
} |
374 |
AC(archive_read_close(a)); |
374 |
AC(archive_read_close(a)); |
375 |
AC(archive_read_free(a)); |
375 |
AC(archive_read_free(a)); |
376 |
} |
376 |
} |
377 |
|
377 |
|
378 |
/* |
378 |
/* |
379 |
* Determine the constitution of resulting archive. |
379 |
* Determine the constitution of resulting archive. |
380 |
*/ |
380 |
*/ |
381 |
static void |
381 |
static int |
382 |
write_archive(struct bsdar *bsdar, char mode) |
382 |
write_archive(struct bsdar *bsdar, char mode) |
383 |
{ |
383 |
{ |
384 |
struct ar_obj *nobj, *obj, *obj_temp, *pos; |
384 |
struct ar_obj *nobj, *obj, *obj_temp, *pos; |
385 |
struct stat sb; |
385 |
struct stat sb; |
386 |
const char *bname; |
386 |
const char *bname; |
387 |
char **av; |
387 |
char **av; |
388 |
int i; |
388 |
int exitcode, i; |
389 |
|
389 |
|
390 |
TAILQ_INIT(&bsdar->v_obj); |
390 |
TAILQ_INIT(&bsdar->v_obj); |
|
|
391 |
exitcode = EXIT_SUCCESS; |
391 |
nobj = NULL; |
392 |
nobj = NULL; |
392 |
pos = NULL; |
393 |
pos = NULL; |
393 |
memset(&sb, 0, sizeof(sb)); |
394 |
memset(&sb, 0, sizeof(sb)); |
394 |
|
395 |
|
395 |
/* |
396 |
/* |
396 |
* Test if the specified archive exists, to figure out |
397 |
* Test if the specified archive exists, to figure out |
397 |
* whether we are creating one here. |
398 |
* whether we are creating one here. |
398 |
*/ |
399 |
*/ |
399 |
if (stat(bsdar->filename, &sb) != 0) { |
400 |
if (stat(bsdar->filename, &sb) != 0) { |
400 |
if (errno != ENOENT) { |
401 |
if (errno != ENOENT) { |
401 |
bsdar_warnc(bsdar, 0, "stat %s failed", |
402 |
bsdar_warnc(bsdar, 0, "stat %s failed", |
402 |
bsdar->filename); |
403 |
bsdar->filename); |
403 |
return; |
404 |
return (EXIT_FAILURE); |
404 |
} |
405 |
} |
405 |
|
406 |
|
406 |
/* We do not create archive in mode 'd', 'm' and 's'. */ |
407 |
/* We do not create archive in mode 'd', 'm' and 's'. */ |
407 |
if (mode != 'r' && mode != 'q') { |
408 |
if (mode != 'r' && mode != 'q') { |
408 |
bsdar_warnc(bsdar, 0, "%s: no such file", |
409 |
bsdar_warnc(bsdar, 0, "%s: no such file", |
409 |
bsdar->filename); |
410 |
bsdar->filename); |
410 |
return; |
411 |
return (EXIT_FAILURE); |
411 |
} |
412 |
} |
412 |
|
413 |
|
413 |
/* Issue a warning if -c is not specified when creating. */ |
414 |
/* Issue a warning if -c is not specified when creating. */ |
414 |
if (!(bsdar->options & AR_C)) |
415 |
if (!(bsdar->options & AR_C)) |
415 |
bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename); |
416 |
bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename); |
416 |
goto new_archive; |
417 |
goto new_archive; |
417 |
} |
418 |
} |
418 |
|
419 |
|
419 |
/* |
420 |
/* |
420 |
* First read members from existing archive. |
421 |
* First read members from existing archive. |
421 |
*/ |
422 |
*/ |
422 |
read_objs(bsdar, bsdar->filename, 0); |
423 |
read_objs(bsdar, bsdar->filename, 0); |
423 |
|
424 |
|
424 |
/* |
425 |
/* |
425 |
* For mode 's', no member will be moved, deleted or replaced. |
426 |
* For mode 's', no member will be moved, deleted or replaced. |
426 |
*/ |
427 |
*/ |
427 |
if (mode == 's') |
428 |
if (mode == 's') |
428 |
goto write_objs; |
429 |
goto write_objs; |
429 |
|
430 |
|
430 |
/* |
431 |
/* |
431 |
* For mode 'q', we don't need to adjust existing members either. |
432 |
* For mode 'q', we don't need to adjust existing members either. |
432 |
* Also, -a, -b and -i are ignored in this mode. New members are |
433 |
* Also, -a, -b and -i are ignored in this mode. New members are |
433 |
* always inserted at tail. |
434 |
* always inserted at tail. |
434 |
*/ |
435 |
*/ |
435 |
if (mode == 'q') |
436 |
if (mode == 'q') |
436 |
goto new_archive; |
437 |
goto new_archive; |
437 |
|
438 |
|
438 |
/* |
439 |
/* |
439 |
* Mode 'A' adds the contents of another archive to the tail of |
440 |
* Mode 'A' adds the contents of another archive to the tail of |
440 |
* current archive. Note that mode 'A' is a special mode for the |
441 |
* current archive. Note that mode 'A' is a special mode for the |
441 |
* ADDLIB command of the ar script mode. Currently there is no |
442 |
* ADDLIB command of the ar script mode. Currently there is no |
442 |
* access to this function from the ar command line mode. |
443 |
* access to this function from the ar command line mode. |
443 |
*/ |
444 |
*/ |
444 |
if (mode == 'A') { |
445 |
if (mode == 'A') { |
445 |
/* |
446 |
/* |
446 |
* Read objects from the target archive of ADDLIB command. |
447 |
* Read objects from the target archive of ADDLIB command. |
447 |
* If there are members specified in argv, read those members |
448 |
* If there are members specified in argv, read those members |
448 |
* only, otherwise the entire archive will be read. |
449 |
* only, otherwise the entire archive will be read. |
449 |
*/ |
450 |
*/ |
450 |
read_objs(bsdar, bsdar->addlib, 1); |
451 |
read_objs(bsdar, bsdar->addlib, 1); |
451 |
goto write_objs; |
452 |
goto write_objs; |
452 |
} |
453 |
} |
453 |
|
454 |
|
454 |
/* |
455 |
/* |
455 |
* Try to find the position member specified by user. |
456 |
* Try to find the position member specified by user. |
456 |
*/ |
457 |
*/ |
457 |
if (bsdar->options & AR_A || bsdar->options & AR_B) { |
458 |
if (bsdar->options & AR_A || bsdar->options & AR_B) { |
458 |
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { |
459 |
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { |
459 |
if (strcmp(obj->name, bsdar->posarg) == 0) { |
460 |
if (strcmp(obj->name, bsdar->posarg) == 0) { |
460 |
pos = obj; |
461 |
pos = obj; |
461 |
break; |
462 |
break; |
462 |
} |
463 |
} |
463 |
} |
464 |
} |
464 |
|
465 |
|
465 |
/* |
466 |
/* |
466 |
* If can't find `pos' specified by user, |
467 |
* If can't find `pos' specified by user, |
467 |
* silently insert objects at tail. |
468 |
* silently insert objects at tail. |
468 |
*/ |
469 |
*/ |
469 |
if (pos == NULL) |
470 |
if (pos == NULL) |
470 |
bsdar->options &= ~(AR_A | AR_B); |
471 |
bsdar->options &= ~(AR_A | AR_B); |
471 |
} |
472 |
} |
472 |
|
473 |
|
473 |
for (i = 0; i < bsdar->argc; i++) { |
474 |
for (i = 0; i < bsdar->argc; i++) { |
474 |
av = &bsdar->argv[i]; |
475 |
av = &bsdar->argv[i]; |
475 |
|
476 |
|
476 |
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { |
477 |
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { |
477 |
if ((bname = basename(*av)) == NULL) |
478 |
if ((bname = basename(*av)) == NULL) |
478 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, |
479 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, |
479 |
"basename failed"); |
480 |
"basename failed"); |
480 |
if (bsdar->options & AR_TR) { |
481 |
if (bsdar->options & AR_TR) { |
481 |
if (strncmp(bname, obj->name, _TRUNCATE_LEN)) |
482 |
if (strncmp(bname, obj->name, _TRUNCATE_LEN)) |
482 |
continue; |
483 |
continue; |
483 |
} else |
484 |
} else |
484 |
if (strcmp(bname, obj->name) != 0) |
485 |
if (strcmp(bname, obj->name) != 0) |
485 |
continue; |
486 |
continue; |
486 |
|
487 |
|
487 |
if (mode == 'r') { |
488 |
if (mode == 'r') { |
488 |
/* |
489 |
/* |
489 |
* if the new member is not qualified |
490 |
* if the new member is not qualified |
490 |
* to replace the old one, skip it. |
491 |
* to replace the old one, skip it. |
491 |
*/ |
492 |
*/ |
492 |
nobj = create_obj_from_file(bsdar, *av, |
493 |
nobj = create_obj_from_file(bsdar, *av, |
493 |
obj->mtime); |
494 |
obj->mtime); |
494 |
if (nobj == NULL) |
495 |
if (nobj == NULL) { |
|
|
496 |
exitcode = EXIT_FAILURE; |
495 |
goto skip_obj; |
497 |
goto skip_obj; |
|
|
498 |
} |
496 |
} |
499 |
} |
497 |
|
500 |
|
498 |
if (bsdar->options & AR_V) |
501 |
if (bsdar->options & AR_V) |
499 |
(void)fprintf(stdout, "%c - %s\n", mode, |
502 |
(void)fprintf(stdout, "%c - %s\n", mode, |
500 |
*av); |
503 |
*av); |
501 |
|
504 |
|
502 |
TAILQ_REMOVE(&bsdar->v_obj, obj, objs); |
505 |
TAILQ_REMOVE(&bsdar->v_obj, obj, objs); |
503 |
if (mode == 'd' || mode == 'r') |
506 |
if (mode == 'd' || mode == 'r') |
504 |
free_obj(bsdar, obj); |
507 |
free_obj(bsdar, obj); |
505 |
|
508 |
|
506 |
if (mode == 'm') |
509 |
if (mode == 'm') |
507 |
insert_obj(bsdar, obj, pos); |
510 |
insert_obj(bsdar, obj, pos); |
508 |
if (mode == 'r') |
511 |
if (mode == 'r') |
509 |
insert_obj(bsdar, nobj, pos); |
512 |
insert_obj(bsdar, nobj, pos); |
510 |
|
513 |
|
511 |
skip_obj: |
514 |
skip_obj: |
512 |
*av = NULL; |
515 |
*av = NULL; |
513 |
break; |
516 |
break; |
514 |
} |
517 |
} |
515 |
|
518 |
|
516 |
} |
519 |
} |
517 |
|
520 |
|
518 |
new_archive: |
521 |
new_archive: |
519 |
/* |
522 |
/* |
520 |
* When operating in mode 'r', directly add those user specified |
523 |
* When operating in mode 'r', directly add those user specified |
521 |
* objects which do not exist in current archive. When operating |
524 |
* objects which do not exist in current archive. When operating |
522 |
* in mode 'q', all objects specified in command line args are |
525 |
* in mode 'q', all objects specified in command line args are |
523 |
* appended to the archive, without comparing with existing ones. |
526 |
* appended to the archive, without comparing with existing ones. |
524 |
*/ |
527 |
*/ |
525 |
for (i = 0; i < bsdar->argc; i++) { |
528 |
for (i = 0; i < bsdar->argc; i++) { |
526 |
av = &bsdar->argv[i]; |
529 |
av = &bsdar->argv[i]; |
527 |
if (*av != NULL && (mode == 'r' || mode == 'q')) { |
530 |
if (*av != NULL && (mode == 'r' || mode == 'q')) { |
528 |
nobj = create_obj_from_file(bsdar, *av, 0); |
531 |
nobj = create_obj_from_file(bsdar, *av, 0); |
529 |
if (nobj != NULL) |
532 |
if (nobj == NULL) { |
530 |
insert_obj(bsdar, nobj, pos); |
533 |
exitcode = EXIT_FAILURE; |
|
|
534 |
*av = NULL; |
535 |
continue; |
536 |
} |
537 |
insert_obj(bsdar, nobj, pos); |
531 |
if (bsdar->options & AR_V && nobj != NULL) |
538 |
if (bsdar->options & AR_V && nobj != NULL) |
532 |
(void)fprintf(stdout, "a - %s\n", *av); |
539 |
(void)fprintf(stdout, "a - %s\n", *av); |
533 |
*av = NULL; |
540 |
*av = NULL; |
534 |
} |
541 |
} |
535 |
} |
542 |
} |
536 |
|
543 |
|
537 |
write_objs: |
544 |
write_objs: |
538 |
write_objs(bsdar); |
545 |
write_objs(bsdar); |
539 |
write_cleanup(bsdar); |
546 |
write_cleanup(bsdar); |
|
|
547 |
|
548 |
return (exitcode); |
540 |
} |
549 |
} |
541 |
|
550 |
|
542 |
/* |
551 |
/* |
543 |
* Memory cleaning up. |
552 |
* Memory cleaning up. |
544 |
*/ |
553 |
*/ |
545 |
static void |
554 |
static void |
546 |
write_cleanup(struct bsdar *bsdar) |
555 |
write_cleanup(struct bsdar *bsdar) |
547 |
{ |
556 |
{ |
548 |
struct ar_obj *obj, *obj_temp; |
557 |
struct ar_obj *obj, *obj_temp; |
549 |
|
558 |
|
550 |
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { |
559 |
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) { |
551 |
TAILQ_REMOVE(&bsdar->v_obj, obj, objs); |
560 |
TAILQ_REMOVE(&bsdar->v_obj, obj, objs); |
552 |
free_obj(bsdar, obj); |
561 |
free_obj(bsdar, obj); |
553 |
} |
562 |
} |
554 |
|
563 |
|
555 |
free(bsdar->as); |
564 |
free(bsdar->as); |
556 |
free(bsdar->s_so); |
565 |
free(bsdar->s_so); |
557 |
free(bsdar->s_sn); |
566 |
free(bsdar->s_sn); |
558 |
bsdar->as = NULL; |
567 |
bsdar->as = NULL; |
559 |
bsdar->s_so = NULL; |
568 |
bsdar->s_so = NULL; |
560 |
bsdar->s_so_max = 0; |
569 |
bsdar->s_so_max = 0; |
561 |
bsdar->s_sn = NULL; |
570 |
bsdar->s_sn = NULL; |
562 |
} |
571 |
} |
563 |
|
572 |
|
564 |
/* |
573 |
/* |
565 |
* Fault in the buffer prior to writing as a workaround for poor performance |
574 |
* Fault in the buffer prior to writing as a workaround for poor performance |
566 |
* due to interaction with kernel fs deadlock avoidance code. See the comment |
575 |
* due to interaction with kernel fs deadlock avoidance code. See the comment |
567 |
* above vn_io_fault_doio() in sys/kern/vfs_vnops.c for details of the issue. |
576 |
* above vn_io_fault_doio() in sys/kern/vfs_vnops.c for details of the issue. |
568 |
*/ |
577 |
*/ |
569 |
static void |
578 |
static void |
570 |
prefault_buffer(const char *buf, size_t s) |
579 |
prefault_buffer(const char *buf, size_t s) |
571 |
{ |
580 |
{ |
572 |
volatile const char *p; |
581 |
volatile const char *p; |
573 |
size_t page_size; |
582 |
size_t page_size; |
574 |
|
583 |
|
575 |
if (s == 0) |
584 |
if (s == 0) |
576 |
return; |
585 |
return; |
577 |
page_size = sysconf(_SC_PAGESIZE); |
586 |
page_size = sysconf(_SC_PAGESIZE); |
578 |
for (p = buf; p < buf + s; p += page_size) |
587 |
for (p = buf; p < buf + s; p += page_size) |
579 |
*p; |
588 |
*p; |
580 |
/* |
589 |
/* |
581 |
* Ensure we touch the last page as well, in case the buffer is not |
590 |
* Ensure we touch the last page as well, in case the buffer is not |
582 |
* page-aligned. |
591 |
* page-aligned. |
583 |
*/ |
592 |
*/ |
584 |
*(volatile const char *)(buf + s - 1); |
593 |
*(volatile const char *)(buf + s - 1); |
585 |
} |
594 |
} |
586 |
|
595 |
|
587 |
/* |
596 |
/* |
588 |
* Wrapper for archive_write_data(). |
597 |
* Wrapper for archive_write_data(). |
589 |
*/ |
598 |
*/ |
590 |
static void |
599 |
static void |
591 |
write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s) |
600 |
write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s) |
592 |
{ |
601 |
{ |
593 |
ssize_t written; |
602 |
ssize_t written; |
594 |
|
603 |
|
595 |
prefault_buffer(buf, s); |
604 |
prefault_buffer(buf, s); |
596 |
while (s > 0) { |
605 |
while (s > 0) { |
597 |
written = archive_write_data(a, buf, s); |
606 |
written = archive_write_data(a, buf, s); |
598 |
if (written < 0) |
607 |
if (written < 0) |
599 |
bsdar_errc(bsdar, EX_SOFTWARE, archive_errno(a), "%s", |
608 |
bsdar_errc(bsdar, EX_SOFTWARE, archive_errno(a), "%s", |
600 |
archive_error_string(a)); |
609 |
archive_error_string(a)); |
601 |
buf = (const char *)buf + written; |
610 |
buf = (const char *)buf + written; |
602 |
s -= written; |
611 |
s -= written; |
603 |
} |
612 |
} |
604 |
} |
613 |
} |
605 |
|
614 |
|
606 |
/* |
615 |
/* |
607 |
* Write the resulting archive members. |
616 |
* Write the resulting archive members. |
608 |
*/ |
617 |
*/ |
609 |
static void |
618 |
static void |
610 |
write_objs(struct bsdar *bsdar) |
619 |
write_objs(struct bsdar *bsdar) |
611 |
{ |
620 |
{ |
612 |
struct ar_obj *obj; |
621 |
struct ar_obj *obj; |
613 |
struct archive *a; |
622 |
struct archive *a; |
614 |
struct archive_entry *entry; |
623 |
struct archive_entry *entry; |
615 |
size_t s_sz; /* size of archive symbol table. */ |
624 |
size_t s_sz; /* size of archive symbol table. */ |
616 |
size_t pm_sz; /* size of pseudo members */ |
625 |
size_t pm_sz; /* size of pseudo members */ |
617 |
size_t w_sz; /* size of words in symbol table */ |
626 |
size_t w_sz; /* size of words in symbol table */ |
618 |
size_t i; |
627 |
size_t i; |
619 |
uint64_t nr; |
628 |
uint64_t nr; |
620 |
uint32_t nr32; |
629 |
uint32_t nr32; |
621 |
|
630 |
|
622 |
if (elf_version(EV_CURRENT) == EV_NONE) |
631 |
if (elf_version(EV_CURRENT) == EV_NONE) |
623 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
632 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
624 |
"ELF library initialization failed: %s", elf_errmsg(-1)); |
633 |
"ELF library initialization failed: %s", elf_errmsg(-1)); |
625 |
|
634 |
|
626 |
bsdar->rela_off = 0; |
635 |
bsdar->rela_off = 0; |
627 |
|
636 |
|
628 |
/* Create archive symbol table and archive string table, if need. */ |
637 |
/* Create archive symbol table and archive string table, if need. */ |
629 |
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { |
638 |
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { |
630 |
if (!(bsdar->options & AR_SS) && obj->maddr != NULL) |
639 |
if (!(bsdar->options & AR_SS) && obj->maddr != NULL) |
631 |
create_symtab_entry(bsdar, obj->maddr, obj->size); |
640 |
create_symtab_entry(bsdar, obj->maddr, obj->size); |
632 |
if (strlen(obj->name) > _MAXNAMELEN_SVR4) |
641 |
if (strlen(obj->name) > _MAXNAMELEN_SVR4) |
633 |
add_to_ar_str_table(bsdar, obj->name); |
642 |
add_to_ar_str_table(bsdar, obj->name); |
634 |
bsdar->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; |
643 |
bsdar->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; |
635 |
} |
644 |
} |
636 |
|
645 |
|
637 |
/* |
646 |
/* |
638 |
* Pad the symbol name string table. It is treated specially because |
647 |
* Pad the symbol name string table. It is treated specially because |
639 |
* symbol name table should be padded by a '\0', not the common '\n' |
648 |
* symbol name table should be padded by a '\0', not the common '\n' |
640 |
* for other members. The size of sn table includes the pad bit. |
649 |
* for other members. The size of sn table includes the pad bit. |
641 |
*/ |
650 |
*/ |
642 |
if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0) |
651 |
if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0) |
643 |
bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; |
652 |
bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; |
644 |
|
653 |
|
645 |
/* |
654 |
/* |
646 |
* Archive string table is padded by a "\n" as the normal members. |
655 |
* Archive string table is padded by a "\n" as the normal members. |
647 |
* The difference is that the size of archive string table counts |
656 |
* The difference is that the size of archive string table counts |
648 |
* in the pad bit, while normal members' size fields do not. |
657 |
* in the pad bit, while normal members' size fields do not. |
649 |
*/ |
658 |
*/ |
650 |
if (bsdar->as != NULL && bsdar->as_sz % 2 != 0) |
659 |
if (bsdar->as != NULL && bsdar->as_sz % 2 != 0) |
651 |
bsdar->as[bsdar->as_sz++] = '\n'; |
660 |
bsdar->as[bsdar->as_sz++] = '\n'; |
652 |
|
661 |
|
653 |
/* |
662 |
/* |
654 |
* If there is a symbol table, calculate the size of pseudo members, |
663 |
* If there is a symbol table, calculate the size of pseudo members, |
655 |
* convert previously stored relative offsets to absolute ones, and |
664 |
* convert previously stored relative offsets to absolute ones, and |
656 |
* then make them Big Endian. |
665 |
* then make them Big Endian. |
657 |
* |
666 |
* |
658 |
* absolute_offset = htobe32(relative_offset + size_of_pseudo_members) |
667 |
* absolute_offset = htobe32(relative_offset + size_of_pseudo_members) |
659 |
*/ |
668 |
*/ |
660 |
w_sz = sizeof(uint32_t); |
669 |
w_sz = sizeof(uint32_t); |
661 |
if (bsdar->s_cnt != 0) { |
670 |
if (bsdar->s_cnt != 0) { |
662 |
s_sz = (bsdar->s_cnt + 1) * sizeof(uint32_t) + bsdar->s_sn_sz; |
671 |
s_sz = (bsdar->s_cnt + 1) * sizeof(uint32_t) + bsdar->s_sn_sz; |
663 |
pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); |
672 |
pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); |
664 |
if (bsdar->as != NULL) |
673 |
if (bsdar->as != NULL) |
665 |
pm_sz += _ARHDR_LEN + bsdar->as_sz; |
674 |
pm_sz += _ARHDR_LEN + bsdar->as_sz; |
666 |
/* Use the 64-bit word size format if necessary. */ |
675 |
/* Use the 64-bit word size format if necessary. */ |
667 |
if (bsdar->s_so_max > UINT32_MAX - pm_sz) { |
676 |
if (bsdar->s_so_max > UINT32_MAX - pm_sz) { |
668 |
w_sz = sizeof(uint64_t); |
677 |
w_sz = sizeof(uint64_t); |
669 |
pm_sz -= s_sz; |
678 |
pm_sz -= s_sz; |
670 |
s_sz = (bsdar->s_cnt + 1) * sizeof(uint64_t) + |
679 |
s_sz = (bsdar->s_cnt + 1) * sizeof(uint64_t) + |
671 |
bsdar->s_sn_sz; |
680 |
bsdar->s_sn_sz; |
672 |
pm_sz += s_sz; |
681 |
pm_sz += s_sz; |
673 |
/* Convert to big-endian. */ |
682 |
/* Convert to big-endian. */ |
674 |
for (i = 0; i < bsdar->s_cnt; i++) |
683 |
for (i = 0; i < bsdar->s_cnt; i++) |
675 |
bsdar->s_so[i] = |
684 |
bsdar->s_so[i] = |
676 |
htobe64(bsdar->s_so[i] + pm_sz); |
685 |
htobe64(bsdar->s_so[i] + pm_sz); |
677 |
} else { |
686 |
} else { |
678 |
/* |
687 |
/* |
679 |
* Convert to big-endian and shuffle in-place to |
688 |
* Convert to big-endian and shuffle in-place to |
680 |
* the front of the allocation. XXX UB |
689 |
* the front of the allocation. XXX UB |
681 |
*/ |
690 |
*/ |
682 |
for (i = 0; i < bsdar->s_cnt; i++) |
691 |
for (i = 0; i < bsdar->s_cnt; i++) |
683 |
((uint32_t *)(bsdar->s_so))[i] = |
692 |
((uint32_t *)(bsdar->s_so))[i] = |
684 |
htobe32(bsdar->s_so[i] + pm_sz); |
693 |
htobe32(bsdar->s_so[i] + pm_sz); |
685 |
} |
694 |
} |
686 |
} |
695 |
} |
687 |
|
696 |
|
688 |
if ((a = archive_write_new()) == NULL) |
697 |
if ((a = archive_write_new()) == NULL) |
689 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_write_new failed"); |
698 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, "archive_write_new failed"); |
690 |
|
699 |
|
691 |
archive_write_set_format_ar_svr4(a); |
700 |
archive_write_set_format_ar_svr4(a); |
692 |
|
701 |
|
693 |
AC(archive_write_open_filename(a, bsdar->filename)); |
702 |
AC(archive_write_open_filename(a, bsdar->filename)); |
694 |
|
703 |
|
695 |
/* |
704 |
/* |
696 |
* write the archive symbol table, if there is one. |
705 |
* write the archive symbol table, if there is one. |
697 |
* If options -s is explicitly specified or we are invoked |
706 |
* If options -s is explicitly specified or we are invoked |
698 |
* as ranlib, write the symbol table even if it is empty. |
707 |
* as ranlib, write the symbol table even if it is empty. |
699 |
*/ |
708 |
*/ |
700 |
if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) || |
709 |
if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) || |
701 |
bsdar->options & AR_S) { |
710 |
bsdar->options & AR_S) { |
702 |
entry = archive_entry_new(); |
711 |
entry = archive_entry_new(); |
703 |
if (entry == NULL) |
712 |
if (entry == NULL) |
704 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
713 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
705 |
"archive_entry_new failed"); |
714 |
"archive_entry_new failed"); |
706 |
if (w_sz == sizeof(uint64_t)) |
715 |
if (w_sz == sizeof(uint64_t)) |
707 |
archive_entry_copy_pathname(entry, "/SYM64/"); |
716 |
archive_entry_copy_pathname(entry, "/SYM64/"); |
708 |
else |
717 |
else |
709 |
archive_entry_copy_pathname(entry, "/"); |
718 |
archive_entry_copy_pathname(entry, "/"); |
710 |
if ((bsdar->options & AR_D) == 0) |
719 |
if ((bsdar->options & AR_D) == 0) |
711 |
archive_entry_set_mtime(entry, time(NULL), 0); |
720 |
archive_entry_set_mtime(entry, time(NULL), 0); |
712 |
archive_entry_set_size(entry, (bsdar->s_cnt + 1) * w_sz + |
721 |
archive_entry_set_size(entry, (bsdar->s_cnt + 1) * w_sz + |
713 |
bsdar->s_sn_sz); |
722 |
bsdar->s_sn_sz); |
714 |
AC(archive_write_header(a, entry)); |
723 |
AC(archive_write_header(a, entry)); |
715 |
if (w_sz == sizeof(uint64_t)) { |
724 |
if (w_sz == sizeof(uint64_t)) { |
716 |
nr = htobe64(bsdar->s_cnt); |
725 |
nr = htobe64(bsdar->s_cnt); |
717 |
write_data(bsdar, a, &nr, sizeof(nr)); |
726 |
write_data(bsdar, a, &nr, sizeof(nr)); |
718 |
} else { |
727 |
} else { |
719 |
nr32 = htobe32((uint32_t)bsdar->s_cnt); |
728 |
nr32 = htobe32((uint32_t)bsdar->s_cnt); |
720 |
write_data(bsdar, a, &nr32, sizeof(nr32)); |
729 |
write_data(bsdar, a, &nr32, sizeof(nr32)); |
721 |
} |
730 |
} |
722 |
write_data(bsdar, a, bsdar->s_so, w_sz * bsdar->s_cnt); |
731 |
write_data(bsdar, a, bsdar->s_so, w_sz * bsdar->s_cnt); |
723 |
write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz); |
732 |
write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz); |
724 |
archive_entry_free(entry); |
733 |
archive_entry_free(entry); |
725 |
} |
734 |
} |
726 |
|
735 |
|
727 |
/* write the archive string table, if any. */ |
736 |
/* write the archive string table, if any. */ |
728 |
if (bsdar->as != NULL) { |
737 |
if (bsdar->as != NULL) { |
729 |
entry = archive_entry_new(); |
738 |
entry = archive_entry_new(); |
730 |
if (entry == NULL) |
739 |
if (entry == NULL) |
731 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
740 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
732 |
"archive_entry_new failed"); |
741 |
"archive_entry_new failed"); |
733 |
archive_entry_copy_pathname(entry, "//"); |
742 |
archive_entry_copy_pathname(entry, "//"); |
734 |
archive_entry_set_size(entry, bsdar->as_sz); |
743 |
archive_entry_set_size(entry, bsdar->as_sz); |
735 |
AC(archive_write_header(a, entry)); |
744 |
AC(archive_write_header(a, entry)); |
736 |
write_data(bsdar, a, bsdar->as, bsdar->as_sz); |
745 |
write_data(bsdar, a, bsdar->as, bsdar->as_sz); |
737 |
archive_entry_free(entry); |
746 |
archive_entry_free(entry); |
738 |
} |
747 |
} |
739 |
|
748 |
|
740 |
/* write normal members. */ |
749 |
/* write normal members. */ |
741 |
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { |
750 |
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) { |
742 |
entry = archive_entry_new(); |
751 |
entry = archive_entry_new(); |
743 |
if (entry == NULL) |
752 |
if (entry == NULL) |
744 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
753 |
bsdar_errc(bsdar, EX_SOFTWARE, 0, |
745 |
"archive_entry_new failed"); |
754 |
"archive_entry_new failed"); |
746 |
archive_entry_copy_pathname(entry, obj->name); |
755 |
archive_entry_copy_pathname(entry, obj->name); |
747 |
archive_entry_set_uid(entry, obj->uid); |
756 |
archive_entry_set_uid(entry, obj->uid); |
748 |
archive_entry_set_gid(entry, obj->gid); |
757 |
archive_entry_set_gid(entry, obj->gid); |
749 |
archive_entry_set_mode(entry, obj->md); |
758 |
archive_entry_set_mode(entry, obj->md); |
750 |
archive_entry_set_size(entry, obj->size); |
759 |
archive_entry_set_size(entry, obj->size); |
751 |
archive_entry_set_mtime(entry, obj->mtime, 0); |
760 |
archive_entry_set_mtime(entry, obj->mtime, 0); |
752 |
archive_entry_set_dev(entry, obj->dev); |
761 |
archive_entry_set_dev(entry, obj->dev); |
753 |
archive_entry_set_ino(entry, obj->ino); |
762 |
archive_entry_set_ino(entry, obj->ino); |
754 |
archive_entry_set_filetype(entry, AE_IFREG); |
763 |
archive_entry_set_filetype(entry, AE_IFREG); |
755 |
AC(archive_write_header(a, entry)); |
764 |
AC(archive_write_header(a, entry)); |
756 |
write_data(bsdar, a, obj->maddr, obj->size); |
765 |
write_data(bsdar, a, obj->maddr, obj->size); |
757 |
archive_entry_free(entry); |
766 |
archive_entry_free(entry); |
758 |
} |
767 |
} |
759 |
|
768 |
|
760 |
AC(archive_write_close(a)); |
769 |
AC(archive_write_close(a)); |
761 |
AC(archive_write_free(a)); |
770 |
AC(archive_write_free(a)); |
762 |
} |
771 |
} |
763 |
|
772 |
|
764 |
/* |
773 |
/* |
765 |
* Extract global symbols from ELF binary members. |
774 |
* Extract global symbols from ELF binary members. |
766 |
*/ |
775 |
*/ |
767 |
static void |
776 |
static void |
768 |
create_symtab_entry(struct bsdar *bsdar, void *maddr, size_t size) |
777 |
create_symtab_entry(struct bsdar *bsdar, void *maddr, size_t size) |
769 |
{ |
778 |
{ |
770 |
Elf *e; |
779 |
Elf *e; |
771 |
Elf_Scn *scn; |
780 |
Elf_Scn *scn; |
772 |
GElf_Shdr shdr; |
781 |
GElf_Shdr shdr; |
773 |
GElf_Sym sym; |
782 |
GElf_Sym sym; |
774 |
Elf_Data *data; |
783 |
Elf_Data *data; |
775 |
char *name; |
784 |
char *name; |
776 |
size_t n, shstrndx; |
785 |
size_t n, shstrndx; |
777 |
int elferr, tabndx, len, i; |
786 |
int elferr, tabndx, len, i; |
778 |
|
787 |
|
779 |
if ((e = elf_memory(maddr, size)) == NULL) { |
788 |
if ((e = elf_memory(maddr, size)) == NULL) { |
780 |
bsdar_warnc(bsdar, 0, "elf_memory() failed: %s", |
789 |
bsdar_warnc(bsdar, 0, "elf_memory() failed: %s", |
781 |
elf_errmsg(-1)); |
790 |
elf_errmsg(-1)); |
782 |
return; |
791 |
return; |
783 |
} |
792 |
} |
784 |
if (elf_kind(e) != ELF_K_ELF) { |
793 |
if (elf_kind(e) != ELF_K_ELF) { |
785 |
/* Silently ignore non-elf member. */ |
794 |
/* Silently ignore non-elf member. */ |
786 |
elf_end(e); |
795 |
elf_end(e); |
787 |
return; |
796 |
return; |
788 |
} |
797 |
} |
789 |
if (elf_getshstrndx(e, &shstrndx) == 0) { |
798 |
if (elf_getshstrndx(e, &shstrndx) == 0) { |
790 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, "elf_getshstrndx failed: %s", |
799 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, "elf_getshstrndx failed: %s", |
791 |
elf_errmsg(-1)); |
800 |
elf_errmsg(-1)); |
792 |
elf_end(e); |
801 |
elf_end(e); |
793 |
return; |
802 |
return; |
794 |
} |
803 |
} |
795 |
|
804 |
|
796 |
tabndx = -1; |
805 |
tabndx = -1; |
797 |
scn = NULL; |
806 |
scn = NULL; |
798 |
while ((scn = elf_nextscn(e, scn)) != NULL) { |
807 |
while ((scn = elf_nextscn(e, scn)) != NULL) { |
799 |
if (gelf_getshdr(scn, &shdr) != &shdr) { |
808 |
if (gelf_getshdr(scn, &shdr) != &shdr) { |
800 |
bsdar_warnc(bsdar, 0, |
809 |
bsdar_warnc(bsdar, 0, |
801 |
"elf_getshdr failed: %s", elf_errmsg(-1)); |
810 |
"elf_getshdr failed: %s", elf_errmsg(-1)); |
802 |
continue; |
811 |
continue; |
803 |
} |
812 |
} |
804 |
if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { |
813 |
if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { |
805 |
bsdar_warnc(bsdar, 0, |
814 |
bsdar_warnc(bsdar, 0, |
806 |
"elf_strptr failed: %s", elf_errmsg(-1)); |
815 |
"elf_strptr failed: %s", elf_errmsg(-1)); |
807 |
continue; |
816 |
continue; |
808 |
} |
817 |
} |
809 |
if (strcmp(name, ".strtab") == 0) { |
818 |
if (strcmp(name, ".strtab") == 0) { |
810 |
tabndx = elf_ndxscn(scn); |
819 |
tabndx = elf_ndxscn(scn); |
811 |
break; |
820 |
break; |
812 |
} |
821 |
} |
813 |
} |
822 |
} |
814 |
elferr = elf_errno(); |
823 |
elferr = elf_errno(); |
815 |
if (elferr != 0) |
824 |
if (elferr != 0) |
816 |
bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s", |
825 |
bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s", |
817 |
elf_errmsg(elferr)); |
826 |
elf_errmsg(elferr)); |
818 |
if (tabndx == -1) { |
827 |
if (tabndx == -1) { |
819 |
bsdar_warnc(bsdar, 0, "can't find .strtab section"); |
828 |
bsdar_warnc(bsdar, 0, "can't find .strtab section"); |
820 |
elf_end(e); |
829 |
elf_end(e); |
821 |
return; |
830 |
return; |
822 |
} |
831 |
} |
823 |
|
832 |
|
824 |
scn = NULL; |
833 |
scn = NULL; |
825 |
while ((scn = elf_nextscn(e, scn)) != NULL) { |
834 |
while ((scn = elf_nextscn(e, scn)) != NULL) { |
826 |
if (gelf_getshdr(scn, &shdr) != &shdr) { |
835 |
if (gelf_getshdr(scn, &shdr) != &shdr) { |
827 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, |
836 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, |
828 |
"elf_getshdr failed: %s", elf_errmsg(-1)); |
837 |
"elf_getshdr failed: %s", elf_errmsg(-1)); |
829 |
continue; |
838 |
continue; |
830 |
} |
839 |
} |
831 |
if (shdr.sh_type != SHT_SYMTAB) |
840 |
if (shdr.sh_type != SHT_SYMTAB) |
832 |
continue; |
841 |
continue; |
833 |
|
842 |
|
834 |
data = NULL; |
843 |
data = NULL; |
835 |
n = 0; |
844 |
n = 0; |
836 |
while (n < shdr.sh_size && |
845 |
while (n < shdr.sh_size && |
837 |
(data = elf_getdata(scn, data)) != NULL) { |
846 |
(data = elf_getdata(scn, data)) != NULL) { |
838 |
len = data->d_size / shdr.sh_entsize; |
847 |
len = data->d_size / shdr.sh_entsize; |
839 |
for (i = 0; i < len; i++) { |
848 |
for (i = 0; i < len; i++) { |
840 |
if (gelf_getsym(data, i, &sym) != &sym) { |
849 |
if (gelf_getsym(data, i, &sym) != &sym) { |
841 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, |
850 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, |
842 |
"gelf_getsym failed: %s", |
851 |
"gelf_getsym failed: %s", |
843 |
elf_errmsg(-1)); |
852 |
elf_errmsg(-1)); |
844 |
continue; |
853 |
continue; |
845 |
} |
854 |
} |
846 |
|
855 |
|
847 |
/* keep only global or weak symbols */ |
856 |
/* keep only global or weak symbols */ |
848 |
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && |
857 |
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && |
849 |
GELF_ST_BIND(sym.st_info) != STB_WEAK) |
858 |
GELF_ST_BIND(sym.st_info) != STB_WEAK) |
850 |
continue; |
859 |
continue; |
851 |
|
860 |
|
852 |
/* keep only defined symbols */ |
861 |
/* keep only defined symbols */ |
853 |
if (sym.st_shndx == SHN_UNDEF) |
862 |
if (sym.st_shndx == SHN_UNDEF) |
854 |
continue; |
863 |
continue; |
855 |
|
864 |
|
856 |
if ((name = elf_strptr(e, tabndx, |
865 |
if ((name = elf_strptr(e, tabndx, |
857 |
sym.st_name)) == NULL) { |
866 |
sym.st_name)) == NULL) { |
858 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, |
867 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, |
859 |
"elf_strptr failed: %s", |
868 |
"elf_strptr failed: %s", |
860 |
elf_errmsg(-1)); |
869 |
elf_errmsg(-1)); |
861 |
continue; |
870 |
continue; |
862 |
} |
871 |
} |
863 |
|
872 |
|
864 |
add_to_ar_sym_table(bsdar, name); |
873 |
add_to_ar_sym_table(bsdar, name); |
865 |
} |
874 |
} |
866 |
} |
875 |
} |
867 |
} |
876 |
} |
868 |
elferr = elf_errno(); |
877 |
elferr = elf_errno(); |
869 |
if (elferr != 0) |
878 |
if (elferr != 0) |
870 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, "elf_nextscn failed: %s", |
879 |
bsdar_warnc(bsdar, EX_SOFTWARE, 0, "elf_nextscn failed: %s", |
871 |
elf_errmsg(elferr)); |
880 |
elf_errmsg(elferr)); |
872 |
|
881 |
|
873 |
elf_end(e); |
882 |
elf_end(e); |
874 |
} |
883 |
} |
875 |
|
884 |
|
876 |
/* |
885 |
/* |
877 |
* Append to the archive string table buffer. |
886 |
* Append to the archive string table buffer. |
878 |
*/ |
887 |
*/ |
879 |
static void |
888 |
static void |
880 |
add_to_ar_str_table(struct bsdar *bsdar, const char *name) |
889 |
add_to_ar_str_table(struct bsdar *bsdar, const char *name) |
881 |
{ |
890 |
{ |
882 |
|
891 |
|
883 |
if (bsdar->as == NULL) { |
892 |
if (bsdar->as == NULL) { |
884 |
bsdar->as_cap = _INIT_AS_CAP; |
893 |
bsdar->as_cap = _INIT_AS_CAP; |
885 |
bsdar->as_sz = 0; |
894 |
bsdar->as_sz = 0; |
886 |
if ((bsdar->as = malloc(bsdar->as_cap)) == NULL) |
895 |
if ((bsdar->as = malloc(bsdar->as_cap)) == NULL) |
887 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
896 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
888 |
} |
897 |
} |
889 |
|
898 |
|
890 |
/* |
899 |
/* |
891 |
* The space required for holding one member name in as table includes: |
900 |
* The space required for holding one member name in as table includes: |
892 |
* strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). |
901 |
* strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). |
893 |
*/ |
902 |
*/ |
894 |
while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) { |
903 |
while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) { |
895 |
bsdar->as_cap *= 2; |
904 |
bsdar->as_cap *= 2; |
896 |
bsdar->as = realloc(bsdar->as, bsdar->as_cap); |
905 |
bsdar->as = realloc(bsdar->as, bsdar->as_cap); |
897 |
if (bsdar->as == NULL) |
906 |
if (bsdar->as == NULL) |
898 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed"); |
907 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed"); |
899 |
} |
908 |
} |
900 |
strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name)); |
909 |
strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name)); |
901 |
bsdar->as_sz += strlen(name); |
910 |
bsdar->as_sz += strlen(name); |
902 |
bsdar->as[bsdar->as_sz++] = '/'; |
911 |
bsdar->as[bsdar->as_sz++] = '/'; |
903 |
bsdar->as[bsdar->as_sz++] = '\n'; |
912 |
bsdar->as[bsdar->as_sz++] = '\n'; |
904 |
} |
913 |
} |
905 |
|
914 |
|
906 |
/* |
915 |
/* |
907 |
* Append to the archive symbol table buffer. |
916 |
* Append to the archive symbol table buffer. |
908 |
*/ |
917 |
*/ |
909 |
static void |
918 |
static void |
910 |
add_to_ar_sym_table(struct bsdar *bsdar, const char *name) |
919 |
add_to_ar_sym_table(struct bsdar *bsdar, const char *name) |
911 |
{ |
920 |
{ |
912 |
|
921 |
|
913 |
if (bsdar->s_so == NULL) { |
922 |
if (bsdar->s_so == NULL) { |
914 |
if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) == |
923 |
if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) == |
915 |
NULL) |
924 |
NULL) |
916 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
925 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
917 |
bsdar->s_so_cap = _INIT_SYMOFF_CAP; |
926 |
bsdar->s_so_cap = _INIT_SYMOFF_CAP; |
918 |
bsdar->s_cnt = 0; |
927 |
bsdar->s_cnt = 0; |
919 |
} |
928 |
} |
920 |
|
929 |
|
921 |
if (bsdar->s_sn == NULL) { |
930 |
if (bsdar->s_sn == NULL) { |
922 |
if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) |
931 |
if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) |
923 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
932 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "malloc failed"); |
924 |
bsdar->s_sn_cap = _INIT_SYMNAME_CAP; |
933 |
bsdar->s_sn_cap = _INIT_SYMNAME_CAP; |
925 |
bsdar->s_sn_sz = 0; |
934 |
bsdar->s_sn_sz = 0; |
926 |
} |
935 |
} |
927 |
|
936 |
|
928 |
if (bsdar->s_cnt * sizeof(uint64_t) >= bsdar->s_so_cap) { |
937 |
if (bsdar->s_cnt * sizeof(uint64_t) >= bsdar->s_so_cap) { |
929 |
bsdar->s_so_cap *= 2; |
938 |
bsdar->s_so_cap *= 2; |
930 |
bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap); |
939 |
bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap); |
931 |
if (bsdar->s_so == NULL) |
940 |
if (bsdar->s_so == NULL) |
932 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed"); |
941 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed"); |
933 |
} |
942 |
} |
934 |
bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off; |
943 |
bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off; |
935 |
if ((uint64_t)bsdar->rela_off > bsdar->s_so_max) |
944 |
if ((uint64_t)bsdar->rela_off > bsdar->s_so_max) |
936 |
bsdar->s_so_max = (uint64_t)bsdar->rela_off; |
945 |
bsdar->s_so_max = (uint64_t)bsdar->rela_off; |
937 |
bsdar->s_cnt++; |
946 |
bsdar->s_cnt++; |
938 |
|
947 |
|
939 |
/* |
948 |
/* |
940 |
* The space required for holding one symbol name in sn table includes: |
949 |
* The space required for holding one symbol name in sn table includes: |
941 |
* strlen(name) + (1 for '\n') + (possibly 1 for padding). |
950 |
* strlen(name) + (1 for '\n') + (possibly 1 for padding). |
942 |
*/ |
951 |
*/ |
943 |
while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) { |
952 |
while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) { |
944 |
bsdar->s_sn_cap *= 2; |
953 |
bsdar->s_sn_cap *= 2; |
945 |
bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap); |
954 |
bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap); |
946 |
if (bsdar->s_sn == NULL) |
955 |
if (bsdar->s_sn == NULL) |
947 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed"); |
956 |
bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed"); |
948 |
} |
957 |
} |
949 |
strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name)); |
958 |
strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name)); |
950 |
bsdar->s_sn_sz += strlen(name); |
959 |
bsdar->s_sn_sz += strlen(name); |
951 |
bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; |
960 |
bsdar->s_sn[bsdar->s_sn_sz++] = '\0'; |
952 |
} |
961 |
} |