1 /*******************************************************************/
2 /* slibtool: a skinny libtool implementation, written in C */
3 /* Copyright (C) 2016--2018 Z. Gilboa */
4 /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
5 /*******************************************************************/
6
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdbool.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <sys/stat.h>
14
15 #define ARGV_DRIVER
16
17 #include <slibtool/slibtool.h>
18 #include "slibtool_driver_impl.h"
19 #include "slibtool_install_impl.h"
20 #include "slibtool_mapfile_impl.h"
21 #include "slibtool_readlink_impl.h"
22 #include "slibtool_spawn_impl.h"
23 #include "slibtool_symlink_impl.h"
24 #include "slibtool_errinfo_impl.h"
25 #include "argv/argv.h"
26
slbt_install_usage(int fdout,const char * program,const char * arg,const struct argv_option ** optv,struct argv_meta * meta,int noclr)27 static int slbt_install_usage(
28 int fdout,
29 const char * program,
30 const char * arg,
31 const struct argv_option ** optv,
32 struct argv_meta * meta,
33 int noclr)
34 {
35 char header[512];
36
37 snprintf(header,sizeof(header),
38 "Usage: %s --mode=install <install> [options] [SOURCE]... DEST\n"
39 "Options:\n",
40 program);
41
42 switch (noclr) {
43 case 0:
44 argv_usage(fdout,header,optv,arg);
45 break;
46
47 default:
48 argv_usage_plain(fdout,header,optv,arg);
49 break;
50 }
51
52 argv_free(meta);
53
54 return SLBT_USAGE;
55 }
56
slbt_exec_install_fail(struct slbt_exec_ctx * actx,struct argv_meta * meta,int ret)57 static int slbt_exec_install_fail(
58 struct slbt_exec_ctx * actx,
59 struct argv_meta * meta,
60 int ret)
61 {
62 argv_free(meta);
63 slbt_free_exec_ctx(actx);
64 return ret;
65 }
66
slbt_exec_install_init_dstdir(const struct slbt_driver_ctx * dctx,struct argv_entry * dest,struct argv_entry * last,char * dstdir)67 static int slbt_exec_install_init_dstdir(
68 const struct slbt_driver_ctx * dctx,
69 struct argv_entry * dest,
70 struct argv_entry * last,
71 char * dstdir)
72 {
73 int fdcwd;
74 struct stat st;
75 char * slash;
76 size_t len;
77
78 /* fdcwd */
79 fdcwd = slbt_driver_fdcwd(dctx);
80
81 /* last */
82 if (dest)
83 last = dest;
84
85 /* dstdir: initial string */
86 if ((size_t)snprintf(dstdir,PATH_MAX,"%s",
87 last->arg) >= PATH_MAX)
88 return SLBT_BUFFER_ERROR(dctx);
89
90 /* dstdir might end with a slash */
91 len = strlen(dstdir);
92
93 if (dstdir[--len] == '/')
94 dstdir[len] = 0;
95
96 /* -t DSTDIR? */
97 if (dest)
98 return 0;
99
100 /* is DEST a directory? */
101 if (!fstatat(fdcwd,dstdir,&st,0))
102 if (S_ISDIR(st.st_mode))
103 return 0;
104
105 /* remove last path component */
106 if ((slash = strrchr(dstdir,'/')))
107 *slash = 0;
108
109 return 0;
110 }
111
slbt_exec_install_import_libraries(const struct slbt_driver_ctx * dctx,struct slbt_exec_ctx * ectx,char * srcdso,char * dstdir)112 static int slbt_exec_install_import_libraries(
113 const struct slbt_driver_ctx * dctx,
114 struct slbt_exec_ctx * ectx,
115 char * srcdso,
116 char * dstdir)
117 {
118 char * slash;
119 char * dot;
120 char * mark;
121 char srcbuf [PATH_MAX];
122 char implib [PATH_MAX];
123 char hostlnk[PATH_MAX];
124 char major [128];
125 char minor [128];
126 char rev [128];
127
128 /* .libs/libfoo.so.x.y.z */
129 if ((size_t)snprintf(srcbuf,sizeof(srcbuf),"%s",
130 srcdso) >= sizeof(srcbuf))
131 return SLBT_BUFFER_ERROR(dctx);
132
133 /* (dso is under .libs) */
134 if (!(slash = strrchr(srcbuf,'/')))
135 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
136
137 /* libfoo.so.x.y.z */
138 if ((size_t)snprintf(implib,sizeof(implib),"%s",
139 ++slash) >= sizeof(implib)
140 - strlen(dctx->cctx->settings.impsuffix))
141 return SLBT_BUFFER_ERROR(dctx);
142
143 /* guard against an infinitely long version */
144 mark = srcbuf + strlen(srcbuf);
145
146 if (dctx->cctx->asettings.osdfussix[0]) {
147 if (!(dot = strrchr(srcbuf,'.')))
148 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
149
150 *dot = 0;
151 }
152
153 /* rev */
154 if (!(dot = strrchr(srcbuf,'.')))
155 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
156 else if ((size_t)(mark - dot) > sizeof(rev))
157 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_REV);
158 else {
159 strcpy(rev,dot);
160 *dot = 0;
161 }
162
163 /* minor */
164 if (!(dot = strrchr(srcbuf,'.')))
165 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
166 else if ((size_t)(mark - dot) > sizeof(minor))
167 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_REV);
168 else {
169 strcpy(minor,dot);
170 *dot = 0;
171 }
172
173 /* major */
174 if (!(dot = strrchr(srcbuf,'.')))
175 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
176 else if ((size_t)(mark - dot) > sizeof(major))
177 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_REV);
178 else {
179 strcpy(major,dot);
180 *dot = 0;
181 }
182
183 if (!dctx->cctx->asettings.osdfussix[0])
184 if (!(dot = strrchr(srcbuf,'.')))
185 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
186
187 /* .libs/libfoo.x.y.z.lib.a */
188 sprintf(dot,"%s%s%s%s",
189 major,minor,rev,
190 dctx->cctx->asettings.impsuffix);
191
192 /* copy: .libs/libfoo.x.y.z.lib.a --> dstdir */
193 if (slbt_copy_file(dctx,ectx,srcbuf,dstdir))
194 return SLBT_NESTED_ERROR(dctx);
195
196 /* .libs/libfoo.x.lib.a */
197 sprintf(dot,"%s%s",
198 major,
199 dctx->cctx->asettings.impsuffix);
200
201 /* copy: .libs/libfoo.x.lib.a --> dstdir */
202 if (slbt_copy_file(dctx,ectx,srcbuf,dstdir))
203 return SLBT_NESTED_ERROR(dctx);
204
205 /* /dstdir/libfoo.lib.a */
206 strcpy(implib,slash);
207 strcpy(dot,dctx->cctx->asettings.impsuffix);
208
209 if ((size_t)snprintf(hostlnk,sizeof(hostlnk),"%s/%s",
210 dstdir,slash) >= sizeof(hostlnk))
211 return SLBT_BUFFER_ERROR(dctx);
212
213 if (slbt_create_symlink(
214 dctx,ectx,
215 implib,
216 hostlnk,
217 SLBT_SYMLINK_DEFAULT))
218 return SLBT_NESTED_ERROR(dctx);
219
220 return 0;
221 }
222
slbt_exec_install_library_wrapper(const struct slbt_driver_ctx * dctx,struct slbt_exec_ctx * ectx,struct argv_entry * entry,char * dstdir)223 static int slbt_exec_install_library_wrapper(
224 const struct slbt_driver_ctx * dctx,
225 struct slbt_exec_ctx * ectx,
226 struct argv_entry * entry,
227 char * dstdir)
228 {
229 int fdcwd;
230 int fddst;
231 size_t buflen;
232 const char * base;
233 char * srcline;
234 char * dstline;
235 char clainame[PATH_MAX];
236 char instname[PATH_MAX];
237 char cfgbuf [PATH_MAX];
238 struct slbt_map_info * mapinfo;
239
240 /* base libfoo.la */
241 if ((base = strrchr(entry->arg,'/')))
242 base++;
243 else
244 base = entry->arg;
245
246 /* /dstdir/libfoo.la */
247 if ((size_t)snprintf(instname,sizeof(instname),"%s/%s",
248 dstdir,base) >= sizeof(instname))
249 return SLBT_BUFFER_ERROR(dctx);
250
251 /* libfoo.la.slibtool.install */
252 if ((size_t)snprintf(clainame,sizeof(clainame),"%s.slibtool.install",
253 entry->arg) >= sizeof(clainame))
254 return SLBT_BUFFER_ERROR(dctx);
255
256 /* fdcwd */
257 fdcwd = slbt_driver_fdcwd(dctx);
258
259 /* fddst (libfoo.la.slibtool.install, build directory) */
260 if ((fddst = openat(fdcwd,clainame,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0)
261 return SLBT_SYSTEM_ERROR(dctx,clainame);
262
263 /* mapinfo (libfoo.la, build directory) */
264 if (!(mapinfo = slbt_map_file(fdcwd,entry->arg,SLBT_MAP_INPUT))) {
265 close(fddst);
266 return SLBT_SYSTEM_ERROR(dctx,entry->arg);
267 }
268
269 /* srcline */
270 if (mapinfo->size < sizeof(cfgbuf)) {
271 buflen = sizeof(cfgbuf);
272 srcline = cfgbuf;
273 } else {
274 buflen = mapinfo->size;
275 srcline = malloc(++buflen);
276 }
277
278 if (!srcline) {
279 close(fddst);
280 slbt_unmap_file(mapinfo);
281 return SLBT_SYSTEM_ERROR(dctx,0);
282 }
283
284 /* copy config, installed=no --> installed=yes */
285 while (mapinfo->mark < mapinfo->cap) {
286 if (slbt_mapped_readline(dctx,mapinfo,srcline,buflen) < 0) {
287 close(fddst);
288 slbt_unmap_file(mapinfo);
289 return SLBT_NESTED_ERROR(dctx);
290 }
291
292 dstline = strcmp(srcline,"installed=no\n")
293 ? srcline
294 : "installed=yes\n";
295
296 if (slbt_dprintf(fddst,"%s",dstline) < 0) {
297 close(fddst);
298 slbt_unmap_file(mapinfo);
299 return SLBT_SYSTEM_ERROR(dctx,0);
300 }
301 }
302
303 if (srcline != cfgbuf)
304 free(srcline);
305
306 /* close, unmap */
307 close(fddst);
308 slbt_unmap_file(mapinfo);
309
310 /* cp libfoo.la.slibtool.instal /dstdir/libfoo.la */
311 if (slbt_copy_file(dctx,ectx,clainame,instname))
312 return SLBT_NESTED_ERROR(dctx);
313
314 return 0;
315 }
316
slbt_exec_install_entry(const struct slbt_driver_ctx * dctx,struct slbt_exec_ctx * ectx,struct argv_entry * entry,struct argv_entry * last,struct argv_entry * dest,char * dstdir,char ** src,char ** dst)317 static int slbt_exec_install_entry(
318 const struct slbt_driver_ctx * dctx,
319 struct slbt_exec_ctx * ectx,
320 struct argv_entry * entry,
321 struct argv_entry * last,
322 struct argv_entry * dest,
323 char * dstdir,
324 char ** src,
325 char ** dst)
326 {
327 int ret;
328 int fdcwd;
329 const char * base;
330 char * dot;
331 char * host;
332 char * mark;
333 char * slash;
334 char * suffix;
335 char * dsosuffix;
336 char sobuf [64];
337 char target [PATH_MAX];
338 char srcfile [PATH_MAX];
339 char dstfile [PATH_MAX];
340 char slnkname[PATH_MAX];
341 char dlnkname[PATH_MAX];
342 char hosttag [PATH_MAX];
343 char lasource[PATH_MAX - 8];
344 bool fexe = false;
345 bool fpe;
346 bool frelease;
347 bool fdualver;
348 bool fstatic;
349 bool farchive;
350 size_t slen;
351 size_t dlen;
352 struct stat st;
353
354 /* executable wrapper? */
355 base = (slash = strrchr(entry->arg,'/'))
356 ? ++slash : entry->arg;
357
358 strcpy(slnkname,entry->arg);
359 mark = &slnkname[base - entry->arg];
360 slen = sizeof(slnkname) - (mark - slnkname);
361
362 if ((size_t)snprintf(mark,slen,
363 ".libs/%s.exe.wrapper",
364 base) >= slen)
365 return SLBT_BUFFER_ERROR(dctx);
366
367 /* fdcwd */
368 fdcwd = slbt_driver_fdcwd(dctx);
369
370 /* fexe */
371 fexe = !fstatat(fdcwd,slnkname,&st,0);
372
373 /* argument suffix */
374 dot = strrchr(entry->arg,'.');
375
376 /* .lai --> .la */
377 if (!fexe && dot && !strcmp(dot,".lai"))
378 dot[3] = 0;
379
380 /* srcfile */
381 if (strlen(entry->arg) + strlen(".libs/") >= (PATH_MAX-1))
382 return SLBT_BUFFER_ERROR(dctx);
383
384 strcpy(lasource,entry->arg);
385
386 if ((slash = strrchr(lasource,'/'))) {
387 *slash++ = 0;
388 sprintf(srcfile,"%s/.libs/%s",lasource,slash);
389 } else {
390 sprintf(srcfile,".libs/%s",lasource);
391 }
392
393 /* executable? ordinary file? */
394 if (fexe || !dot || strcmp(dot,".la")) {
395 *src = fexe ? srcfile : (char *)entry->arg;
396 *dst = dest ? 0 : (char *)last->arg;
397
398 if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
399 if (slbt_output_install(dctx,ectx))
400 return SLBT_NESTED_ERROR(dctx);
401
402 return (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
403 ? SLBT_SPAWN_ERROR(dctx) : 0;
404 }
405
406 /* -shrext, dsosuffix */
407 strcpy(sobuf,dctx->cctx->settings.dsosuffix);
408 dsosuffix = sobuf;
409
410 if ((size_t)snprintf(slnkname,sizeof(slnkname),"%s.shrext",
411 srcfile) >= sizeof(slnkname))
412 return SLBT_BUFFER_ERROR(dctx);
413
414 if (!fstatat(fdcwd,slnkname,&st,0)) {
415 if (slbt_readlinkat(fdcwd,slnkname,target,sizeof(target)) < 0)
416 return SLBT_SYSTEM_ERROR(dctx,slnkname);
417
418 if (strncmp(lasource,target,(slen = strlen(lasource))))
419 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
420
421 if (strncmp(&target[slen],".shrext",7))
422 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
423
424 strcpy(sobuf,&target[slen+7]);
425 }
426
427 /* legabits? */
428 if (dctx->cctx->drvflags & SLBT_DRIVER_LEGABITS)
429 if (slbt_exec_install_library_wrapper(dctx,ectx,entry,dstdir))
430 return SLBT_NESTED_ERROR(dctx);
431
432 /* *dst: consider: cp libfoo.la /dest/dir/libfoo.la */
433 if ((*dst = dest ? 0 : (char *)last->arg))
434 if ((dot = strrchr(last->arg,'.')))
435 if (!(strcmp(dot,".la")))
436 *dst = dstdir;
437
438 /* libfoo.a */
439 dot = strrchr(srcfile,'.');
440 strcpy(dot,dctx->cctx->settings.arsuffix);
441
442 /* dot/suffix */
443 strcpy(slnkname,srcfile);
444 dot = strrchr(slnkname,'.');
445
446 /* .libs/libfoo.so.def.host */
447 slen = sizeof(slnkname);
448 slen -= (dot - slnkname);
449
450 /* detect -release, exclusively or alongside -version-info */
451 frelease = false;
452 fdualver = false;
453 fstatic = false;
454 fpe = false;
455
456 /* static library only? */
457 sprintf(dot,"%s",dsosuffix);
458 fstatic = slbt_symlink_is_a_placeholder(fdcwd,slnkname);
459
460 /* libfoo.a --> libfoo.so.release */
461 if (!fstatic) {
462 sprintf(dot,"%s.release",dsosuffix);
463 frelease = !fstatat(fdcwd,slnkname,&st,0);
464 }
465
466 /* libfoo.a --> libfoo.so.dualver */
467 if (!fstatic && !frelease) {
468 sprintf(dot,"%s.dualver",dsosuffix);
469 fdualver = !fstatat(fdcwd,slnkname,&st,0);
470 }
471
472 /* libfoo.so.def.{flavor} */
473 if (fstatic) {
474 (void)0;
475
476 } else if (frelease || fdualver) {
477 strcpy(dlnkname,slnkname);
478 slash = strrchr(dlnkname,'/');
479
480 dlen = sizeof(dlnkname);
481 dlen -= (++slash - dlnkname);
482 dlen -= 9;
483
484 if (slbt_readlinkat(fdcwd,slnkname,slash,dlen))
485 return SLBT_SYSTEM_ERROR(dctx,slnkname);
486
487 if (fdualver) {
488 /* remove .patch */
489 if (!(mark = strrchr(dlnkname,'.')))
490 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
491
492 *mark = 0;
493
494 /* remove .minor */
495 if (!(mark = strrchr(dlnkname,'.')))
496 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
497
498 *mark = 0;
499
500 /* remove .major */
501 if (!(mark = strrchr(dlnkname,'.')))
502 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
503 } else {
504 mark = slash += strlen(slash);
505 }
506
507 strcpy(mark,".def.host");
508
509 if (slbt_readlinkat(fdcwd,dlnkname,hosttag,sizeof(hosttag)))
510 return SLBT_SYSTEM_ERROR(dctx,slnkname);
511 } else {
512 if ((size_t)snprintf(dot,slen,"%s.def.host",dsosuffix) >= slen)
513 return SLBT_BUFFER_ERROR(dctx);
514
515 if (slbt_readlinkat(fdcwd,frelease ? dlnkname : slnkname,hosttag,sizeof(hosttag)))
516 return SLBT_SYSTEM_ERROR(dctx,slnkname);
517 }
518
519 /* host/flabor */
520 if (fstatic) {
521 (void)0;
522
523 } else if (!(host = strrchr(hosttag,'.'))) {
524 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
525 } else {
526 host++;
527 }
528
529 /* symlink-based alternate host */
530 if (!fstatic) {
531 if (slbt_set_alternate_host(dctx,host,host))
532 return SLBT_NESTED_ERROR(dctx);
533
534 fpe = !strcmp(dctx->cctx->asettings.imagefmt,"pe");
535 }
536
537 /* libfoo.a --> libfoo.so */
538 strcpy(dot,dsosuffix);
539
540 /* libfoo.a installation */
541 if (!(dctx->cctx->drvflags & SLBT_DRIVER_DISABLE_STATIC))
542 farchive = true;
543 else if (fstatic)
544 farchive = true;
545 else
546 farchive = false;
547
548 if (farchive)
549 if (slbt_copy_file(dctx,ectx,
550 srcfile,
551 dest ? (char *)dest->arg : *dst))
552 return SLBT_NESTED_ERROR(dctx);
553
554 /* basename */
555 if ((base = strrchr(slnkname,'/')))
556 base++;
557 else
558 base = slnkname;
559
560 /* source (build) symlink target */
561 if (slbt_readlinkat(fdcwd,slnkname,target,sizeof(target)) < 0) {
562 /* -all-static? */
563 if (fstatic)
564 return 0;
565
566 /* -avoid-version? */
567 if (fstatat(fdcwd,slnkname,&st,0))
568 return SLBT_SYSTEM_ERROR(dctx,slnkname);
569
570 /* dstfile */
571 if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s",
572 dstdir,base) >= sizeof(dstfile))
573 return SLBT_BUFFER_ERROR(dctx);
574
575 /* single spawn, no symlinks */
576 *src = slnkname;
577 *dst = dest ? 0 : dstfile;
578
579 if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
580 if (slbt_output_install(dctx,ectx))
581 return SLBT_NESTED_ERROR(dctx);
582
583 if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
584 return SLBT_SPAWN_ERROR(dctx);
585
586 return 0;
587 }
588
589 /* srcfile: .libs/libfoo.so.x.y.z */
590 slash = strrchr(srcfile,'/');
591 strcpy(++slash,target);
592
593 /* dstfile */
594 if (!dest)
595 if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s",
596 dstdir,target) >= sizeof(dstfile))
597 return SLBT_BUFFER_ERROR(dctx);
598
599 /* spawn */
600 *src = srcfile;
601 *dst = dest ? 0 : dstfile;
602
603 if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
604 if (slbt_output_install(dctx,ectx))
605 return SLBT_NESTED_ERROR(dctx);
606
607 if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
608 return SLBT_SPAWN_ERROR(dctx);
609
610 /* destination symlink: dstdir/libfoo.so */
611 if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s",
612 dstdir,base) >= sizeof(dlnkname))
613 return SLBT_BUFFER_ERROR(dctx);
614
615 /* create symlink: libfoo.so --> libfoo.so.x.y.z */
616 if (slbt_create_symlink(
617 dctx,ectx,
618 target,dlnkname,
619 SLBT_SYMLINK_DEFAULT))
620 return SLBT_NESTED_ERROR(dctx);
621
622 if (frelease)
623 return 0;
624
625 /* libfoo.so.x --> libfoo.so.x.y.z */
626 strcpy(slnkname,target);
627
628 if ((suffix = strrchr(slnkname,'.')))
629 *suffix++ = 0;
630 else
631 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
632
633 if ((dot = strrchr(slnkname,'.')))
634 *dot++ = 0;
635 else
636 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
637
638 if ((*dot < '0') || (*dot > '9'))
639 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
640
641 /* libfoo.x.y.z.so? */
642 if ((suffix[0] < '0') || (suffix[0] > '9')) {
643 if ((dot = strrchr(slnkname,'.')))
644 dot++;
645 else
646 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
647
648 if ((*dot < '0') || (*dot > '9'))
649 return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FLOW);
650
651 for (; *suffix; )
652 *dot++ = *suffix++;
653
654 *dot++ = 0;
655 }
656
657 /* destination symlink: dstdir/libfoo.so.x */
658 if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s",
659 dstdir,slnkname) >= sizeof(dlnkname))
660 return SLBT_BUFFER_ERROR(dctx);
661
662 if (fpe) {
663 /* copy: .libs/libfoo.so.x.y.z --> libfoo.so.x */
664 if (slbt_copy_file(
665 dctx,ectx,
666 srcfile,
667 dlnkname))
668 return SLBT_NESTED_ERROR(dctx);
669
670 /* import libraries */
671 if (slbt_exec_install_import_libraries(
672 dctx,ectx,
673 srcfile,
674 dstdir))
675 return SLBT_NESTED_ERROR(dctx);
676 } else {
677 /* create symlink: libfoo.so.x --> libfoo.so.x.y.z */
678 if (slbt_create_symlink(
679 dctx,ectx,
680 target,dlnkname,
681 SLBT_SYMLINK_DEFAULT))
682 return SLBT_NESTED_ERROR(dctx);
683 }
684
685 return 0;
686 }
687
slbt_exec_install(const struct slbt_driver_ctx * dctx,struct slbt_exec_ctx * ectx)688 int slbt_exec_install(
689 const struct slbt_driver_ctx * dctx,
690 struct slbt_exec_ctx * ectx)
691 {
692 int ret;
693 int fdout;
694 char ** argv;
695 char ** iargv;
696 char ** src;
697 char ** dst;
698 char * slash;
699 char * optsh;
700 char * script;
701 char * shtool;
702 struct slbt_exec_ctx * actx;
703 struct argv_meta * meta;
704 struct argv_entry * entry;
705 struct argv_entry * copy;
706 struct argv_entry * dest;
707 struct argv_entry * last;
708 const struct argv_option * optv[SLBT_OPTV_ELEMENTS];
709 char dstdir[PATH_MAX];
710
711 /* dry run */
712 if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
713 return 0;
714
715 /* context */
716 if (ectx)
717 actx = 0;
718 else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
719 return ret;
720 else
721 actx = ectx;
722
723 /* initial state, install mode skin */
724 slbt_reset_arguments(ectx);
725 slbt_disable_placeholders(ectx);
726 iargv = ectx->cargv;
727 fdout = slbt_driver_fdout(dctx);
728 optsh = 0;
729 script = 0;
730
731 /* work around non-conforming uses of --mode=install */
732 if (iargv[1] && (slash = strrchr(iargv[1],'/'))) {
733 if (!strcmp(++slash,"install-sh")) {
734 optsh = *iargv++;
735 script = *iargv;
736 }
737 } else {
738 slash = strrchr(iargv[0],'/');
739 shtool = slash ? ++slash : iargv[0];
740 shtool = strcmp(shtool,"shtool") ? 0 : shtool;
741
742 if (shtool && iargv[1] && !strcmp(iargv[1],"install")) {
743 iargv++;
744 } else if (shtool) {
745 return slbt_install_usage(
746 fdout,
747 dctx->program,
748 0,optv,0,
749 dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
750 }
751 }
752
753 /* missing arguments? */
754 argv_optv_init(slbt_install_options,optv);
755
756 if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
757 return slbt_install_usage(
758 fdout,
759 dctx->program,
760 0,optv,0,
761 dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
762
763 /* <install> argv meta */
764 if (!(meta = argv_get(
765 iargv,optv,
766 dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
767 ? ARGV_VERBOSITY_ERRORS
768 : ARGV_VERBOSITY_NONE,
769 fdout)))
770 return slbt_exec_install_fail(
771 actx,meta,
772 SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_INSTALL_FAIL));
773
774 /* dest, alternate argument vector options */
775 argv = ectx->altv;
776 copy = meta->entries;
777 dest = 0;
778 last = 0;
779
780 if (optsh)
781 *argv++ = script;
782
783 *argv++ = iargv[0];
784
785 for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
786 if (entry->fopt) {
787 switch (entry->tag) {
788 case TAG_INSTALL_SYSROOT:
789 break;
790
791 case TAG_INSTALL_COPY:
792 *argv++ = "-c";
793 copy = entry;
794 break;
795
796 case TAG_INSTALL_FORCE:
797 *argv++ = "-f";
798 break;
799
800 case TAG_INSTALL_MKDIR:
801 *argv++ = "-d";
802 copy = 0;
803 break;
804
805 case TAG_INSTALL_TARGET_MKDIR:
806 *argv++ = "-D";
807 copy = 0;
808 break;
809
810 case TAG_INSTALL_STRIP:
811 *argv++ = "-s";
812 break;
813
814 case TAG_INSTALL_PRESERVE:
815 *argv++ = "-p";
816 break;
817
818 case TAG_INSTALL_USER:
819 *argv++ = "-o";
820 break;
821
822 case TAG_INSTALL_GROUP:
823 *argv++ = "-g";
824 break;
825
826 case TAG_INSTALL_MODE:
827 *argv++ = "-m";
828 break;
829
830 case TAG_INSTALL_DSTDIR:
831 *argv++ = "-t";
832 dest = entry;
833 break;
834 }
835
836 if (entry->tag == TAG_INSTALL_SYSROOT) {
837 (void)0;
838
839 } else if (entry->fval) {
840 *argv++ = (char *)entry->arg;
841 }
842 } else
843 last = entry;
844 }
845
846 /* install */
847 if (copy) {
848 /* using alternate argument vector */
849 if (optsh)
850 ectx->altv[0] = optsh;
851
852 ectx->argv = ectx->altv;
853 ectx->program = ectx->altv[0];
854
855 /* marks */
856 src = argv++;
857 dst = argv++;
858
859 /* dstdir */
860 if (slbt_exec_install_init_dstdir(dctx,dest,last,dstdir))
861 return slbt_exec_install_fail(
862 actx,meta,
863 SLBT_NESTED_ERROR(dctx));
864
865 /* install entries one at a time */
866 for (entry=meta->entries; entry->fopt || entry->arg; entry++)
867 if (!entry->fopt && (dest || (entry != last)))
868 if (slbt_exec_install_entry(
869 dctx,ectx,
870 entry,last,
871 dest,dstdir,
872 src,dst))
873 return slbt_exec_install_fail(
874 actx,meta,
875 SLBT_NESTED_ERROR(dctx));
876 } else {
877 /* using original argument vector */
878 ectx->argv = ectx->cargv;
879 ectx->program = ectx->cargv[0];
880
881 /* spawn */
882 if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
883 if (slbt_output_install(dctx,ectx))
884 return SLBT_NESTED_ERROR(dctx);
885
886 if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode)
887 return slbt_exec_install_fail(
888 actx,meta,
889 SLBT_SPAWN_ERROR(dctx));
890 }
891
892 argv_free(meta);
893 slbt_free_exec_ctx(actx);
894
895 return 0;
896 }
897