summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormidipix <writeonce@midipix.org>2016-09-24 17:53:54 -0400
committermidipix <writeonce@midipix.org>2016-09-24 19:47:58 -0400
commit0fb20a657d44f0afd5f1feed096cfe434fb6b56f (patch)
tree14dd4fffaf77a6cbfff7182f64dcf32f43b8669b
parentd6e753a79665a44edb2832cb33793914ca549d44 (diff)
downloadslibtool-0fb20a657d44f0afd5f1feed096cfe434fb6b56f.tar.bz2
slibtool-0fb20a657d44f0afd5f1feed096cfe434fb6b56f.tar.xz
uninstall mode: initial implementation.
-rw-r--r--include/slibtool/slibtool.h2
-rw-r--r--project/common.mk2
-rw-r--r--project/headers.mk1
-rw-r--r--src/driver/slbt_amain.c3
-rw-r--r--src/internal/slibtool_uninstall_impl.h25
-rw-r--r--src/logic/slbt_exec_uninstall.c348
-rw-r--r--src/output/slbt_output_exec.c7
-rw-r--r--src/skin/slbt_skin_uninstall.c25
8 files changed, 413 insertions, 0 deletions
diff --git a/include/slibtool/slibtool.h b/include/slibtool/slibtool.h
index d16c16f..3ea06a9 100644
--- a/include/slibtool/slibtool.h
+++ b/include/slibtool/slibtool.h
@@ -261,6 +261,7 @@ slbt_api int slbt_exec_compile (const struct slbt_driver_ctx *, struct slbt_ex
slbt_api int slbt_exec_execute (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_exec_uninstall (const struct slbt_driver_ctx *, struct slbt_exec_ctx *);
slbt_api int slbt_set_alternate_host (const struct slbt_driver_ctx *, const char * host, const char * flavor);
slbt_api void slbt_reset_alternate_host (const struct slbt_driver_ctx *);
@@ -282,6 +283,7 @@ slbt_api int slbt_output_compile (const struct slbt_driver_ctx *, const struct
slbt_api int slbt_output_execute (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *);
slbt_api int slbt_output_install (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *);
slbt_api int slbt_output_link (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *);
+slbt_api int slbt_output_uninstall (const struct slbt_driver_ctx *, const struct slbt_exec_ctx *);
slbt_api int slbt_output_error_record (const struct slbt_driver_ctx *, const struct slbt_error_info *);
slbt_api int slbt_output_error_vector (const struct slbt_driver_ctx *);
diff --git a/project/common.mk b/project/common.mk
index 56121f2..47c5d74 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -14,12 +14,14 @@ COMMON_SRCS = \
src/logic/slbt_exec_execute.c \
src/logic/slbt_exec_install.c \
src/logic/slbt_exec_link.c \
+ src/logic/slbt_exec_uninstall.c \
src/logic/slbt_map_input.c \
src/output/slbt_output_config.c \
src/output/slbt_output_error.c \
src/output/slbt_output_exec.c \
src/skin/slbt_skin_default.c \
src/skin/slbt_skin_install.c \
+ src/skin/slbt_skin_uninstall.c \
APP_SRCS = \
src/slibtool.c
diff --git a/project/headers.mk b/project/headers.mk
index 20fa046..0a518a8 100644
--- a/project/headers.mk
+++ b/project/headers.mk
@@ -12,5 +12,6 @@ INTERNAL_HEADERS = \
$(PROJECT_DIR)/src/internal/$(PACKAGE)_readlink_impl.h \
$(PROJECT_DIR)/src/internal/$(PACKAGE)_spawn_impl.h \
$(PROJECT_DIR)/src/internal/$(PACKAGE)_symlink_impl.h \
+ $(PROJECT_DIR)/src/internal/$(PACKAGE)_uninstall_impl.h \
ALL_HEADERS = $(API_HEADERS) $(INTERNAL_HEADERS)
diff --git a/src/driver/slbt_amain.c b/src/driver/slbt_amain.c
index 8c29e8d..25a1159 100644
--- a/src/driver/slbt_amain.c
+++ b/src/driver/slbt_amain.c
@@ -67,6 +67,9 @@ static void slbt_perform_driver_actions(struct slbt_driver_ctx * dctx)
if (dctx->cctx->mode == SLBT_MODE_LINK)
slbt_exec_link(dctx,0);
+
+ if (dctx->cctx->mode == SLBT_MODE_UNINSTALL)
+ slbt_exec_uninstall(dctx,0);
}
static void slbt_perform_unit_actions(struct slbt_unit_ctx * uctx)
diff --git a/src/internal/slibtool_uninstall_impl.h b/src/internal/slibtool_uninstall_impl.h
new file mode 100644
index 0000000..b78bf37
--- /dev/null
+++ b/src/internal/slibtool_uninstall_impl.h
@@ -0,0 +1,25 @@
+#ifndef SLIBTOOL_UNINSTALL_IMPL_H
+#define SLIBTOOL_UNINSTALL_IMPL_H
+
+#include "argv/argv.h"
+
+extern const struct argv_option slbt_uninstall_options[];
+
+enum uninstall_tags {
+ TAG_UNINSTALL_HELP,
+ TAG_UNINSTALL_VERSION,
+ TAG_UNINSTALL_FORCE,
+ TAG_UNINSTALL_RMDIR,
+ TAG_UNINSTALL_VERBOSE,
+ TAG_UNINSTALL_FORBIDDEN,
+ TAG_UNINSTALL_RECURSIVE = TAG_UNINSTALL_FORBIDDEN,
+};
+
+#define SLBT_UNINSTALL_HELP 0x0001
+#define SLBT_UNINSTALL_VERSION 0x0002
+#define SLBT_UNINSTALL_FORCE 0x0004
+#define SLBT_UNINSTALL_RMDIR 0x0008
+#define SLBT_UNINSTALL_VERBOSE 0x0010
+#define SLBT_UNINSTALL_FORBIDDEN 0x8000
+
+#endif
diff --git a/src/logic/slbt_exec_uninstall.c b/src/logic/slbt_exec_uninstall.c
new file mode 100644
index 0000000..2e54f79
--- /dev/null
+++ b/src/logic/slbt_exec_uninstall.c
@@ -0,0 +1,348 @@
+/*******************************************************************/
+/* slibtool: a skinny libtool implementation, written in C */
+/* Copyright (C) 2016 Z. Gilboa */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#define ARGV_DRIVER
+
+#include <slibtool/slibtool.h>
+#include "slibtool_uninstall_impl.h"
+#include "slibtool_readlink_impl.h"
+#include "slibtool_errinfo_impl.h"
+#include "argv/argv.h"
+
+static int slbt_uninstall_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=uninstall <rm> [options] [DEST]...\n"
+ "Options:\n",
+ program);
+
+ argv_usage(stdout,header,options,arg);
+ argv_free(meta);
+
+ return SLBT_USAGE;
+}
+
+static int slbt_exec_uninstall_fail(
+ struct slbt_exec_ctx * actx,
+ struct argv_meta * meta,
+ int ret)
+{
+ argv_free(meta);
+ slbt_free_exec_ctx(actx);
+ return ret;
+}
+
+static int slbt_exec_uninstall_fs_entry(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ char ** parg,
+ char * path,
+ uint32_t flags)
+{
+ struct stat st;
+ char * slash;
+ char dpath[PATH_MAX];
+
+ /* needed? */
+ if (stat(path,&st) && (errno == ENOENT))
+ if (lstat(path,&st) && (errno == ENOENT))
+ return 0;
+
+ /* output */
+ *parg = path;
+
+ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
+ if (slbt_output_uninstall(dctx,ectx))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* directory? */
+ if (S_ISDIR(st.st_mode)) {
+ if (!(rmdir(path)))
+ return 0;
+
+ else if ((errno == EEXIST) || (errno == ENOTEMPTY))
+ return 0;
+
+ else
+ return SLBT_SYSTEM_ERROR(dctx);
+ }
+
+ /* remove file or symlink entry */
+ if (unlink(path))
+ return SLBT_SYSTEM_ERROR(dctx);
+
+ /* remove empty containing directory? */
+ if (flags & SLBT_UNINSTALL_RMDIR) {
+ strcpy(dpath,path);
+
+ /* invalid (current) directory? */
+ if (!(slash = strrchr(dpath,'/')))
+ return 0;
+
+ *slash = 0;
+
+ if (rmdir(dpath))
+ return SLBT_SYSTEM_ERROR(dctx);
+ }
+
+ return 0;
+}
+
+static int slbt_exec_uninstall_versioned_library(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ char ** parg,
+ char * rpath,
+ char * lpath,
+ const char * suffix,
+ uint32_t flags)
+{
+ char * slash;
+ char * dot;
+ char * path;
+ char apath[PATH_MAX];
+
+ /* normalize library link path */
+ if (lpath[0] == '/') {
+ path = lpath;
+
+ } else if (!(slash = strrchr(rpath,'/'))) {
+ path = lpath;
+
+ } else {
+ strcpy(apath,rpath);
+ strcpy(&apath[slash-rpath+1],lpath);
+ path = apath;
+ }
+
+ /* delete associated version files */
+ while ((dot = strrchr(path,'.')) && (strcmp(dot,suffix))) {
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ *dot = 0;
+ }
+
+ return 0;
+}
+
+static int slbt_exec_uninstall_entry(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx,
+ struct argv_entry * entry,
+ char ** parg,
+ uint32_t flags)
+{
+ char path [PATH_MAX];
+ char lpath[PATH_MAX];
+ char * dot;
+
+ if ((size_t)snprintf(path,PATH_MAX,"%s",
+ entry->arg) >= PATH_MAX-8)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ *parg = (char *)entry->arg;
+
+ /* remove explicit argument */
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* non-.la-wrapper argument? */
+ if (!(dot = strrchr(path,'.')))
+ return 0;
+
+ else if (strcmp(dot,".la"))
+ return 0;
+
+ /* remove .a archive as needed */
+ strcpy(dot,".a");
+
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* .so symlink? */
+ strcpy(dot,".so");
+
+ if (!(slbt_readlink(path,lpath,sizeof(lpath))))
+ if (slbt_exec_uninstall_versioned_library(
+ dctx,ectx,parg,
+ path,lpath,
+ ".so",flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* .lib.a symlink? */
+ strcpy(dot,".lib.a");
+
+ if (!(slbt_readlink(path,lpath,sizeof(lpath))))
+ if (slbt_exec_uninstall_versioned_library(
+ dctx,ectx,parg,
+ path,lpath,
+ ".lib.a",flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* .dll symlink? */
+ strcpy(dot,".dll");
+
+ if (!(slbt_readlink(path,lpath,sizeof(lpath))))
+ if (slbt_exec_uninstall_versioned_library(
+ dctx,ectx,parg,
+ path,lpath,
+ ".dll",flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove .so library as needed */
+ strcpy(dot,".so");
+
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove .lib.a import library as needed */
+ strcpy(dot,".lib.a");
+
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove .dll library as needed */
+ strcpy(dot,".dll");
+
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove .exe image as needed */
+ strcpy(dot,".exe");
+
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* remove binary image as needed */
+ *dot = 0;
+
+ if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
+ return SLBT_NESTED_ERROR(dctx);
+
+ return 0;
+}
+
+int slbt_exec_uninstall(
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_exec_ctx * ectx)
+{
+ int ret;
+ char ** argv;
+ char ** iargv;
+ uint32_t flags;
+ struct slbt_exec_ctx * actx;
+ struct argv_meta * meta;
+ struct argv_entry * entry;
+ const struct argv_option * options = slbt_uninstall_options;
+
+ /* dry run */
+ if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
+ return 0;
+
+ /* context */
+ if (ectx)
+ actx = 0;
+ else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
+ return ret;
+ else
+ actx = ectx;
+
+ /* initial state, uninstall mode skin */
+ slbt_reset_arguments(ectx);
+ slbt_disable_placeholders(ectx);
+ iargv = ectx->cargv;
+
+ /* work around non-conforming uses of --mode=uninstall */
+ if (!(strcmp(iargv[0],"/bin/sh")) || !strcmp(iargv[0],"/bin/bash"))
+ iargv++;
+
+ /* missing arguments? */
+ if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
+ return slbt_uninstall_usage(dctx->program,0,options,0);
+
+ /* <uninstall> argv meta */
+ if (!(meta = argv_get(
+ iargv,
+ options,
+ dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
+ ? ARGV_VERBOSITY_ERRORS
+ : ARGV_VERBOSITY_NONE)))
+ return slbt_exec_uninstall_fail(
+ actx,meta,
+ SLBT_CUSTOM_ERROR(dctx,0));
+
+ /* dest, alternate argument vector options */
+ argv = ectx->altv;
+ flags = 0;
+
+ *argv++ = iargv[0];
+
+ for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
+ if (entry->fopt) {
+ switch (entry->tag) {
+ case TAG_UNINSTALL_HELP:
+ flags |= SLBT_UNINSTALL_HELP;
+ break;
+
+ case TAG_UNINSTALL_VERSION:
+ flags |= SLBT_UNINSTALL_VERSION;
+ break;
+
+ case TAG_UNINSTALL_FORCE:
+ *argv++ = "-f";
+ flags |= SLBT_UNINSTALL_FORCE;
+ break;
+
+ case TAG_UNINSTALL_RMDIR:
+ *argv++ = "-d";
+ flags |= SLBT_UNINSTALL_RMDIR;
+ break;
+
+ case TAG_UNINSTALL_VERBOSE:
+ *argv++ = "-v";
+ flags |= SLBT_UNINSTALL_VERBOSE;
+ break;
+ }
+ }
+ }
+
+ /* --help */
+ if (flags & SLBT_UNINSTALL_HELP) {
+ slbt_uninstall_usage(dctx->program,0,options,meta);
+ return 0;
+ }
+
+ /* uninstall */
+ ectx->argv = ectx->altv;
+ ectx->program = ectx->altv[0];
+
+ /* uninstall entries one at a time */
+ for (entry=meta->entries; entry->fopt || entry->arg; entry++)
+ if (!entry->fopt)
+ if (slbt_exec_uninstall_entry(dctx,ectx,entry,argv,flags))
+ return slbt_exec_uninstall_fail(
+ actx,meta,
+ SLBT_NESTED_ERROR(dctx));
+
+ argv_free(meta);
+ slbt_free_exec_ctx(actx);
+
+ return 0;
+}
diff --git a/src/output/slbt_output_exec.c b/src/output/slbt_output_exec.c
index 6360ca2..7ef4d88 100644
--- a/src/output/slbt_output_exec.c
+++ b/src/output/slbt_output_exec.c
@@ -125,3 +125,10 @@ int slbt_output_link(
{
return slbt_output_exec(dctx,ectx,"link");
}
+
+int slbt_output_uninstall(
+ const struct slbt_driver_ctx * dctx,
+ const struct slbt_exec_ctx * ectx)
+{
+ return slbt_output_exec(dctx,ectx,"uninstall");
+}
diff --git a/src/skin/slbt_skin_uninstall.c b/src/skin/slbt_skin_uninstall.c
new file mode 100644
index 0000000..e34c81e
--- /dev/null
+++ b/src/skin/slbt_skin_uninstall.c
@@ -0,0 +1,25 @@
+#include "slibtool_uninstall_impl.h"
+#include "argv/argv.h"
+
+const struct argv_option slbt_uninstall_options[] = {
+ {"help", 'h',TAG_UNINSTALL_HELP,ARGV_OPTARG_NONE,0,0,0,
+ "display uninstall mode help"},
+
+ {"version", 0,TAG_UNINSTALL_VERSION,ARGV_OPTARG_NONE,0,0,0,
+ "display version information"},
+
+ {"force", 'f',TAG_UNINSTALL_FORCE,ARGV_OPTARG_NONE,0,0,0,
+ "force file removal"},
+
+ {"dir", 'd',TAG_UNINSTALL_RMDIR,ARGV_OPTARG_NONE,0,0,0,
+ "remove empty directories"},
+
+ {"recursive", 'r',TAG_UNINSTALL_RECURSIVE,ARGV_OPTARG_NONE,0,0,0,
+ "remove directories recursively; "
+ "passing this argument to slibtool is forbidden"},
+
+ {"verbose", 'v',TAG_UNINSTALL_VERBOSE,ARGV_OPTARG_NONE,0,0,0,
+ "spray the terminal with colorful information"},
+
+ {0,0,0,0,0,0,0,0}
+};