|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <string.h>
|
|
Packit |
8f70b4 |
#ifdef HAVE_DLFCN_H
|
|
Packit |
8f70b4 |
# include <dlfcn.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <stddef.h>
|
|
Packit |
8f70b4 |
#include "module.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "configmake.h"
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifndef RTLD_GLOBAL
|
|
Packit |
8f70b4 |
# define RTLD_GLOBAL 0
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef RTLD_NOW
|
|
Packit |
8f70b4 |
# define DLOPEN_FLAGS RTLD_NOW|RTLD_GLOBAL
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
/* SunOS4 manual says it is reserved and must be 1 */
|
|
Packit |
8f70b4 |
# define DLOPEN_FLAGS 1
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#ifdef RTLD_LAZY
|
|
Packit |
8f70b4 |
# define DLOPEN_FLAGS_LAZY RTLD_LAZY|RTLD_GLOBAL
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# define DLOPEN_FLAGS_LAZY DLOPEN_FLAGS
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
typedef void (*init_t)(int,const char*const*);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* TODO: this can go to a config file. */
|
|
Packit |
8f70b4 |
static const char * const module_aliases[]=
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
"proto-hftp", "proto-http",
|
|
Packit |
8f70b4 |
#if USE_SSL
|
|
Packit |
8f70b4 |
"proto-https", "proto-http",
|
|
Packit |
8f70b4 |
"proto-ftps", "proto-ftp",
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
"cmd-at", "cmd-sleep",
|
|
Packit |
8f70b4 |
"cmd-repeat", "cmd-sleep",
|
|
Packit |
8f70b4 |
NULL
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class lftp_module_info
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
lftp_module_info *next;
|
|
Packit |
8f70b4 |
static lftp_module_info *base;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *path;
|
|
Packit |
8f70b4 |
void *addr;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
lftp_module_info(const char *p,void *a)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
path=xstrdup(p);
|
|
Packit |
8f70b4 |
addr=a;
|
|
Packit |
8f70b4 |
next=base;
|
|
Packit |
8f70b4 |
base=this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
~lftp_module_info()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xfree(path);
|
|
Packit |
8f70b4 |
for(lftp_module_info **scan=&bas;; *scan; scan=&scan[0]->next)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(*scan==this)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*scan=scan[0]->next;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static lftp_module_info *find_module(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int name_len=strlen(name);
|
|
Packit |
8f70b4 |
for(lftp_module_info *scan=base; scan; scan=scan->next)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *slash=strrchr(scan->path,'/');
|
|
Packit |
8f70b4 |
char *scan_name=(slash?slash+1:scan->path);
|
|
Packit |
8f70b4 |
if(!strncmp(scan_name,name,name_len)
|
|
Packit |
8f70b4 |
&& (scan_name[name_len]==0 || !strcmp(&scan_name[name_len],".so")))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return scan;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static void delete_by_name(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
lftp_module_info *m=find_module(name);
|
|
Packit |
8f70b4 |
if(m)
|
|
Packit |
8f70b4 |
delete m;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
lftp_module_info *lftp_module_info::base;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static ResDecl res_mod_path("module:path", PKGLIBDIR "/" VERSION ":" PKGLIBDIR, 0,0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* dlopen can take a file without extension and automatically do the
|
|
Packit |
8f70b4 |
* right thing, however that doesn't fit with this code that tries to
|
|
Packit |
8f70b4 |
* stat before the dlopen call, hence need some help here */
|
|
Packit |
8f70b4 |
#if defined(__MACH__) && defined(__APPLE__)
|
|
Packit |
8f70b4 |
static const char ext[] = ".bundle";
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
static const char ext[] = ".so";
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static int access_so(xstring &fullpath)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int res=access(fullpath,F_OK);
|
|
Packit |
8f70b4 |
if(res==-1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!fullpath.ends_with(ext))
|
|
Packit |
8f70b4 |
fullpath.append(ext);
|
|
Packit |
8f70b4 |
res=access(fullpath,F_OK);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static const char *find_module_alias(const char *path)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *const *scan;
|
|
Packit |
8f70b4 |
for(scan=module_aliases; *scan; scan+=2)
|
|
Packit |
8f70b4 |
if(!strcmp(path,*scan))
|
|
Packit |
8f70b4 |
return scan[1];
|
|
Packit |
8f70b4 |
return path;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void *module_load(const char *path,int argc,const char *const *argv)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef HAVE_DLOPEN
|
|
Packit |
8f70b4 |
void *map;
|
|
Packit |
8f70b4 |
const char *modules_path=res_mod_path.Query(path);
|
|
Packit |
8f70b4 |
xstring fullpath;
|
|
Packit |
8f70b4 |
init_t init;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(strchr(path,'/'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fullpath.set(path);
|
|
Packit |
8f70b4 |
access_so(fullpath);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
path=find_module_alias(path);
|
|
Packit |
8f70b4 |
char *p=alloca_strdup(modules_path);
|
|
Packit |
8f70b4 |
for(p=strtok(p,":"); p; p=strtok(0,":"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fullpath.vset(p,"/",path,NULL);
|
|
Packit |
8f70b4 |
if(access_so(fullpath)==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(p==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
fullpath.vset(PKGLIBDIR,"/",VERSION,"/",path,NULL); // fallback
|
|
Packit |
8f70b4 |
access_so(fullpath);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
map=dlopen(fullpath,DLOPEN_FLAGS); // LAZY?
|
|
Packit |
8f70b4 |
if(map==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
(void)new lftp_module_info(fullpath,map);
|
|
Packit |
8f70b4 |
#if 0 // for some reason this does not work even with LAZY (because of _init?).
|
|
Packit |
8f70b4 |
const char*const*depend=(const char*const*)dlsym(map,"module_depend");
|
|
Packit |
8f70b4 |
if(depend)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(*depend)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(lftp_module_info::find_module(*depend)==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
void *dep=module_load(*depend,0,0);
|
|
Packit |
8f70b4 |
if(!dep)
|
|
Packit |
8f70b4 |
fprintf(stderr,_("depend module `%s': %s\n"),*depend,module_error_message());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
depend++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif //0
|
|
Packit |
8f70b4 |
init=(init_t)dlsym(map,"module_init");
|
|
Packit |
8f70b4 |
if(init)
|
|
Packit |
8f70b4 |
(*init)(argc,argv);
|
|
Packit |
8f70b4 |
return map;
|
|
Packit |
8f70b4 |
#else // !HAVE_DLOPEN
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *module_error_message()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef HAVE_DLOPEN
|
|
Packit |
8f70b4 |
return dlerror();
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
return _("modules are not supported on this system");
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool module_init_preloaded(const char *module)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#if defined(HAVE_DLOPEN) && defined(RTLD_DEFAULT)
|
|
Packit |
8f70b4 |
module=find_module_alias(module);
|
|
Packit |
8f70b4 |
char *init_fn=alloca_strdup2(module,12);
|
|
Packit |
8f70b4 |
// change dashes to underscores in the function name
|
|
Packit |
8f70b4 |
for(char *scan=init_fn; *scan; scan++)
|
|
Packit |
8f70b4 |
if(*scan=='-')
|
|
Packit |
8f70b4 |
*scan='_';
|
|
Packit |
8f70b4 |
strcat(init_fn,"_module_init");
|
|
Packit |
8f70b4 |
init_t init=(init_t)dlsym(RTLD_DEFAULT,init_fn);
|
|
Packit |
8f70b4 |
if(init) {
|
|
Packit |
8f70b4 |
(*init)(0,0);
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|