This is a proposal to add a --migrate_new_server option which
if set activates the migration feature which works as described below.
Earlier versions of this code have been used in production.
This up-port to perdition-1.19-rc2 has been lightly tested.
Feedback on both the code and the feature are very welcome.
0. Accept the user-name and password from the end-user
(this is part perdition's normal behaviour)
1. Check a local key-value GDBM database,
/etc/perdition/migrate.db
This database tracks the migration status of users.
If the user is present in the database and their
status is done, then perdition will skip to step 7.
Otherwise the use will be migrated using steps 3 - 6.
3. Log the user into the existing mail server
as per usual perdition settings - either the
server returned by a popmap or set by --outgoing_server.
If this fails, the user will be disconnected.
The purpose of this step is to verify the
username and password provided.
4. Run the perdition perdition-migrate-adduser script.
By default this creates a new account with the
supplied username obtained in step 1).
This is a script so that it can easily be customized.
It may also be replaced with any program that accepts
a username as its only argument.
5. Run the perdition-migrate-passwd script.
By default this sets a password on the account for username
where password and username are obtained in step 1).
Again, this is a script so that it can easily be customized.
It may also be replaced with any program that accepts
a username:password from stdin and no arguments.
This script may also be used to migrate mail as needed.
N.B: Steps 4 and 5 could be combined into a single step,
or a new migrate-mail step could be added.
6. Mark the user as having being migrated in the DB that
was checked in step 2.
* Actually, the progress is recorded such
that if, for example 4) succeeds but then 5) fails
then the migration can skip step 4 the next time.
7. Log the user into the machine specified by migrate_new_server.
A limitation is that a popmap lookup doesn't occur here.
I think that this could be resolved by adding --migrate_new_map_library
and --migrate_new_map_library_opt options. Though I suspect that
the code-changes would be non-trivial.
Documentation similar to the above needs to be incorporated
into perdition(8) or elsewhere.
Signed-off-by: Simon Horman <horms(a)verge.net.au>
Index: perdition/configure.ac
===================================================================
--- perdition.orig/configure.ac 2010-07-19 19:21:52.000000000 +0900
+++ perdition/configure.ac 2010-07-19 19:32:24.000000000 +0900
@@ -1141,6 +1141,9 @@ perdition/db/ldap/doc/Makefile
perdition/db/odbc/Makefile
perdition/db/daemon/Makefile
perdition/db/daemon/lib/Makefile
+migrate/Makefile
+migrate/bin/Makefile
+migrate/lib/Makefile
makegdbm/Makefile
makebdb/Makefile
etc/Makefile
Index: perdition/etc/perdition/perdition.conf
===================================================================
--- perdition.orig/etc/perdition/perdition.conf 2010-07-19 19:21:52.000000000 +0900
+++ perdition/etc/perdition/perdition.conf 2010-07-19 19:26:43.000000000 +0900
@@ -403,3 +403,18 @@
# to connect to the server.
#ssl_no_cn_verify
+######################################################################
+# Options below relate to migrate extensions
+# They are not available if perdition is compiled without the
+# migration feature
+######################################################################
+
+# migrate_configured:
+# Enable the migration feature
+migrate_enabled
+
+# migrate_new_server SERVER:
+# Server to send users to after migration.
+# Same format as the --outgoing_server option
+# (default "")
+migrate_new_server localhost
Index: perdition/perdition/options.c
===================================================================
--- perdition.orig/perdition/options.c 2010-07-19 19:21:52.000000000 +0900
+++ perdition/perdition/options.c 2010-07-19 19:26:43.000000000 +0900
@@ -342,6 +342,16 @@ opt_err_digit(flag_t f, poptContext cont
#endif /* WITH_SSL_SUPPORT */
+#define NO_MIGRATE_OPT(_opt) \
+ VANESSA_LOGGER_DEBUG_RAW(_opt \
+ " is only supported when migrate extensions are compiled in"); \
+ if(f&OPT_ERR){ \
+ usage(-1); \
+ } \
+ else{ \
+ poptFreeContext(context); \
+ return(-1); \
+ }
/**********************************************************************
* options
@@ -446,6 +456,8 @@ int options(int argc, char **argv, flag_
TAG_LOGIN_DISABLED, NULL, NULL},
{"lower_case", '\0', POPT_ARG_STRING, NULL,
TAG_LOWER_CASE, NULL, NULL},
+ {"migrate_new_server", '\0', POPT_ARG_STRING, NULL,
+ TAG_MIGRATE_NEW_SERVER, NULL, NULL},
{"pid_file", '\0', POPT_ARG_STRING, NULL,
TAG_PID_FILE, NULL, NULL},
{"no_daemon", '\0', POPT_ARG_NONE, NULL,
@@ -539,8 +551,8 @@ int options(int argc, char **argv, flag_
opt_i(&(opt.tcp_keepalive), DEFAULT_TCP_KEEPALIVE, &i, 0, OPT_NOT_SET);
opt_i(&(opt.login_disabled), DEFAULT_LOGIN_DISABLED, &i, 0, OPT_NOT_SET);
opt_i(&(opt.lower_case), DEFAULT_LOWER_CASE, &i, 0, OPT_NOT_SET);
- opt_i(&(opt.server_resp_line), DEFAULT_SERVER_RESP_LINE,
- &i, 0, OPT_NOT_SET);
+ opt_da(&(opt.migrate_new_server), DEFAULT_MIGRATE_NEW_SERVER,
+ &i, 0, OPT_NOT_SET);
opt_i(&(opt.strip_domain), DEFAULT_STRIP_DOMAIN, &i, 0, OPT_NOT_SET);
opt_i(&(opt.timeout), DEFAULT_TIMEOUT, &i, 0, OPT_NOT_SET);
opt_i(&(opt.username_from_database), DEFAULT_USERNAME_FROM_DATABASE,
@@ -833,6 +845,16 @@ int options(int argc, char **argv, flag_
}
OPT_LOWER_CASE;
break;
+ case TAG_MIGRATE_NEW_SERVER:
+ if(options_set_mask(&(opt.mask2), f, MASK2_MIGRATE_NEW_SERVER)){
+ if(!(f&OPT_NOT_SET) && opt.migrate_new_server) {
+ vanessa_dynamic_array_destroy(opt.migrate_new_server);
+ }
+ OPTARG_DUP;
+ opt.migrate_new_server = split_str_server_port(optarg_copy,
+ OPT_SERVER_DELIMITER);
+ }
+ break;
case TAG_QUERY_KEY:
if(options_set_mask(&(opt.mask), f, MASK_QUERY_KEY)){
if(!(f&OPT_NOT_SET) && opt.query_key!=NULL) {
@@ -1156,6 +1178,7 @@ static char *log_options_head_str(void)
static char *log_options_non_ssl_str(void)
{
int status = -1;
+ char *migrate_new_server = NULL;
char *out = NULL;
char *protocol=NULL;
char *outgoing_server=NULL;
@@ -1171,6 +1194,15 @@ static char *log_options_non_ssl_str(voi
return NULL;
}
+ if (opt.migrate_new_server) {
+ migrate_new_server = vanessa_dynamic_array_display(
+ opt.migrate_new_server, OPT_SERVER_DELIMITER);
+ if (!migrate_new_server) {
+ VANESSA_LOGGER_DEBUG("vanessa_dynamic_array_display");
+ goto err;
+ }
+ }
+
if((protocol=protocol_list(protocol, NULL, opt.protocol))==NULL){
VANESSA_LOGGER_DEBUG("protocol_list");
goto err;
@@ -1186,6 +1218,16 @@ static char *log_options_non_ssl_str(voi
}
}
+ if(opt.outgoing_server!=NULL){
+ if((outgoing_server=vanessa_dynamic_array_display(
+ opt.outgoing_server,
+ OPT_SERVER_DELIMITER
+ ))==NULL){
+ VANESSA_LOGGER_DEBUG("vanessa_dynamic_array_display");
+ goto err;
+ }
+ }
+
if(opt.bind_address!=NULL){
if((bind_address=vanessa_dynamic_array_display(
opt.bind_address,
@@ -1241,6 +1283,7 @@ static char *log_options_non_ssl_str(voi
"log_passwd=\"%s\", "
"login_disabled=%s, "
"lower_case=\"%s\", "
+ "migrate_new_server=\"%s\", "
"managesieve_capability=\"%s\", "
"map_library=\"%s\", "
"map_library_opt=\"%s\", "
@@ -1285,6 +1328,7 @@ static char *log_options_non_ssl_str(voi
OPT_STR(log_passwd_to_str(opt.log_passwd)),
BIN_OPT_STR(opt.login_disabled),
OPT_STR(lower_case),
+ OPT_STR(migrate_new_server),
OPT_STR(opt.managesieve_capability),
OPT_STR(opt.map_library),
OPT_STR(opt.map_library_opt),
@@ -1316,6 +1360,7 @@ err:
str_free(out);
out = NULL;
}
+ str_free(outgoing_server);
str_free(protocol);
str_free(outgoing_server);
str_free(bind_address);
@@ -1601,6 +1646,10 @@ void usage(int exit_status){
" --lower_case STATE[,STATE...]:\n"
" Convert usernames to lower case according the the locale in given\n"
" state(s). (default \"\")\n"
+ " --migrate_new_server SERVER:\n"
+ " Server to send users to after migration.\n"
+ " Same format as the --outgoing_server option\n"
+ " (default \"%s\")\n"
" --managesieve_capability STRING:\n"
" Capabilities for managesieve.\n"
" (default \"%s\")\n"
@@ -1732,6 +1781,7 @@ void usage(int exit_status){
DEFAULT_CONNECTION_LIMIT,
OPT_STR(PERDITION_PROTOCOL_DEPENDANT),
OPT_STR(log_passwd_to_str(DEFAILT_LOG_PASSWD)),
+ OPT_STR(DEFAULT_MIGRATE_NEW_SERVER),
OPT_STR(DEFAULT_MANAGESIEVE_CAPABILITY),
OPT_STR(DEFAULT_MAP_LIB),
OPT_STR(DEFAULT_MAP_LIB_OPT),
Index: perdition/perdition/options.h
===================================================================
--- perdition.orig/perdition/options.h 2010-07-19 19:21:52.000000000 +0900
+++ perdition/perdition/options.h 2010-07-19 19:26:43.000000000 +0900
@@ -132,6 +132,7 @@
#define DEFAULT_LOG_FACILITY "mail"
#define DEFAULT_LOGIN_DISABLED 0
#define DEFAULT_LOWER_CASE STATE_NONE
+#define DEFAULT_MIGRATE_NEW_SERVER NULL
#define DEFAULT_MANAGESIEVE_CAPABILITY MANAGESIEVE_DEFAULT_CAPA
#define DEFAULT_MAP_LIB_OPT NULL
#define DEFAULT_NO_BIND_BANNER 0
@@ -184,6 +185,7 @@
#endif /* WITH_SSL_SUPPORT */
+
typedef struct {
int add_domain;
unsigned int add_domain_strip_depth;
@@ -211,6 +213,7 @@ typedef struct {
int log_passwd;
int login_disabled;
int lower_case;
+ vanessa_dynamic_array_t *migrate_new_server;
char *map_library;
char *map_library_opt;
int no_bind_banner;
@@ -296,6 +299,7 @@ typedef struct {
#define MASK2_MANAGESIEVE_CAPABILITY (flag_t) 0x00000040
#define MASK2_POP_CAPABILITY (flag_t) 0x00000080
#define MASK2_TCP_KEEPALIVE (flag_t) 0x00000100
+#define MASK2_MIGRATE_NEW_SERVER (flag_t) 0x00000200
#ifdef WITH_SSL_SUPPORT
/* options_t.ssl_mask entries */
@@ -355,6 +359,7 @@ typedef struct {
#define TAG_MANAGESIEVE_CAPABILITY (int) 155
#define TAG_POP_CAPABILITY (int) 156
#define TAG_TCP_KEEPALIVE (int) 157
+#define TAG_MIGRATE_NEW_SERVER (int) 158
/*Flag values for options()*/
#define OPT_ERR (flag_t) 0x1 /*Print error to stderr, enable help*/
Index: perdition/perdition/perdition.c
===================================================================
--- perdition.orig/perdition/perdition.c 2010-07-19 19:26:32.000000000 +0900
+++ perdition/perdition/perdition.c 2010-07-19 19:26:43.000000000 +0900
@@ -54,6 +54,7 @@
#include "quit.h"
#include "config_file.h"
#include "config_file.h"
+#include "migrate.h"
#include "server_port.h"
#include "username.h"
#include "ssl.h"
@@ -359,6 +360,7 @@ int main (int argc, char **argv, char **
int *g = NULL;
int rc;
int flag;
+ int migrate_done_flag = 0;
#ifdef WITH_SSL_SUPPORT
SSL_CTX *ssl_ctx=NULL;
@@ -861,6 +863,44 @@ int main (int argc, char **argv, char **
port=user_server_port_get_port(usp);
}
+ /* XXX: Migrate extensions call for logging in to two different real
+ * servers in succession. To avoid restructuring the code massively,
+ * just jump in with a goto. */
+migrate_loop:
+ if (opt.migrate_new_server) {
+ if (!migrate_done_flag) {
+ int status;
+ status = migrate_done(PERDITION_SYSCONFDIR
+ "/migrate.db",
+ auth_get_authorisation_id(&auth));
+ if (status < 0) {
+ VANESSA_LOGGER_DEBUG("migrate_done");
+ LOGIN_FAILED_PROTOCOL(PROTOCOL_ERR, "Migration "
+ "status check failed");
+ PERDITION_CLEAN_UP_MAIN;
+ continue;
+ }
+ if (status) {
+ VANESSA_LOGGER_INFO("migrate done");
+ migrate_done_flag++;
+ }
+ else
+ VANESSA_LOGGER_INFO("migrate not done");
+ }
+
+ if (migrate_done_flag) {
+ if (!round_robin_server)
+ user_server_port_destroy(usp);
+ round_robin_server=1;
+ rnd = (rnd +1 ) % vanessa_dynamic_array_get_count(
+ opt.migrate_new_server);
+ usp = vanessa_dynamic_array_get_element(
+ opt.migrate_new_server, rnd);
+ servername = user_server_port_get_server(usp);
+ port = user_server_port_get_port(usp);
+ }
+ }
+
/*Use the default port if the port is not set*/
if(!port || !*port) {
port=opt.outgoing_port;
@@ -1055,6 +1095,25 @@ int main (int argc, char **argv, char **
perdition_exit_cleanly(-1);
}
+
+ if (opt.migrate_new_server && !migrate_done_flag) {
+ if (migrate(PERDITION_SYSCONFDIR "/migrate.db",
+ PERDITION_SYSCONFDIR "/migrate.lock",
+ auth_get_authorisation_id(&auth),
+ auth.passwd) < 0) {
+ VANESSA_LOGGER_DEBUG("migrate");
+ LOGIN_FAILED_PROTOCOL(PROTOCOL_NO, "Migration Failure");
+ PERDITION_CLEAN_UP_MAIN;
+ continue;
+ }
+
+ io_close(server_io);
+ io_destroy(server_io);
+ server_io = NULL;
+ migrate_done_flag++;
+ goto migrate_loop;
+ }
+
if(opt.server_resp_line){
*(server_resp_buf+server_resp_buf_size)='\0';
if (protocol->write_str(client_io, WRITE_STR_NO_CLLF, client_tag,
Index: perdition/Makefile.am
===================================================================
--- perdition.orig/Makefile.am 2010-07-19 19:21:52.000000000 +0900
+++ perdition/Makefile.am 2010-07-19 19:26:43.000000000 +0900
@@ -23,7 +23,7 @@
######################################################################
if GDBM_BUILD
-MAKEGDBM_DIR = makegdbm
+MAKEGDBM_DIR = makegdbm migrate
endif
if BDB_BUILD
MAKEBDB_DIR = makebdb
Index: perdition/debian/perdition.files
===================================================================
--- perdition.orig/debian/perdition.files 2010-07-19 19:21:53.000000000 +0900
+++ perdition/debian/perdition.files 2010-07-19 19:26:43.000000000 +0900
@@ -53,3 +53,8 @@ usr/lib/libperditiondb_bdb.a
usr/lib/libperditiondb_bdb.la
usr/lib/libperditiondb_bdb.so.0
usr/lib/libperditiondb_bdb.so.0.0.0
+usr/sbin/perdition-migrate
+usr/sbin/perdition-migrate-adduser
+usr/sbin/perdition-migrate-passwd
+usr/lib/libperdition_migrate.so.0
+usr/lib/libperdition_migrate.so.0.0.0
Index: perdition/migrate/Makefile.am
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/Makefile.am 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,27 @@
+######################################################################
+# Makefile.am April 2008
+# Horms horms(a)verge.net.au
+#
+# perdition
+# Mail retrieval proxy server
+# Copyright (C) 1999-2008 Horms
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA
+#
+######################################################################
+
+SUBDIRS = lib bin
+
Index: perdition/migrate/bin/Makefile.am
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/bin/Makefile.am 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,36 @@
+######################################################################
+# Makefile.am February 2000
+# Horms horms(a)verge.net.au
+#
+# perdition
+# Mail retrieval proxy server
+# Copyright (C) 1999-2005 Horms
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA
+#
+######################################################################
+
+EXTRA_DIST = $(sbin_SCRIPTS)
+
+sbin_PROGRAMS = perdition-migrate
+sbin_SCRIPTS = perdition-migrate-adduser perdition-migrate-passwd
+
+perdition_migrate_SOURCES = perdition-migrate.c
+
+INCLUDES = -I$(top_srcdir)/migrate/lib \
+-DPERDITION_SYSCONFDIR=\"$(sysconfdir)/perdition\"
+LDADD = -L$(top_builddir)/migrate/lib
+perdition_migrate_LDFLAGS = -lvanessa_logger -lperdition_migrate
Index: perdition/migrate/bin/perdition-migrate-adduser
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/bin/perdition-migrate-adduser 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ $# != 1 ]; then
+ echo "Usage: adduser-local USERNAME" >&2
+ exit 1
+fi
+
+adduser --no-create-home "$1"
+
Index: perdition/migrate/bin/perdition-migrate-passwd
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/bin/perdition-migrate-passwd 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+chpasswd
+
Index: perdition/migrate/bin/perdition-migrate.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/bin/perdition-migrate.c 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,166 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gdbm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <vanessa_logger.h>
+
+#include "migrate.h"
+
+#define NAME "perdition-migrate"
+
+#ifndef PERDITION_SYSCONFDIR
+#define PERDITION_SYSCONFDIR "/usr/local/etc/perdition"
+#endif
+
+/*
+ * Locking scheme
+ *
+ * To open the db read-only use db = db_open(opt.fl.migrate_db, GDBM_READER),
+ * this will use flock() to take a shared lock on the database.
+ *
+ * To open the db for writing use db = db_open(opt.fl.migrate_db, GDBM_WRITER),
+ * this will use flock() to take an exclusive lock on the database.
+ *
+ * To close the db use db_close(db);
+ *
+ * To lock the state of the database so that no changes can be made
+ * use fd = lock((opt.fl.migrate_lock), before opening the db for
+ * writing. This allows the db to be closed, while other operations are
+ * preformed, thus allowing readers to open the db during potentially
+ * blocking operations.
+ *
+ * To release this lock call unlock(fd) after updating the database
+ * and closing.
+ *
+ */
+
+#define OPT_CMD_MIGRATE 1
+#define OPT_CMD_DUMP 2
+
+typedef struct {
+ int cmd;
+ char *username;
+ char *passwd;
+ char *migrate_lock;
+ char *migrate_db;
+} options_t;
+
+options_t opt;
+
+void usage(int exit_status)
+{
+ FILE *fh;
+
+ fh = exit_status ? stderr : stdout;
+
+ fprintf(fh,
+ "Usage:\n"
+ " " NAME " dump\n"
+ " " NAME " migrate USERNAME PASSWD\n");
+
+ exit(exit_status);
+}
+
+void parse_options(int argc, char **argv)
+{
+ int min_args = 2;
+
+ if (argc < min_args) {
+ fprintf(stderr, "Too few arguments\n\n");
+ usage(1);
+ }
+
+ if (!strcmp(argv[1], "migrate")) {
+ opt.cmd = OPT_CMD_MIGRATE;
+ min_args = 4;
+ }
+ else if (!strcmp(argv[1], "dump")) {
+ opt.cmd = OPT_CMD_DUMP;
+ min_args = 2;
+ }
+ else {
+ fprintf(stderr, "Unknown command \"%s\"\n\n", argv[1]);
+ usage(1);
+ }
+
+ if (argc < min_args) {
+ fprintf(stderr, "Too few arguments\n\n");
+ usage(1);
+ }
+
+ switch (opt.cmd) {
+ case OPT_CMD_MIGRATE:
+ opt.username = argv[2];
+ opt.passwd = argv[3];
+ break;
+ }
+
+ opt.migrate_lock = PERDITION_SYSCONFDIR "/migrate.lock";
+ opt.migrate_db = PERDITION_SYSCONFDIR "/migrate.db";
+}
+
+int
+main (int argc, char **argv)
+{
+ int status;
+ vanessa_logger_t *vl;
+
+ vl = vanessa_logger_openlog_filehandle(stderr, NAME, LOG_DEBUG,
+ VANESSA_LOGGER_F_NO_IDENT_PID|
+ VANESSA_LOGGER_F_CONS);
+ if (!vl) {
+ fprintf(stderr, "Can't open logging to stdout\n");
+ exit(1);
+ }
+ vanessa_logger_set(vl);
+
+ parse_options(argc, argv);
+
+ switch (opt.cmd) {
+ case OPT_CMD_DUMP:
+ if (migrate_dump(opt.migrate_db) < 0) {
+ VANESSA_LOGGER_DEBUG("migrate_dump");
+ VANESSA_LOGGER_ERR("can't dump");
+ return -1;
+ }
+ return 0;
+ }
+
+ /* Do we need to do anything ? */
+ status = migrate_done(opt.migrate_db, opt.username);
+ if (status < 0) {
+ VANESSA_LOGGER_DEBUG("migrate_done");
+ VANESSA_LOGGER_ERR("can't check migration status");
+ exit(1);
+ }
+ if (status == 1) {
+ printf("user already migrated\n");
+ return 0;
+ }
+
+ /* Connect to old server to verify password */
+ sleep(1);
+
+ /* Do something */
+ status = migrate(opt.migrate_db, opt.migrate_lock, opt.username,
+ opt.passwd);
+ if (status < 0) {
+ VANESSA_LOGGER_DEBUG("migrate");
+ VANESSA_LOGGER_ERR("can't migrate");
+ exit(1);
+ }
+
+ vanessa_logger_unset();
+ vanessa_logger_closelog(vl);
+ return 0;
+}
+
Index: perdition/migrate/lib/Makefile.am
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/Makefile.am 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,33 @@
+######################################################################
+# Makefile.am April 2008
+# Horms horms(a)verge.net.au
+#
+# perdition
+# Mail retrieval proxy server
+# Copyright (C) 1999-2008 Horms
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA
+#
+######################################################################
+
+lib_LTLIBRARIES = libperdition_migrate.la
+
+libperdition_migrate_la_SOURCES = db.c db.h migrate.c migrate.h shell.c shell.h
+
+libperdition_migrate_la_LDFLAGS = -version-info 0:0:0 \
+ -lgdbm -vanessa_logger
+
+INCLUDES = -I$(top_srcdir)/perdition
Index: perdition/migrate/lib/db.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/db.c 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,240 @@
+#include <gdbm.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef DB_DEBUG
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include <vanessa_logger.h>
+
+#include "unused.h"
+#include "migrate.h"
+
+#define NAME "db_test"
+
+/*
+ * Locking scheme
+ *
+ * To open the db read-only use db = db_open(opt.fl.migrate_db, GDBM_READER),
+ * this will use flock() to take a shared lock on the database.
+ *
+ * To open the db for writing use db = db_open(opt.fl.migrate_db, GDBM_WRITER),
+ * this will use flock() to take an exclusive lock on the database.
+ *
+ * To close the db use db_close(db);
+ *
+ * To lock the state of the database so that no changes can be made
+ * use fd = lock((opt.fl.migrate_lock), before opening the db for
+ * writing. This allows the db to be closed, while other operations are
+ * preformed, thus allowing readers to open the db during potentially
+ * blocking operations.
+ *
+ * To release this lock call unlock(fd) after updating the database
+ * and closing.
+ *
+ */
+
+#include "db.h"
+
+#define VANESSA_LOGGER_DEBUG_GDBM_ERRNO(str) \
+ _vanessa_logger_log_prefix(__vanessa_logger_vl, LOG_DEBUG, \
+ __FUNCTION__, "%s: %s", str, \
+ gdbm_errno ? \
+ gdbm_strerror(gdbm_errno) : \
+ strerror(errno));
+
+#ifdef DB_DEBUG
+static void db_log_debug(const char *s)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ printf("%d: %ld.%06ld: %s\n", getpid(), tv.tv_sec, tv.tv_usec, s);
+}
+#else
+static void db_log_debug(const char *UNUSED(s)) { ; }
+#endif
+
+int lock(const char *fn)
+{
+ int fd;
+ char buf[11];
+ ssize_t bytes;
+
+ db_log_debug("locking");
+
+ fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+ if (fd < 0) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("open [%s]: %s", fn,
+ strerror(errno));
+ return -1;
+ }
+
+ if (flock(fd, LOCK_EX)) {
+ VANESSA_LOGGER_DEBUG_ERRNO("flock");
+ goto err_close;
+ }
+
+ /* XXX: Duplicated from write_pid_file() */
+ if (snprintf(buf, sizeof(buf), "%u", getpid()) >= (int)sizeof(buf)) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("Pid too long for buffer [%u]",
+ getpid());
+ goto err_unlock;
+ }
+
+ /* XXX: Can a short write occur? */
+ while (1) {
+ bytes = write(fd, buf, strlen(buf));
+ if (bytes != (ssize_t)strlen(buf)) {
+ if (bytes < 0 && errno == EINTR) {
+ continue;
+ }
+ VANESSA_LOGGER_DEBUG_UNSAFE("Could not write pid-file "
+ "[%s]: %s", fn, strerror(errno));
+ goto err_unlock;
+ }
+ break;
+ }
+
+ db_log_debug("locked");
+
+ return fd;
+
+err_unlock:
+ /* No need to flock(fd, LOCK_UN)
+ * as the lock is automatically released with all
+ * file desciptors are closed, and there should
+ * be just one */
+err_close:
+ close(fd);
+ return -1;
+}
+
+int unlock(int fd)
+{
+ db_log_debug("unlocking");
+
+ /* No need to flock(gdbm_fdesc(db), LOCK_UN)
+ * as the lock is automatically released with all
+ * file desciptors are closed, and there should
+ * be just one */
+
+ if (close(fd) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("close (very bad)");
+ return -1;
+ }
+ db_log_debug("unlock");
+ return 0;
+}
+
+GDBM_FILE db_open(char *fn, int read_write)
+{
+ GDBM_FILE db;
+ int lock_op;
+
+ db_log_debug("opening");
+
+ switch (read_write) {
+ case GDBM_READER:
+ lock_op = LOCK_SH;
+ break;
+ case GDBM_WRITER:
+ case GDBM_WRCREAT:
+ case GDBM_NEWDB:
+ lock_op = LOCK_EX;
+ break;
+ default:
+ VANESSA_LOGGER_DEBUG("unknown read_write argument");
+ return NULL;
+ }
+
+ db = gdbm_open(fn, 0, GDBM_WRCREAT|GDBM_SYNC|GDBM_NOLOCK,
+ S_IRUSR|S_IWUSR, 0);
+ if (!db) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("gdbm_open [%s]: %s", fn,
+ gdbm_errno ?
+ gdbm_strerror(gdbm_errno) :
+ strerror(errno));
+ return NULL;
+ }
+ if (flock(gdbm_fdesc(db), lock_op)) {
+ VANESSA_LOGGER_DEBUG_ERRNO("flock");
+ goto err_close;
+ }
+
+ db_log_debug("opened");
+
+ return db;
+
+err_close:
+ gdbm_close(db);
+ return NULL;
+}
+
+void db_close(GDBM_FILE db)
+{
+ db_log_debug("closing");
+
+ /* No need to flock(gdbm_fdesc(db), LOCK_UN)
+ * as the lock is automatically released with all
+ * file desciptors are closed, and there should
+ * be just one */
+
+ gdbm_close(db);
+ db_log_debug("closed");
+}
+
+struct db_ent db_fetch_ent(GDBM_FILE db, char *user)
+{
+ datum key;
+ datum value;
+ struct db_ent ent = { .status = STATUS_INVALID };
+
+ key.dptr = user;
+ key.dsize = strlen(user) + 1;
+
+ value = gdbm_fetch(db, key);
+ if (value.dptr == NULL) {
+ ent.status = STATUS_NEXIST;
+ return ent;
+ }
+
+ memcpy(&ent.status, value.dptr, sizeof(db_status_t));
+
+ return ent;
+}
+
+int db_store_ent(GDBM_FILE db, char *user, struct db_ent ent)
+{
+ datum key;
+ datum value;
+ int status = -1;
+
+ key.dptr = user;
+ key.dsize = strlen(user) + 1;
+
+ value.dsize = sizeof(db_status_t);
+ value.dptr = (char *)malloc(value.dsize);
+ if (value.dptr == NULL) {
+ VANESSA_LOGGER_DEBUG_ERRNO("malloc");
+ return -1;
+ }
+
+ memcpy(value.dptr, &ent.status, sizeof(db_status_t));
+
+ if (gdbm_store(db, key, value, GDBM_REPLACE) < 0) {
+ VANESSA_LOGGER_DEBUG_GDBM_ERRNO("gdbm_store");
+ goto err_free;
+ }
+
+ status = 0;
+err_free:
+ free(value.dptr);
+ return status;
+}
Index: perdition/migrate/lib/db.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/db.h 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,29 @@
+#ifndef DB_H
+#define DB_H
+
+#include <gdbm.h>
+#include <stdint.h>
+
+int lock(const char *fn);
+int unlock(int fd);
+GDBM_FILE db_open(char *fn, int read_write);
+void db_close(GDBM_FILE db);
+
+#define STATUS_NEXIST 0x00
+#define STATUS_INIT 0x01
+#define STATUS_ACCOUNT_CREATED 0x02
+#define STATUS_PASSWORD_SET 0x04
+#define STATUS_DONE 0x08
+#define STATUS_SKIP 0x10
+#define STATUS_INVALID 0xff
+
+typedef uint8_t db_status_t;
+
+struct db_ent {
+ db_status_t status;
+};
+
+struct db_ent db_fetch_ent(GDBM_FILE db, char *user);
+int db_store_ent(GDBM_FILE db, char *user, struct db_ent ent);
+
+#endif
Index: perdition/migrate/lib/migrate.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/migrate.c 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,242 @@
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdlib.h>
+
+#include <vanessa_logger.h>
+
+#include "migrate.h"
+#include "db.h"
+#include "shell.h"
+
+int migrate_done(char *db_fn, char *user)
+{
+ GDBM_FILE db;
+ struct db_ent ent;
+ int status = -1;
+
+ db = db_open(db_fn, GDBM_READER);
+ if (!db) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("db_open [%s]", db_fn);
+ return -1;
+ }
+
+ ent = db_fetch_ent(db, user);
+ if (ent.status == STATUS_INVALID) {
+ VANESSA_LOGGER_DEBUG("db_fetch_ent");
+ goto err_close;
+ }
+
+ status = (ent.status & (STATUS_DONE|STATUS_SKIP)) ? 1 : 0;
+
+err_close:
+ db_close(db);
+ return status;
+}
+
+static int set_passwd (const char *user, const char *passwd)
+{
+ int status = -1;
+ char *cmd = "perdition-migrate-passwd";
+ char *argv[2];
+ char *user_pass;
+ int level = LOG_ERR;
+
+ VANESSA_LOGGER_INFO_UNSAFE("Running %s for \'%s\'", cmd, user);
+
+ user_pass = malloc(strlen(user) + 1 + strlen(passwd) + 1);
+ if (!user_pass) {
+ VANESSA_LOGGER_DEBUG_ERRNO("malloc");
+ goto err;
+ }
+ strcpy(user_pass, user);
+ strcat(user_pass, ":");
+ strcat(user_pass, passwd);
+
+ argv[0] = cmd;
+ argv[1] = NULL;
+
+ status = my_execvp_stdin(argv[0], argv, user_pass);
+ if (status) {
+ if (level == LOG_INFO)
+ return WEXITSTATUS(status);
+ VANESSA_LOGGER_ERR_UNSAFE("Error: while running %s for "
+ "'%s': (%d)", cmd, user, status);
+ }
+
+err:
+ free(user_pass);
+ return status;
+}
+
+static int add_user (char *user)
+{
+ int status;
+ char *cmd = "perdition-migrate-adduser";
+ char *argv[3];
+ int level = LOG_ERR;
+
+ VANESSA_LOGGER_INFO_UNSAFE("Running %s for \'%s\'", cmd, user);
+ {
+ int i = 0;
+ argv[i++] = cmd;
+ argv[i++] = (char *)user;
+ argv[i++] = NULL;
+ }
+
+ status = my_execvp(argv[0], argv);
+ if (status) {
+ if (level == LOG_INFO)
+ return WEXITSTATUS(status);
+ VANESSA_LOGGER_ERR_UNSAFE("Error: while running %s for "
+ "'%s': (%d)", cmd, user, status);
+ }
+
+ return status;
+}
+
+int create_account(char *user)
+{
+ if(getpwnam(user)) {
+ return 0;
+ }
+ switch (errno) {
+ case EINTR:
+ case EIO:
+ case EMFILE:
+ case ENFILE:
+ case ENOMEM:
+ case ERANGE:
+ VANESSA_LOGGER_DEBUG_ERRNO("getpwnam");
+ return -1;
+ }
+ errno = 0;
+
+ if (add_user(user)) {
+ VANESSA_LOGGER_DEBUG("add_user");
+ return -1;
+ }
+
+ return 0;
+}
+
+int migrate(char *db_fn, const char *lock_fn, char *user, const char *passwd)
+{
+ GDBM_FILE db = NULL;
+ int status_lock;
+ db_status_t saved_db_status;
+ struct db_ent ent;
+ int return_status = -1;
+
+ status_lock = lock(lock_fn);
+ if (status_lock < 0) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("lock [%s]", lock_fn);
+ goto err_unlock;
+ }
+
+ db = db_open(db_fn, GDBM_WRITER);
+ if (!db) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("db_open 1 [%s]", db_fn);
+ goto err_unlock;
+ }
+
+ ent = db_fetch_ent(db, user);
+ if (ent.status == STATUS_INVALID) {
+ VANESSA_LOGGER_DEBUG("db_fetch_ent");
+ goto err_close;
+ }
+ saved_db_status = ent.status;
+
+ db_close(db);
+ db = NULL;
+
+ /* The status flags are just a way of skipping unnecessary work.
+ * The work itself should be idempotent so that if a crash occurs
+ * after some work is done and before status is saved to the
+ * database, the work can simply be done again.
+ */
+
+ ent.status |= STATUS_INIT;
+
+ if (! (ent.status & STATUS_ACCOUNT_CREATED) ) {
+ if (create_account(user)) {
+ VANESSA_LOGGER_DEBUG("create_account");
+ goto err_save;
+ }
+ ent.status |= STATUS_ACCOUNT_CREATED;
+ }
+
+ if (! (ent.status & STATUS_PASSWORD_SET) ) {
+ if (set_passwd(user, passwd)) {
+ VANESSA_LOGGER_DEBUG("set_passwd");
+ goto err_save;
+ }
+ ent.status |= STATUS_PASSWORD_SET;
+ }
+
+ ent.status |= STATUS_DONE;
+
+ return_status = 0;
+err_save:
+ if (ent.status != saved_db_status) {
+ db = db_open(db_fn, GDBM_WRITER);
+ if (!db) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("db_open 2 [%s]", db_fn);
+ return_status = -1;
+ goto err_unlock;
+ }
+ if (db_store_ent(db, user, ent) < 0) {
+ VANESSA_LOGGER_DEBUG("db_store_ent");
+ return_status = -1;
+ }
+ }
+err_close:
+ if (db != NULL)
+ db_close(db);
+err_unlock:
+ if (unlock(status_lock) < 0) {
+ VANESSA_LOGGER_DEBUG("unlock");
+ return_status = -1;
+ }
+ return return_status;
+}
+
+int migrate_dump(char *db_fn)
+{
+ GDBM_FILE db;
+ datum key;
+ int status = -1;
+ int count = 0;
+ struct db_ent ent;
+
+ db = db_open(db_fn, GDBM_READER);
+ if (!db) {
+ VANESSA_LOGGER_DEBUG_UNSAFE("db_open [%s]", db_fn);
+ return -1;
+ }
+
+ key = gdbm_firstkey(db);
+ while (key.dptr != NULL) {
+ ent = db_fetch_ent(db, key.dptr);
+ if (ent.status < 0) {
+ VANESSA_LOGGER_DEBUG("db_fetch_ent");
+ goto err_close;
+ }
+ count++;
+ printf("%s: init=%d account_created=%d password_set=%d "
+ "done=%d skip=%d\n", key.dptr,
+ ent.status & STATUS_INIT ? 1 : 0,
+ ent.status & STATUS_ACCOUNT_CREATED ? 1 : 0,
+ ent.status & STATUS_PASSWORD_SET ? 1 : 0,
+ ent.status & STATUS_DONE ? 1 : 0,
+ ent.status & STATUS_SKIP ? 1 : 0);
+ key = gdbm_nextkey(db, key);
+ }
+ printf("%d %s\n", count, count == 1 ? "User" : "Users");
+
+ status = 0;
+err_close:
+ db_close(db);
+ return status;
+}
Index: perdition/migrate/lib/migrate.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/migrate.h 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,9 @@
+#ifndef FSL_H
+#define FSL_H
+
+int migrate_done(char *db_fn, char *user);
+int migrate(char *db_fn, const char *lock_fn, char *user, const char *passwd);
+int migrate_dump(char *db_fn);
+
+#endif
+
Index: perdition/migrate/lib/shell.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/shell.c 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,314 @@
+/**********************************************************************
+ * shell.c October 2005
+ * Horms horms(a)verge.net.au
+ *
+ * perdition
+ * Mail retrieval proxy server
+ * Copyright (C) 1999-2005 Horms
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ *
+ **********************************************************************/
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <vanessa_logger.h>
+
+#include "shell.h"
+
+static int
+log_from_fd(int *fd, fd_set *readfds) {
+ ssize_t len;
+ char buf[1024];
+ char *next;
+ char *cur;
+
+ if (*fd == -1 || !FD_ISSET(*fd, readfds))
+ return 0;
+
+ len = read(*fd, buf, sizeof(buf)-1);
+ if (len < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("read: stdout");
+ return -1;
+ }
+
+ if (!len) {
+ close(*fd);
+ *fd = -1;
+ return 0;
+ }
+
+ buf[len] = '\0';
+ cur = buf;
+ while (cur) {
+ next = strchr(cur, '\n');
+ if (next) {
+ *next = '\0';
+ next++;
+ }
+ else if (!*cur)
+ break;
+ VANESSA_LOGGER_DEBUG_RAW(cur);
+ cur = next;
+ }
+
+ return 0;
+}
+
+int
+my_execvp_stdin(char *file, char *argv[], const char *stdin_buf)
+{
+ int status = -1;
+ int child_status = -1;
+ int stdin_pipe[2] = {-1, -1};
+ int stdout_pipe[2] = {-1, -1};
+ int stderr_pipe[2] = {-1, -1};
+ sigset_t sigset;
+ sigset_t sigset_saved;
+ pid_t child = 0;
+
+#ifdef EXEC_DEBUG
+ {
+ char *const *p;
+ VANESSA_LOGGER_DEBUG_RAW_UNSAFE("Executing: (arg0) %s", file);
+ for (p = argv; *p; p++) {
+ VANESSA_LOGGER_DEBUG_RAW_UNSAFE(
+ "Executing: (argN) %s", *p);
+ }
+ }
+#endif
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigset, &sigset_saved);
+
+ if (pipe(stdin_pipe) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("pipe: stdin");
+ goto err;
+ }
+ if (pipe(stdout_pipe) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("pipe: stdout");
+ goto err;
+ }
+ if (pipe(stderr_pipe) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("pipe: stderr");
+ goto err;
+ }
+
+ child = fork();
+ if (child < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("fork");
+ goto err;
+ }
+ else if (!child) {
+ /* Child */
+ vanessa_logger_reopen(vanessa_logger_get());
+ close(stdin_pipe[1]);
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
+ if (dup2(stdin_pipe[0], 0) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("dup: stdin");
+ exit (127);
+ }
+ if (dup2(stdout_pipe[1], 1) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("dup: stdout");
+ exit (127);
+ }
+ if (dup2(stderr_pipe[1], 2) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("dup: stderr");
+ exit (127);
+ }
+
+ sigprocmask(SIG_SETMASK, &sigset_saved, NULL);
+
+ execvp(file, argv);
+ VANESSA_LOGGER_DEBUG_ERRNO("dup: execvp");
+ exit(127);
+ }
+
+ /* Parent */
+
+ close(stdin_pipe[0]);
+ stdin_pipe[0] = -1;
+ close(stderr_pipe[1]);
+ stderr_pipe[1] = -1;
+ close(stdout_pipe[1]);
+ stdout_pipe[1] = -1;
+
+ if (stdin_buf && strlen(stdin_buf)) {
+ size_t buf_off = 0, buf_len = strlen(stdin_buf);
+ while (1) {
+ ssize_t bytes;
+ bytes = write(stdin_pipe[1], stdin_buf + buf_off,
+ buf_len - buf_off);
+ if (bytes < 0) {
+ if (errno == EINTR)
+ continue;
+ VANESSA_LOGGER_DEBUG_ERRNO("write");
+ goto err;
+ }
+ if (bytes + buf_off == buf_len)
+ break;
+ }
+ close(stdin_pipe[1]);
+ stdin_pipe[1] = -1;
+ }
+
+ while (1) {
+ int maxfd = -1;
+ fd_set readfds;
+ fd_set exceptfds;
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&exceptfds);
+
+ if (stderr_pipe[0] != -1) {
+ FD_SET(stderr_pipe[0], &readfds);
+ FD_SET(stderr_pipe[0], &exceptfds);
+ if (stderr_pipe[0] > maxfd)
+ maxfd = stderr_pipe[0];
+ }
+ if (stdout_pipe[0] != -1) {
+ FD_SET(stdout_pipe[0], &readfds);
+ FD_SET(stdout_pipe[0], &exceptfds);
+ if (stdout_pipe[0] > maxfd)
+ maxfd = stdout_pipe[0];
+ }
+
+ if (maxfd == -1)
+ break;
+
+ status = select(maxfd + 1, &readfds, NULL, &exceptfds, NULL);
+ if (status < 0) {
+ if (errno != EINTR) /* Ignore EINTR */
+ continue;
+ VANESSA_LOGGER_DEBUG_ERRNO("select");
+ return -1;
+ } else if ((stderr_pipe[0] != -1 &&
+ FD_ISSET(stderr_pipe[0], &exceptfds)) ||
+ (stdout_pipe[0] != -1 &&
+ FD_ISSET(stdout_pipe[0], &exceptfds))) {
+ VANESSA_LOGGER_DEBUG("exceptfds set");
+ goto err;
+ } else if (!status)
+ break;
+
+ if (log_from_fd(&stderr_pipe[0], &readfds) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("log_from_fd: stderr");
+ goto err;
+ }
+ if (log_from_fd(&stdout_pipe[0], &readfds) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("log_from_fd: stdout");
+ goto err;
+ }
+ }
+
+
+ if (waitpid (child, &child_status, 0) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("waitpid");
+ goto err;
+ }
+ child = 0;
+ status = 0;
+err:
+ if (child > 0) {
+ if (kill (child, SIGKILL) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("kill");
+ status = -1;
+ }
+ if (waitpid (child, &child_status, 0) < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("waitpid");
+ status = -1;
+ }
+ }
+ sigprocmask(SIG_SETMASK, &sigset_saved, NULL);
+
+ if (stdin_pipe[0] != -1)
+ close(stdin_pipe[0]);
+ if (stdin_pipe[1] != -1)
+ close(stdin_pipe[1]);
+
+ if (stderr_pipe[0] != -1)
+ close(stderr_pipe[0]);
+ if (stderr_pipe[1] != -1)
+ close(stderr_pipe[1]);
+
+ if (stdout_pipe[0] != -1)
+ close(stdout_pipe[0]);
+ if (stdout_pipe[1] != -1)
+ close(stdout_pipe[1]);
+
+ return (status ? status : child_status);
+}
+
+int
+my_execvp(char *file, char *argv[])
+{
+ return my_execvp_stdin(file, argv, NULL);
+}
+
+#ifdef MY_EXECVP_BG
+static pid_t
+my_execvp_bg(const char *file, char *const argv[])
+{
+ pid_t child;
+
+ child = fork();
+ if (child < 0) {
+ VANESSA_LOGGER_DEBUG_ERRNO("fork");
+ return child;
+ }
+ else if (!child) {
+ int status;
+ status = my_execvp(file, argv);
+ if (status == -1)
+ exit(127);
+ exit(WEXITSTATUS(status));
+ }
+
+ return child;
+}
+#endif
+
+#ifdef MY_SYSTEM
+static int
+my_system(const char *cmd)
+{
+ char *argv[4];
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = (char *)cmd;
+ argv[3] = NULL;
+ return my_execvp(argv[0], argv);
+}
+
+static int
+my_system_bg(const char *cmd)
+{
+ char *args[4];
+
+ args[0] = "/bin/sh";
+ args[1] = "-c";
+ args[2] = (char *)cmd;
+ args[3] = NULL;
+ return my_execvp_bg(args[0], args);
+}
+#endif
Index: perdition/migrate/lib/shell.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ perdition/migrate/lib/shell.h 2010-07-19 19:26:43.000000000 +0900
@@ -0,0 +1,7 @@
+#ifndef SHELL_H
+#define SHELL_H
+
+int my_execvp_stdin(char *file, char *argv[], const char *stdin_buf);
+int my_execvp(char *file, char *argv[]);
+
+#endif
Index: perdition/perdition.spec.in
===================================================================
--- perdition.orig/perdition.spec.in 2010-07-19 19:21:53.000000000 +0900
+++ perdition/perdition.spec.in 2010-07-19 19:26:43.000000000 +0900
@@ -327,6 +327,13 @@ ldconfig
%{_libdir}/libperditiondb_daemon_base.so.0
%{_libdir}/libperditiondb_daemon_base.so.0.0.0
+#migrate
+%{_libdir}/libperdition_migrate.so.0
+%{_libdir}/libperdition_migrate.so.0.0.0
+%{_sbindir}/perdition-migrate
+%{_sbindir}/perdition-migrate-adduser
+%{_sbindir}/perdition-migrate-passwd
+
## bdb map
%if %{?_without_bdb:0}%{!?_without_bdb:1}
%files -n libperditiondb_bdb0
Index: perdition/perdition/Makefile.am
===================================================================
--- perdition.orig/perdition/Makefile.am 2010-07-19 19:21:52.000000000 +0900
+++ perdition/perdition/Makefile.am 2010-07-19 19:26:43.000000000 +0900
@@ -103,6 +103,7 @@ INCLUDES= \
-DPERDITION_LIBDIR=\"${libdir}\" \
-DPERDITION_SYSCONFDIR=\"$(sysconfdir)/perdition\" \
-DPERDITION_LOCALSTATEDIR=\"$(localstatedir)\" \
+-I$(top_srcdir)/migrate/lib \
@ssl_includes@
# Removed because Debian doesn't like it
@@ -113,11 +114,12 @@ LDADD = \
-lvanessa_socket \
-lvanessa_logger \
-lpopt \
+-L$(top_builddir)/migrate/lib -lperdition_migrate \
@pam_lib@ \
@socket_lib@ \
@dl_lib@ \
@ssl_lib@ \
@dmalloc_lib@
-perdition_LDFLAGS = -rdynamic
+perdition_LDFLAGS = -rdynamic $(MIGRATE_LD)