diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h index 8618e3b..fc29bef 100644 --- a/include/slibtool/slibtool.h +++ b/include/slibtool/slibtool.h @@ -192,6 +192,7 @@ slbt_api void slbt_reset_placeholders (struct slbt_exec_ctx *); slbt_api void slbt_disable_placeholders (struct slbt_exec_ctx *); slbt_api int slbt_exec_compile (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); +slbt_api int slbt_exec_install (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); slbt_api int slbt_exec_link (const struct slbt_driver_ctx *, struct slbt_exec_ctx *); slbt_api int slbt_map_input (int fd, const char * path, int prot, struct slbt_input *); diff --git a/project/common.mk b/project/common.mk index 06b9292..719b6a2 100644 --- a/project/common.mk +++ b/project/common.mk @@ -4,11 +4,13 @@ COMMON_SRCS = \ src/driver/slbt_unit_ctx.c \ src/logic/slbt_exec_compile.c \ src/logic/slbt_exec_ctx.c \ + src/logic/slbt_exec_install.c \ src/logic/slbt_exec_link.c \ src/logic/slbt_map_input.c \ src/output/slbt_output_config.c \ src/output/slbt_output_exec.c \ src/skin/slbt_skin_default.c \ + src/skin/slbt_skin_install.c \ APP_SRCS = \ src/slibtool.c diff --git a/project/headers.mk b/project/headers.mk index 803dbc7..7b036f6 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -5,6 +5,7 @@ API_HEADERS = \ INTERNAL_HEADERS = \ $(PROJECT_DIR)/src/internal/argv/argv.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_driver_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_install_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_spawn_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_symlink_impl.h \ diff --git a/src/internal/slibtool_install_impl.h b/src/internal/slibtool_install_impl.h new file mode 100644 index 0000000..e5741a7 --- /dev/null +++ b/src/internal/slibtool_install_impl.h @@ -0,0 +1,21 @@ +#ifndef SLIBTOOL_INSTALL_IMPL_H +#define SLIBTOOL_INSTALL_IMPL_H + +#include "argv/argv.h" + +extern const struct argv_option slbt_install_options[]; + +enum install_tags { + TAG_INSTALL_HELP, + TAG_INSTALL_COPY, + TAG_INSTALL_MKDIR, + TAG_INSTALL_TARGET_MKDIR, + TAG_INSTALL_STRIP, + TAG_INSTALL_PRESERVE, + TAG_INSTALL_USER, + TAG_INSTALL_GROUP, + TAG_INSTALL_MODE, + TAG_INSTALL_DSTDIR, +}; + +#endif diff --git a/src/logic/slbt_exec_install.c b/src/logic/slbt_exec_install.c new file mode 100644 index 0000000..24b98f8 --- /dev/null +++ b/src/logic/slbt_exec_install.c @@ -0,0 +1,344 @@ +/*******************************************************************/ +/* slibtool: a skinny libtool implementation, written in C */ +/* Copyright (C) 2016 Z. Gilboa */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#include +#include +#include +#include +#include +#include + +#define ARGV_DRIVER + +#include +#include "slibtool_install_impl.h" +#include "slibtool_spawn_impl.h" +#include "slibtool_symlink_impl.h" +#include "argv/argv.h" + +static int slbt_install_usage( + const char * program, + const char * arg, + const struct argv_option * options, + struct argv_meta * meta) +{ + char header[512]; + + snprintf(header,sizeof(header), + "Usage: %s --mode=install [options] [SOURCE]... DEST\n" + "Options:\n", + program); + + argv_usage(stdout,header,options,arg); + argv_free(meta); + + return SLBT_USAGE; +} + +static int slbt_exec_install_fail( + struct slbt_exec_ctx * actx, + struct argv_meta * meta) +{ + argv_free(meta); + slbt_free_exec_ctx(actx); + return -1; +} + +static int slbt_exec_install_init_dstdir( + struct argv_entry * dest, + struct argv_entry * last, + char * dstdir) +{ + char * slash; + size_t len; + + if (dest) + last = dest; + + /* dstdir: initial string */ + if ((size_t)snprintf(dstdir,PATH_MAX,"%s", + last->arg) >= PATH_MAX) + return -1; + + /* dstdir might end with a slash */ + len = strlen(dstdir); + + if (dstdir[--len] == '/') + dstdir[len] = '\0'; + + /* remove last path component */ + if (!dest && (slash = strrchr(dstdir,'/'))) + *slash = '\0'; + + return 0; +} + +static int 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) +{ + int ret; + char * dot; + char * base; + char * slash; + char target [PATH_MAX]; + char srcfile [PATH_MAX]; + char dstfile [PATH_MAX]; + char slnkname[PATH_MAX]; + char dlnkname[PATH_MAX]; + char lasource[PATH_MAX]; + + /* .la ? */ + if (!(dot = strrchr(entry->arg,'.')) || strcmp(dot,".la")) { + *src = (char *)entry->arg; + *dst = dest ? 0 : (char *)last->arg; + + if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) + if (slbt_output_install(dctx,ectx)) + return -1; + + return (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode) + ? -1 : 0; + } + + /* srcfile */ + if (strlen(entry->arg) + strlen(".libs/") >= (PATH_MAX-1)) + return -1; + + strcpy(lasource,entry->arg); + + if ((slash = strrchr(lasource,'/'))) { + *slash++ = '\0'; + sprintf(srcfile,"%s/.libs/%s",lasource,slash); + } else + sprintf(srcfile,".libs/%s",lasource); + + strcpy(slnkname,srcfile); + + /* libfoo.la --> libfoo.so */ + dot = strrchr(slnkname,'.'); + sprintf(dot,dctx->cctx->settings.dsosuffix); + + /* basename */ + if ((base = strrchr(slnkname,'/'))) + base++; + else + base = slnkname; + + /* source (build) symlink target */ + if (readlink(slnkname,target,sizeof(target)) <= 0) + return -1; + + /* srcfile: .libs/libfoo.so.x.y.z */ + slash = strrchr(srcfile,'/'); + strcpy(++slash,target); + + /* dstfile */ + if (!dest) + if ((size_t)snprintf(dstfile,sizeof(dstfile),"%s/%s", + dstdir,target) >= sizeof(dstfile)) + return -1; + + /* spawn */ + *src = srcfile; + *dst = dest ? 0 : dstfile; + + if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) + if (slbt_output_install(dctx,ectx)) + return -1; + + if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode) + return -1; + + /* destination symlink: dstdir/libfoo.so */ + if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s", + dstdir,base) >= sizeof(dlnkname)) + return -1; + + /* create symlink: libfoo.so --> libfoo.so.x.y.z */ + if (slbt_create_symlink( + dctx,ectx, + target,dlnkname, + false)) + return -1; + + /* libfoo.so.x.y.z --> libfoo.so.x */ + strcpy(slnkname,target); + + if ((dot = strrchr(slnkname,'.'))) + *dot = '\0'; + else + return -1; + + if ((dot = strrchr(slnkname,'.'))) + *dot = '\0'; + else + return -1; + + /* destination symlink: dstdir/libfoo.so.x */ + if ((size_t)snprintf(dlnkname,sizeof(dlnkname),"%s/%s", + dstdir,slnkname) >= sizeof(dlnkname)) + return -1; + + /* create symlink: libfoo.so.x --> libfoo.so.x.y.z */ + if (slbt_create_symlink( + dctx,ectx, + target,dlnkname, + false)) + return -1; + + return 0; +} + +int slbt_exec_install( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx) +{ + int ret; + char ** argv; + char ** src; + char ** dst; + struct slbt_exec_ctx * actx; + struct argv_meta * meta; + struct argv_entry * entry; + struct argv_entry * copy; + struct argv_entry * dest; + struct argv_entry * last; + char dstdir[PATH_MAX]; + const struct argv_option * options = slbt_install_options; + + /* context */ + if (ectx) + actx = 0; + else if ((ret = slbt_get_exec_ctx(dctx,&ectx))) + return ret; + else + actx = ectx; + + /* initial state, install mode skin */ + slbt_reset_arguments(ectx); + slbt_disable_placeholders(ectx); + argv = ectx->cargv; + + /* missing arguments? */ + if (!argv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE)) + return slbt_install_usage(dctx->program,0,options,0); + + /* argv meta */ + if (!(meta = argv_get( + argv, + options, + dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS + ? ARGV_VERBOSITY_ERRORS + : ARGV_VERBOSITY_NONE))) + return slbt_exec_install_fail(actx,meta); + + /* dest, alternate argument vector options */ + argv = ectx->altv; + copy = meta->entries; + dest = 0; + last = 0; + + *argv++ = ectx->cargv[0]; + + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_INSTALL_COPY: + *argv++ = "-c"; + copy = entry; + break; + + case TAG_INSTALL_MKDIR: + *argv++ = "-d"; + copy = 0; + break; + + case TAG_INSTALL_TARGET_MKDIR: + *argv++ = "-D"; + copy = 0; + break; + + case TAG_INSTALL_STRIP: + *argv++ = "-s"; + break; + + case TAG_INSTALL_PRESERVE: + *argv++ = "-p"; + break; + + case TAG_INSTALL_USER: + *argv++ = "-o"; + break; + + case TAG_INSTALL_GROUP: + *argv++ = "-g"; + break; + + case TAG_INSTALL_MODE: + *argv++ = "-m"; + break; + + case TAG_INSTALL_DSTDIR: + *argv++ = "-t"; + dest = entry; + break; + } + + if (entry->fval) + *argv++ = (char *)entry->arg; + } else + last = entry; + } + + /* install */ + if (copy) { + /* using alternate argument vector */ + ectx->argv = ectx->altv; + ectx->program = ectx->altv[0]; + + /* marks */ + src = argv++; + dst = argv++; + + /* dstdir */ + if (slbt_exec_install_init_dstdir(dest,last,dstdir)) + return slbt_exec_install_fail(actx,meta); + + /* install entries one at a time */ + for (entry=meta->entries; entry->fopt || entry->arg; entry++) + if (!entry->fopt && (dest || (entry != last))) + if (slbt_exec_install_entry( + dctx,ectx, + entry,last, + dest,dstdir, + src,dst)) + return slbt_exec_install_fail(actx,meta); + } else { + /* using original argument vector */ + ectx->argv = ectx->cargv; + ectx->program = ectx->cargv[0]; + + /* spawn */ + if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) + if (slbt_output_install(dctx,ectx)) + return -1; + + if (((ret = slbt_spawn(ectx,true)) < 0) || ectx->exitcode) + return slbt_exec_install_fail(actx,meta); + } + + argv_free(meta); + slbt_free_exec_ctx(actx); + + return 0; +} diff --git a/src/skin/slbt_skin_install.c b/src/skin/slbt_skin_install.c new file mode 100644 index 0000000..5689b02 --- /dev/null +++ b/src/skin/slbt_skin_install.c @@ -0,0 +1,36 @@ +#include "slibtool_install_impl.h" +#include "argv/argv.h" + +const struct argv_option slbt_install_options[] = { + {"help", 'h',TAG_INSTALL_HELP,ARGV_OPTARG_NONE,0,0,0, + "display install mode help"}, + + {0, 'c',TAG_INSTALL_COPY,ARGV_OPTARG_NONE,0,0,0, + "copy"}, + + {0, 'd',TAG_INSTALL_MKDIR,ARGV_OPTARG_NONE,0,0,0, + "create directories"}, + + {0, 'D',TAG_INSTALL_TARGET_MKDIR,ARGV_OPTARG_NONE,0,0,0, + "create target directories"}, + + {0, 's',TAG_INSTALL_STRIP,ARGV_OPTARG_NONE,0,0,0, + "strip symbols"}, + + {0, 'p',TAG_INSTALL_PRESERVE,ARGV_OPTARG_NONE,0,0,0, + "preserve symbols"}, + + {0, 'o',TAG_INSTALL_USER,ARGV_OPTARG_REQUIRED,0,0,"", + "set %s ownership"}, + + {0, 'g',TAG_INSTALL_GROUP,ARGV_OPTARG_REQUIRED,0,0,"", + "set %s ownership"}, + + {0, 'm',TAG_INSTALL_MODE,ARGV_OPTARG_REQUIRED,0,0,"", + "set permissions to %s"}, + + {0, 't',TAG_INSTALL_DSTDIR,ARGV_OPTARG_REQUIRED,0,0,"", + "install to %s"}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/slibtool.c b/src/slibtool.c index 21b80dc..9ac8ef2 100644 --- a/src/slibtool.c +++ b/src/slibtool.c @@ -30,6 +30,9 @@ static void slibtool_perform_driver_actions(struct slbt_driver_ctx * dctx) if (dctx->cctx->mode == SLBT_MODE_COMPILE) dctx->nerrors += (slbt_exec_compile(dctx,0) < 0); + if (dctx->cctx->mode == SLBT_MODE_INSTALL) + dctx->nerrors += (slbt_exec_install(dctx,0) < 0); + if (dctx->cctx->mode == SLBT_MODE_LINK) dctx->nerrors += (slbt_exec_link(dctx,0) < 0); }