mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-23 20:03:31 +01:00
Add a lockfile to the Tor data directory to avoid situations where two Tors start with the same datadir, or where a --list-fingerprints races with a server to create keys, or such.
svn:r16722
This commit is contained in:
parent
6a29ad853b
commit
f80ac31d74
@ -3,6 +3,10 @@ Changes in version 0.2.1.6-alpha - 2008-09-xx
|
||||
- Fix compile on OpenBSD 4.4-current. Bugfix on 0.2.1.5-alpha.
|
||||
Reported by Tas.
|
||||
|
||||
o Minor features:
|
||||
- Use a lockfile to make sure that two Tor processes are not
|
||||
simultaneously running with the same datadir.
|
||||
|
||||
|
||||
Changes in version 0.2.1.5-alpha - 2008-08-31
|
||||
o Major features:
|
||||
|
@ -324,7 +324,7 @@ AC_CHECK_HEADERS(netdb.h sys/ioctl.h sys/socket.h arpa/inet.h netinet/in.h pwd.h
|
||||
|
||||
dnl These headers are not essential
|
||||
|
||||
AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h limits.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h syslog.h sys/time.h sys/resource.h inttypes.h utime.h sys/utime.h sys/mman.h netinet/in6.h malloc.h sys/syslimits.h malloc/malloc.h linux/types.h)
|
||||
AC_CHECK_HEADERS(stdint.h sys/types.h inttypes.h sys/param.h sys/wait.h limits.h sys/limits.h netinet/in.h arpa/inet.h machine/limits.h syslog.h sys/time.h sys/resource.h inttypes.h utime.h sys/utime.h sys/mman.h netinet/in6.h malloc.h sys/syslimits.h malloc/malloc.h linux/types.h sys/file.h)
|
||||
|
||||
TOR_CHECK_PROTOTYPE(malloc_good_size, HAVE_MALLOC_GOOD_SIZE_PROTOTYPE,
|
||||
[#ifdef HAVE_MALLOC_H
|
||||
|
@ -26,6 +26,7 @@ const char compat_c_id[] =
|
||||
#ifdef MS_WINDOWS
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
#include <sys/locking.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNAME
|
||||
@ -98,6 +99,9 @@ const char compat_c_id[] =
|
||||
#ifdef HAVE_SYS_SYSLIMITS_H
|
||||
#include <sys/syslimits.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BSOCKETS
|
||||
#include <bsocket.h>
|
||||
@ -488,6 +492,77 @@ touch_file(const char *fname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tor_lockfile_t {
|
||||
char *filename;
|
||||
int fd;
|
||||
};
|
||||
|
||||
tor_lockfile_t *
|
||||
tor_lockfile_lock(const char *filename, int blocking, int *locked_out)
|
||||
{
|
||||
tor_lockfile_t *result;
|
||||
int fd;
|
||||
*locked_out = 0;
|
||||
|
||||
log_info(LD_FS, "Locking \"%s\"", filename);
|
||||
fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
|
||||
if (fd < 0) {
|
||||
log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename,
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
#ifdef WIN32
|
||||
_lseek(fd, 0, SEEK_SET);
|
||||
if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLOCK, 0) < 0) {
|
||||
if (errno != EDEADLOCK)
|
||||
log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
|
||||
else
|
||||
*locked_out = 1;
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) {
|
||||
if (errno != EWOULDBLOCK)
|
||||
log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno));
|
||||
else
|
||||
*locked_out = 1;
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = tor_malloc(sizeof(tor_lockfile_t));
|
||||
result->filename = tor_strdup(filename);
|
||||
result->fd = fd;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
tor_lockfile_unlock(tor_lockfile_t *lockfile)
|
||||
{
|
||||
tor_assert(lockfile);
|
||||
|
||||
log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename);
|
||||
#ifdef WIN32
|
||||
_lseek(fd, 0, SEEK_SET);
|
||||
if (_locking(fd, _LK_UNLCK, 0) < 0) {
|
||||
log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename,
|
||||
strerror(errno));
|
||||
}
|
||||
#else
|
||||
if (flock(lockfile->fd, LOCK_UN) < 0) {
|
||||
log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename,
|
||||
strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
close(lockfile->fd);
|
||||
lockfile->fd = -1;
|
||||
tor_free(lockfile->filename);
|
||||
tor_free(lockfile);
|
||||
}
|
||||
|
||||
#undef DEBUG_SOCKET_COUNTING
|
||||
#ifdef DEBUG_SOCKET_COUNTING
|
||||
/** A bitarray of all fds that should be passed to tor_socket_close(). Only
|
||||
|
@ -266,6 +266,11 @@ struct tm *tor_gmtime_r(const time_t *timep, struct tm *result);
|
||||
int replace_file(const char *from, const char *to);
|
||||
int touch_file(const char *fname);
|
||||
|
||||
typedef struct tor_lockfile_t tor_lockfile_t;
|
||||
tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking,
|
||||
int *locked_out);
|
||||
void tor_lockfile_unlock(tor_lockfile_t *lockfile);
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
#define PATH_SEPARATOR "\\"
|
||||
#else
|
||||
|
@ -1172,6 +1172,11 @@ options_act(or_options_t *old_options)
|
||||
int running_tor = options->command == CMD_RUN_TOR;
|
||||
char *msg;
|
||||
|
||||
if (running_tor && !have_lockfile()) {
|
||||
if (try_locking(options, 1) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (consider_adding_dir_authorities(options, old_options) < 0)
|
||||
return -1;
|
||||
|
||||
@ -4883,10 +4888,10 @@ get_or_state(void)
|
||||
* Note: Consider using the get_datadir_fname* macros in or.h.
|
||||
*/
|
||||
char *
|
||||
get_datadir_fname2_suffix(const char *sub1, const char *sub2,
|
||||
const char *suffix)
|
||||
options_get_datadir_fname2_suffix(or_options_t *options,
|
||||
const char *sub1, const char *sub2,
|
||||
const char *suffix)
|
||||
{
|
||||
or_options_t *options = get_options();
|
||||
char *fname = NULL;
|
||||
size_t len;
|
||||
tor_assert(options);
|
||||
|
@ -1850,6 +1850,54 @@ tor_init(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static tor_lockfile_t *lockfile = NULL;
|
||||
|
||||
int
|
||||
try_locking(or_options_t *options, int err_if_locked)
|
||||
{
|
||||
if (lockfile)
|
||||
return 0;
|
||||
else {
|
||||
char *fname = options_get_datadir_fname2_suffix(options, "lock",NULL,NULL);
|
||||
int already_locked = 0;
|
||||
tor_lockfile_t *lf = tor_lockfile_lock(fname, 0, &already_locked);
|
||||
tor_free(fname);
|
||||
if (!lf) {
|
||||
if (err_if_locked && already_locked) {
|
||||
int r;
|
||||
log_warn(LD_GENERAL, "It looks like another Tor process is running "
|
||||
"with the same data directory. Waiting 5 seconds to see "
|
||||
"if it goes away.");
|
||||
sleep(5);
|
||||
r = try_locking(options, 0);
|
||||
if (r<0) {
|
||||
log_err(LD_GENERAL, "No, it's still there. Exiting.");
|
||||
exit(0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
lockfile = lf;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
have_lockfile(void)
|
||||
{
|
||||
return lockfile != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
release_lockfile(void)
|
||||
{
|
||||
if (lockfile) {
|
||||
tor_lockfile_unlock(lockfile);
|
||||
lockfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Free all memory that we might have allocated somewhere.
|
||||
* If <b>postfork</b>, we are a worker process and we want to free
|
||||
* only the parts of memory that we won't touch. If !<b>postfork</b>,
|
||||
|
12
src/or/or.h
12
src/or/or.h
@ -2781,8 +2781,11 @@ config_line_t *option_get_assignment(or_options_t *options,
|
||||
const char *key);
|
||||
int options_save_current(void);
|
||||
const char *get_torrc_fname(void);
|
||||
char *get_datadir_fname2_suffix(const char *sub1, const char *sub2,
|
||||
const char *suffix);
|
||||
char *options_get_datadir_fname2_suffix(or_options_t *options,
|
||||
const char *sub1, const char *sub2,
|
||||
const char *suffix);
|
||||
#define get_datadir_fname2_suffix(sub1, sub2, suffix) \
|
||||
options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix))
|
||||
/** Return a newly allocated string containing datadir/sub1. See
|
||||
* get_datadir_fname2_suffix. */
|
||||
#define get_datadir_fname(sub1) get_datadir_fname2_suffix((sub1), NULL, NULL)
|
||||
@ -3493,6 +3496,11 @@ void dns_servers_relaunch_checks(void);
|
||||
|
||||
void control_signal_act(int the_signal);
|
||||
void handle_signals(int is_parent);
|
||||
|
||||
int try_locking(or_options_t *options, int err_if_locked);
|
||||
int have_lockfile(void);
|
||||
void release_lockfile(void);
|
||||
|
||||
void tor_cleanup(void);
|
||||
void tor_free_all(int postfork);
|
||||
|
||||
|
@ -235,6 +235,17 @@ init_key_from_file(const char *fname, int generate, int severity)
|
||||
goto error;
|
||||
case FN_NOENT:
|
||||
if (generate) {
|
||||
if (!have_lockfile()) {
|
||||
if (try_locking(get_options(), 0)<0) {
|
||||
/* Make sure that --list-fingerprint only creates new keys
|
||||
* if there is no possibility for a deadlock. */
|
||||
log(severity, LD_FS, "Another Tor process has locked \"%s\". Not "
|
||||
"writing any new keys.", fname);
|
||||
/*XXXX The 'other process' might make a key in a second or two;
|
||||
* maybe we should wait for it. */
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.",
|
||||
fname);
|
||||
if (crypto_pk_generate_key(prkey)) {
|
||||
|
Loading…
Reference in New Issue
Block a user