lockdb.c 3.55 KB
Newer Older
Per Cederqvist's avatar
Per Cederqvist committed
1
2
/*
 * Lock and unlock the database.
3
 * Copyright (C) 1999, 2003  Lysator Academic Computer Association.
Per Cederqvist's avatar
Per Cederqvist committed
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM 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 1, or (at your option) 
 * any later version.
 * 
 * LysKOM 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 LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
Per Cederqvist's avatar
Per Cederqvist committed
23
 * Please report bugs at http://bugzilla.lysator.liu.se/. 
Per Cederqvist's avatar
Per Cederqvist committed
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 */

#include <config.h>

#include <sys/param.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#  include <string.h>
#else
#  ifdef HAVE_STRINGS_H
#    include <strings.h>
#  endif
#endif
#ifndef HAVE_STRCHR
#  define strchr index
#endif
#include <stdlib.h>
#include <signal.h>
Per Cederqvist's avatar
Per Cederqvist committed
45
#include <netdb.h>
46
#include "timewrap.h"
Per Cederqvist's avatar
Per Cederqvist committed
47
48
49
50

#include "lockdb.h"
#include "log.h"
#include "kom-types.h"
51
#include "conf-file.h"
Per Cederqvist's avatar
Per Cederqvist committed
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "param.h"
#include "lyskomd.h"

int lock_db(void)
{
    char new_lock[MAXHOSTNAMELEN + 3 + 3 * sizeof(pid_t)];
    char current_lock[MAXHOSTNAMELEN + 4 + 3 * sizeof(pid_t)];
    char *end;
    int retry;
    size_t sz;
    size_t ix;
    pid_t pid;
    

    if (gethostname(new_lock, MAXHOSTNAMELEN) == -1)
67
	restart_kom("gethostname failed: %s\n", strerror(errno));
Per Cederqvist's avatar
Per Cederqvist committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

    new_lock[MAXHOSTNAMELEN+1] = '\0';
    end = strchr(new_lock, '\0');
    sprintf(end, ":%ld", (long)getpid());

    for (retry = 0; retry < 2; ++retry)
    {
	if (symlink(new_lock, param.lockfile_name) == 0)
	{
	    kom_log("Created lock %s\n", param.lockfile_name);
	    return 0;
	}
	
	if (errno != EEXIST)
	    restart_kom("Failed to create lock symlink %s "
83
84
			"pointing to %s: %s\n", param.lockfile_name,
			new_lock, strerror(errno));
Per Cederqvist's avatar
Per Cederqvist committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

	if (retry)
	{
	    kom_log("Lock file recreated by some other party\n");
	    return -1;
	}

	sz = readlink(param.lockfile_name, current_lock, sizeof(current_lock));
	if (sz >= sizeof(current_lock) - 1)
	    restart_kom("Too much data in lock symlink %s\n",
			param.lockfile_name);
	current_lock[sz] = '\0';

	for (ix = 0; ix < sizeof(new_lock); ++ix)
	{
	    if (new_lock[ix] != current_lock[ix])
	    {
102
		kom_log("Database already locked by %s\n", current_lock);
Per Cederqvist's avatar
Per Cederqvist committed
103
104
105
106
107
108
109
110
111
		return -1;
	    }

	    if (new_lock[ix] == ':')
		break;
	}

	pid = strtol(&current_lock[ix+1], &end, 10);
	if (end == &current_lock[ix+1])
112
	    restart_kom("Found a broken lock symlink %s: %s\n",
Per Cederqvist's avatar
Per Cederqvist committed
113
114
115
116
			param.lockfile_name, current_lock);

	if (kill(pid, 0) == 0 || errno != ESRCH)
	{
117
	    kom_log("Database already locked by %s\n", current_lock);
Per Cederqvist's avatar
Per Cederqvist committed
118
119
120
121
122
123
124
125
	    return -1;
	}

	/* The process is dead.  Remove the stale lock file.  If it
	   was just removed by a dying process -- fine.  */
	if (remove(param.lockfile_name) < 0 && errno != ENOENT)
	    restart_kom("Failed to remove stale lock symlink %s\n",
			param.lockfile_name);
126
	else
127
	    kom_log("Removed stale lock file left by %s.\n", current_lock);
Per Cederqvist's avatar
Per Cederqvist committed
128
129
130
131
132
133
134
135
136
137
    }
    restart_kom("Unreachable code reached in lock_db.\n");
}

void
unlock_db(void)
{
    if (remove(param.lockfile_name) < 0)
	restart_kom("Failed to remove lock file %s\n", param.lockfile_name);
}