|
|
0fb20a |
/*******************************************************************/
|
|
|
0fb20a |
/* slibtool: a skinny libtool implementation, written in C */
|
|
|
49181b |
/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
|
|
|
0fb20a |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
0fb20a |
/*******************************************************************/
|
|
|
0fb20a |
|
|
|
0fb20a |
#include <stdio.h>
|
|
|
0fb20a |
#include <string.h>
|
|
|
0fb20a |
#include <stdbool.h>
|
|
|
0fb20a |
#include <fcntl.h>
|
|
|
0fb20a |
#include <errno.h>
|
|
|
0fb20a |
#include <sys/stat.h>
|
|
|
0fb20a |
|
|
|
0fb20a |
#include <slibtool/slibtool.h>
|
|
|
d58d2f |
#include "slibtool_driver_impl.h"
|
|
|
0fb20a |
#include "slibtool_uninstall_impl.h"
|
|
|
0fb20a |
#include "slibtool_readlink_impl.h"
|
|
|
19022e |
#include "slibtool_snprintf_impl.h"
|
|
|
0fb20a |
#include "slibtool_errinfo_impl.h"
|
|
|
0fb20a |
#include "argv/argv.h"
|
|
|
0fb20a |
|
|
|
0fb20a |
static int slbt_uninstall_usage(
|
|
|
a82cc2 |
int fdout,
|
|
|
0fb20a |
const char * program,
|
|
|
0fb20a |
const char * arg,
|
|
|
d58d2f |
const struct argv_option ** optv,
|
|
|
d4560d |
struct argv_meta * meta,
|
|
|
d4560d |
int noclr)
|
|
|
0fb20a |
{
|
|
|
0fb20a |
char header[512];
|
|
|
0fb20a |
|
|
|
0fb20a |
snprintf(header,sizeof(header),
|
|
|
0fb20a |
"Usage: %s --mode=uninstall <rm> [options] [DEST]...\n"
|
|
|
0fb20a |
"Options:\n",
|
|
|
0fb20a |
program);
|
|
|
0fb20a |
|
|
|
d4560d |
switch (noclr) {
|
|
|
d4560d |
case 0:
|
|
|
2f8d3e |
slbt_argv_usage(fdout,header,optv,arg);
|
|
|
d4560d |
break;
|
|
|
d4560d |
|
|
|
d4560d |
default:
|
|
|
2f8d3e |
slbt_argv_usage_plain(fdout,header,optv,arg);
|
|
|
d4560d |
break;
|
|
|
d4560d |
}
|
|
|
d4560d |
|
|
|
2f8d3e |
slbt_argv_free(meta);
|
|
|
0fb20a |
|
|
|
0fb20a |
return SLBT_USAGE;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
static int slbt_exec_uninstall_fail(
|
|
|
0fb20a |
struct slbt_exec_ctx * actx,
|
|
|
0fb20a |
struct argv_meta * meta,
|
|
|
0fb20a |
int ret)
|
|
|
0fb20a |
{
|
|
|
2f8d3e |
slbt_argv_free(meta);
|
|
|
0fb20a |
slbt_free_exec_ctx(actx);
|
|
|
0fb20a |
return ret;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
static int slbt_exec_uninstall_fs_entry(
|
|
|
0fb20a |
const struct slbt_driver_ctx * dctx,
|
|
|
0fb20a |
struct slbt_exec_ctx * ectx,
|
|
|
0fb20a |
char ** parg,
|
|
|
0fb20a |
char * path,
|
|
|
0fb20a |
uint32_t flags)
|
|
|
0fb20a |
{
|
|
|
0fb20a |
struct stat st;
|
|
|
7ae5c1 |
int fdcwd;
|
|
|
0fb20a |
char * slash;
|
|
|
0fb20a |
char dpath[PATH_MAX];
|
|
|
0fb20a |
|
|
|
7ae5c1 |
/* fdcwd */
|
|
|
7ae5c1 |
fdcwd = slbt_driver_fdcwd(dctx);
|
|
|
7ae5c1 |
|
|
|
0fb20a |
/* needed? */
|
|
|
7ae5c1 |
if (fstatat(fdcwd,path,&st,0) && (errno == ENOENT))
|
|
|
7ae5c1 |
if (fstatat(fdcwd,path,&st,AT_SYMLINK_NOFOLLOW))
|
|
|
7ae5c1 |
if (errno == ENOENT)
|
|
|
7ae5c1 |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
/* output */
|
|
|
0fb20a |
*parg = path;
|
|
|
0fb20a |
|
|
|
0fb20a |
if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT))
|
|
|
0fb20a |
if (slbt_output_uninstall(dctx,ectx))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* directory? */
|
|
|
0fb20a |
if (S_ISDIR(st.st_mode)) {
|
|
|
e524bd |
if (!unlinkat(fdcwd,path,AT_REMOVEDIR))
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
else if ((errno == EEXIST) || (errno == ENOTEMPTY))
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
else
|
|
|
6beda1 |
return SLBT_SYSTEM_ERROR(dctx,path);
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove file or symlink entry */
|
|
|
d38565 |
if (unlinkat(fdcwd,path,0))
|
|
|
6beda1 |
return SLBT_SYSTEM_ERROR(dctx,path);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove empty containing directory? */
|
|
|
0fb20a |
if (flags & SLBT_UNINSTALL_RMDIR) {
|
|
|
0fb20a |
strcpy(dpath,path);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* invalid (current) directory? */
|
|
|
0fb20a |
if (!(slash = strrchr(dpath,'/')))
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
*slash = 0;
|
|
|
0fb20a |
|
|
|
e524bd |
if (unlinkat(fdcwd,dpath,AT_REMOVEDIR))
|
|
|
6beda1 |
return SLBT_SYSTEM_ERROR(dctx,dpath);
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
static int slbt_exec_uninstall_versioned_library(
|
|
|
0fb20a |
const struct slbt_driver_ctx * dctx,
|
|
|
0fb20a |
struct slbt_exec_ctx * ectx,
|
|
|
0fb20a |
char ** parg,
|
|
|
0fb20a |
char * rpath,
|
|
|
0fb20a |
char * lpath,
|
|
|
0fb20a |
const char * suffix,
|
|
|
0fb20a |
uint32_t flags)
|
|
|
0fb20a |
{
|
|
|
0fb20a |
char * slash;
|
|
|
0fb20a |
char * dot;
|
|
|
0fb20a |
char * path;
|
|
|
0fb20a |
char apath[PATH_MAX];
|
|
|
0fb20a |
|
|
|
0fb20a |
/* normalize library link path */
|
|
|
0fb20a |
if (lpath[0] == '/') {
|
|
|
0fb20a |
path = lpath;
|
|
|
0fb20a |
|
|
|
0fb20a |
} else if (!(slash = strrchr(rpath,'/'))) {
|
|
|
0fb20a |
path = lpath;
|
|
|
0fb20a |
|
|
|
0fb20a |
} else {
|
|
|
0fb20a |
strcpy(apath,rpath);
|
|
|
0fb20a |
strcpy(&apath[slash-rpath+1],lpath);
|
|
|
0fb20a |
path = apath;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
/* delete associated version files */
|
|
|
0fb20a |
while ((dot = strrchr(path,'.')) && (strcmp(dot,suffix))) {
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
*dot = 0;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
static int slbt_exec_uninstall_entry(
|
|
|
0fb20a |
const struct slbt_driver_ctx * dctx,
|
|
|
0fb20a |
struct slbt_exec_ctx * ectx,
|
|
|
0fb20a |
struct argv_entry * entry,
|
|
|
0fb20a |
char ** parg,
|
|
|
0fb20a |
uint32_t flags)
|
|
|
0fb20a |
{
|
|
|
c81d16 |
int fdcwd;
|
|
|
c0ac19 |
const char * dsosuffix;
|
|
|
c0ac19 |
char * dot;
|
|
|
c0ac19 |
char path [PATH_MAX];
|
|
|
c0ac19 |
char lpath[PATH_MAX];
|
|
|
0fb20a |
|
|
|
19022e |
if (slbt_snprintf(path,
|
|
|
19022e |
PATH_MAX - 8,
|
|
|
19022e |
"%s",entry->arg) < 0)
|
|
|
0fb20a |
return SLBT_BUFFER_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
*parg = (char *)entry->arg;
|
|
|
0fb20a |
|
|
|
c81d16 |
/* fdcwd */
|
|
|
c81d16 |
fdcwd = slbt_driver_fdcwd(dctx);
|
|
|
c81d16 |
|
|
|
0fb20a |
/* remove explicit argument */
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* non-.la-wrapper argument? */
|
|
|
0fb20a |
if (!(dot = strrchr(path,'.')))
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
else if (strcmp(dot,".la"))
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove .a archive as needed */
|
|
|
0fb20a |
strcpy(dot,".a");
|
|
|
0fb20a |
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
c0ac19 |
/* dsosuffix */
|
|
|
c0ac19 |
dsosuffix = dctx->cctx->settings.dsosuffix;
|
|
|
c0ac19 |
|
|
|
0fb20a |
/* .so symlink? */
|
|
|
c0ac19 |
strcpy(dot,dsosuffix);
|
|
|
0fb20a |
|
|
|
c81d16 |
if (!(slbt_readlinkat(fdcwd,path,lpath,sizeof(lpath))))
|
|
|
0fb20a |
if (slbt_exec_uninstall_versioned_library(
|
|
|
0fb20a |
dctx,ectx,parg,
|
|
|
0fb20a |
path,lpath,
|
|
|
c0ac19 |
dsosuffix,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* .lib.a symlink? */
|
|
|
0fb20a |
strcpy(dot,".lib.a");
|
|
|
0fb20a |
|
|
|
c81d16 |
if (!(slbt_readlinkat(fdcwd,path,lpath,sizeof(lpath))))
|
|
|
0fb20a |
if (slbt_exec_uninstall_versioned_library(
|
|
|
0fb20a |
dctx,ectx,parg,
|
|
|
0fb20a |
path,lpath,
|
|
|
0fb20a |
".lib.a",flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* .dll symlink? */
|
|
|
0fb20a |
strcpy(dot,".dll");
|
|
|
0fb20a |
|
|
|
c81d16 |
if (!(slbt_readlinkat(fdcwd,path,lpath,sizeof(lpath))))
|
|
|
0fb20a |
if (slbt_exec_uninstall_versioned_library(
|
|
|
0fb20a |
dctx,ectx,parg,
|
|
|
0fb20a |
path,lpath,
|
|
|
0fb20a |
".dll",flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove .so library as needed */
|
|
|
c0ac19 |
strcpy(dot,dsosuffix);
|
|
|
0fb20a |
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove .lib.a import library as needed */
|
|
|
0fb20a |
strcpy(dot,".lib.a");
|
|
|
0fb20a |
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove .dll library as needed */
|
|
|
0fb20a |
strcpy(dot,".dll");
|
|
|
0fb20a |
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove .exe image as needed */
|
|
|
0fb20a |
strcpy(dot,".exe");
|
|
|
0fb20a |
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* remove binary image as needed */
|
|
|
0fb20a |
*dot = 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
if (slbt_exec_uninstall_fs_entry(dctx,ectx,parg,path,flags))
|
|
|
0fb20a |
return SLBT_NESTED_ERROR(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
int slbt_exec_uninstall(
|
|
|
0fb20a |
const struct slbt_driver_ctx * dctx,
|
|
|
0fb20a |
struct slbt_exec_ctx * ectx)
|
|
|
0fb20a |
{
|
|
|
0fb20a |
int ret;
|
|
|
a82cc2 |
int fdout;
|
|
|
0fb20a |
char ** argv;
|
|
|
0fb20a |
char ** iargv;
|
|
|
0fb20a |
uint32_t flags;
|
|
|
0fb20a |
struct slbt_exec_ctx * actx;
|
|
|
0fb20a |
struct argv_meta * meta;
|
|
|
0fb20a |
struct argv_entry * entry;
|
|
|
d58d2f |
const struct argv_option * optv[SLBT_OPTV_ELEMENTS];
|
|
|
0fb20a |
|
|
|
0fb20a |
/* dry run */
|
|
|
0fb20a |
if (dctx->cctx->drvflags & SLBT_DRIVER_DRY_RUN)
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
/* context */
|
|
|
0fb20a |
if (ectx)
|
|
|
0fb20a |
actx = 0;
|
|
|
0fb20a |
else if ((ret = slbt_get_exec_ctx(dctx,&ectx)))
|
|
|
0fb20a |
return ret;
|
|
|
0fb20a |
else
|
|
|
0fb20a |
actx = ectx;
|
|
|
0fb20a |
|
|
|
0fb20a |
/* initial state, uninstall mode skin */
|
|
|
0fb20a |
slbt_reset_arguments(ectx);
|
|
|
0fb20a |
slbt_disable_placeholders(ectx);
|
|
|
0fb20a |
iargv = ectx->cargv;
|
|
|
a82cc2 |
fdout = slbt_driver_fdout(dctx);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* missing arguments? */
|
|
|
2f8d3e |
slbt_optv_init(slbt_uninstall_options,optv);
|
|
|
d58d2f |
|
|
|
0fb20a |
if (!iargv[1] && (dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_USAGE))
|
|
|
a82cc2 |
return slbt_uninstall_usage(
|
|
|
a82cc2 |
fdout,
|
|
|
a82cc2 |
dctx->program,
|
|
|
d4560d |
0,optv,0,
|
|
|
d4560d |
dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
|
|
|
0fb20a |
|
|
|
0fb20a |
/* <uninstall> argv meta */
|
|
|
2f8d3e |
if (!(meta = slbt_argv_get(
|
|
|
a82cc2 |
iargv,optv,
|
|
|
0fb20a |
dctx->cctx->drvflags & SLBT_DRIVER_VERBOSITY_ERRORS
|
|
|
0fb20a |
? ARGV_VERBOSITY_ERRORS
|
|
|
93f9e4 |
: ARGV_VERBOSITY_NONE,
|
|
|
a82cc2 |
fdout)))
|
|
|
0fb20a |
return slbt_exec_uninstall_fail(
|
|
|
0fb20a |
actx,meta,
|
|
Kylie McClain |
7ce25c |
SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_UNINSTALL_FAIL));
|
|
|
0fb20a |
|
|
|
0fb20a |
/* dest, alternate argument vector options */
|
|
|
0fb20a |
argv = ectx->altv;
|
|
|
0fb20a |
flags = 0;
|
|
|
0fb20a |
|
|
|
0fb20a |
*argv++ = iargv[0];
|
|
|
0fb20a |
|
|
|
0fb20a |
for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
|
|
|
0fb20a |
if (entry->fopt) {
|
|
|
0fb20a |
switch (entry->tag) {
|
|
|
57ed91 |
case TAG_UNINSTALL_SYSROOT:
|
|
|
57ed91 |
break;
|
|
|
57ed91 |
|
|
|
0fb20a |
case TAG_UNINSTALL_HELP:
|
|
|
0fb20a |
flags |= SLBT_UNINSTALL_HELP;
|
|
|
0fb20a |
break;
|
|
|
0fb20a |
|
|
|
0fb20a |
case TAG_UNINSTALL_VERSION:
|
|
|
0fb20a |
flags |= SLBT_UNINSTALL_VERSION;
|
|
|
0fb20a |
break;
|
|
|
0fb20a |
|
|
|
0fb20a |
case TAG_UNINSTALL_FORCE:
|
|
|
0fb20a |
*argv++ = "-f";
|
|
|
0fb20a |
flags |= SLBT_UNINSTALL_FORCE;
|
|
|
0fb20a |
break;
|
|
|
0fb20a |
|
|
|
0fb20a |
case TAG_UNINSTALL_RMDIR:
|
|
|
0fb20a |
*argv++ = "-d";
|
|
|
0fb20a |
flags |= SLBT_UNINSTALL_RMDIR;
|
|
|
0fb20a |
break;
|
|
|
0fb20a |
|
|
|
0fb20a |
case TAG_UNINSTALL_VERBOSE:
|
|
|
0fb20a |
*argv++ = "-v";
|
|
|
0fb20a |
flags |= SLBT_UNINSTALL_VERBOSE;
|
|
|
0fb20a |
break;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
}
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
/* --help */
|
|
|
0fb20a |
if (flags & SLBT_UNINSTALL_HELP) {
|
|
|
a82cc2 |
slbt_uninstall_usage(
|
|
|
a82cc2 |
fdout,
|
|
|
a82cc2 |
dctx->program,
|
|
|
d4560d |
0,optv,meta,
|
|
|
d4560d |
dctx->cctx->drvflags & SLBT_DRIVER_ANNOTATE_NEVER);
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
}
|
|
|
0fb20a |
|
|
|
0fb20a |
/* uninstall */
|
|
|
0fb20a |
ectx->argv = ectx->altv;
|
|
|
0fb20a |
ectx->program = ectx->altv[0];
|
|
|
0fb20a |
|
|
|
0fb20a |
/* uninstall entries one at a time */
|
|
|
0fb20a |
for (entry=meta->entries; entry->fopt || entry->arg; entry++)
|
|
|
0fb20a |
if (!entry->fopt)
|
|
|
0fb20a |
if (slbt_exec_uninstall_entry(dctx,ectx,entry,argv,flags))
|
|
|
0fb20a |
return slbt_exec_uninstall_fail(
|
|
|
0fb20a |
actx,meta,
|
|
|
0fb20a |
SLBT_NESTED_ERROR(dctx));
|
|
|
0fb20a |
|
|
|
2f8d3e |
slbt_argv_free(meta);
|
|
|
0fb20a |
slbt_free_exec_ctx(actx);
|
|
|
0fb20a |
|
|
|
0fb20a |
return 0;
|
|
|
0fb20a |
}
|