Merge branch 'darktohka/dblock' into 'master'
Ignore database locks if the process that locked the database no longer exists See merge request pacman/pacman!231
This commit is contained in:
commit
d9e5a06fe6
7 changed files with 110 additions and 15 deletions
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -135,10 +136,59 @@ int _alpm_handle_lock(alpm_handle_t *handle)
|
||||||
FREE(dir);
|
FREE(dir);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
handle->lockfd = open(handle->lockfile, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
|
handle->lockfd = open(handle->lockfile, O_RDWR | O_CREAT | O_CLOEXEC, 0000);
|
||||||
} while(handle->lockfd == -1 && errno == EINTR);
|
} while(handle->lockfd == -1 && errno == EINTR);
|
||||||
|
|
||||||
return (handle->lockfd >= 0 ? 0 : -1);
|
if(handle->lockfd < 0) {
|
||||||
|
/* failed to open lock for writing */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lock opened */
|
||||||
|
/* check the pid */
|
||||||
|
pid_t pid = getpid();
|
||||||
|
char buf[12];
|
||||||
|
ssize_t bytesread = read(handle->lockfd, buf, sizeof(buf) - 1);
|
||||||
|
|
||||||
|
buf[bytesread] = '\0';
|
||||||
|
pid_t lockedpid;
|
||||||
|
|
||||||
|
if(sscanf(buf, "%d", &lockedpid) == 1 && kill(lockedpid, 0) == 0 && errno != ESRCH) {
|
||||||
|
/* could not grab lock */
|
||||||
|
/* old pid is still active */
|
||||||
|
close(handle->lockfd);
|
||||||
|
handle->lockfd = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write pid to lock */
|
||||||
|
/* first allocate string for pid */
|
||||||
|
char *pidstr = NULL;
|
||||||
|
int len = asprintf(&pidstr, "%d\n", pid);
|
||||||
|
|
||||||
|
if(len == -1) {
|
||||||
|
_alpm_log(handle, ALPM_LOG_ERROR, "alloc failure: could not allocate pid");
|
||||||
|
close(handle->lockfd);
|
||||||
|
unlink(handle->lockfile);
|
||||||
|
handle->lockfd = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally write pid to lock */
|
||||||
|
int writtenbytes = write(handle->lockfd, pidstr, len);
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
FREE(pidstr);
|
||||||
|
|
||||||
|
if(writtenbytes != len) {
|
||||||
|
_alpm_log(handle, ALPM_LOG_ERROR, "could not write pid to lockfile");
|
||||||
|
close(handle->lockfd);
|
||||||
|
unlink(handle->lockfile);
|
||||||
|
handle->lockfd = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SYMEXPORT alpm_unlock(alpm_handle_t *handle)
|
int SYMEXPORT alpm_unlock(alpm_handle_t *handle)
|
||||||
|
|
31
scripts/libmakepkg/util/lock.sh.in
Normal file
31
scripts/libmakepkg/util/lock.sh.in
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# lock.sh - functions to handle pacman locking
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024 Pacman Development Team <pacman-dev@lists.archlinux.org>
|
||||||
|
#
|
||||||
|
# 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
is_pacman_locked() {
|
||||||
|
local lockfile="$(pacman-conf DBPath)/db.lck"
|
||||||
|
if [[ -f $lockfile ]]; then
|
||||||
|
local pid=$(<"$lockfile")
|
||||||
|
# Check if the pid is valid and the process is still running
|
||||||
|
if [[ -n $pid && $pid =~ ^[0-9]+$ && -d /proc/$pid ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ sources = [
|
||||||
'config.sh.in',
|
'config.sh.in',
|
||||||
'dirsize.sh.in',
|
'dirsize.sh.in',
|
||||||
'error.sh.in',
|
'error.sh.in',
|
||||||
|
'lock.sh.in',
|
||||||
'message.sh.in',
|
'message.sh.in',
|
||||||
'option.sh.in',
|
'option.sh.in',
|
||||||
'parseopts.sh.in',
|
'parseopts.sh.in',
|
||||||
|
|
|
@ -243,14 +243,11 @@ run_pacman() {
|
||||||
else
|
else
|
||||||
cmd=(su root -c "$cmdescape")
|
cmd=(su root -c "$cmdescape")
|
||||||
fi
|
fi
|
||||||
local lockfile="$(pacman-conf DBPath)/db.lck"
|
local timer=0
|
||||||
while [[ -f $lockfile ]]; do
|
while is_pacman_locked && (( timer < 10 )); do
|
||||||
local timer=0
|
(( ++timer ))
|
||||||
msg "$(gettext "Pacman is currently in use, please wait...")"
|
msg "$(gettext "Pacman is currently in use, please wait...")"
|
||||||
while [[ -f $lockfile ]] && (( timer < 10 )); do
|
sleep 3
|
||||||
(( ++timer ))
|
|
||||||
sleep 3
|
|
||||||
done
|
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
"${cmd[@]}"
|
"${cmd[@]}"
|
||||||
|
|
|
@ -30,6 +30,7 @@ declare -r myver='@PACKAGE_VERSION@'
|
||||||
MAKEPKG_LIBRARY=${MAKEPKG_LIBRARY:-'@libmakepkgdir@'}
|
MAKEPKG_LIBRARY=${MAKEPKG_LIBRARY:-'@libmakepkgdir@'}
|
||||||
|
|
||||||
# Import libmakepkg
|
# Import libmakepkg
|
||||||
|
source "$MAKEPKG_LIBRARY"/util/lock.sh
|
||||||
source "$MAKEPKG_LIBRARY"/util/message.sh
|
source "$MAKEPKG_LIBRARY"/util/message.sh
|
||||||
source "$MAKEPKG_LIBRARY"/util/parseopts.sh
|
source "$MAKEPKG_LIBRARY"/util/parseopts.sh
|
||||||
|
|
||||||
|
@ -132,15 +133,18 @@ fi
|
||||||
|
|
||||||
# strip any trailing slash from our dbroot
|
# strip any trailing slash from our dbroot
|
||||||
dbroot="${dbroot%/}"
|
dbroot="${dbroot%/}"
|
||||||
|
|
||||||
|
# make sure pacman isn't running
|
||||||
|
if is_pacman_locked; then
|
||||||
|
die "$(gettext "Pacman lock file was found. Cannot run while pacman is running.")"
|
||||||
|
fi
|
||||||
|
|
||||||
# form the path to our lockfile location
|
# form the path to our lockfile location
|
||||||
lockfile="${dbroot}/db.lck"
|
lockfile="${dbroot}/db.lck"
|
||||||
|
|
||||||
# make sure pacman isn't running
|
|
||||||
if [[ -f $lockfile ]]; then
|
|
||||||
die "$(gettext "Pacman lock file was found. Cannot run while pacman is running.")"
|
|
||||||
fi
|
|
||||||
# do not let pacman run while we do this
|
# do not let pacman run while we do this
|
||||||
touch "$lockfile"
|
# write our pid to the lockfile
|
||||||
|
echo $$ > "$lockfile"
|
||||||
|
|
||||||
if [[ -f "${dbroot}"/local/ALPM_DB_VERSION ]]; then
|
if [[ -f "${dbroot}"/local/ALPM_DB_VERSION ]]; then
|
||||||
db_version=$(cat "${dbroot}"/local/ALPM_DB_VERSION)
|
db_version=$(cat "${dbroot}"/local/ALPM_DB_VERSION)
|
||||||
|
|
|
@ -232,7 +232,7 @@ class pmtest(object):
|
||||||
return files
|
return files
|
||||||
|
|
||||||
def run(self, pacman):
|
def run(self, pacman):
|
||||||
if os.path.isfile(util.PM_LOCK):
|
if util.ispacmanlocked():
|
||||||
tap.bail("\tERROR: another pacman session is on-going -- skipping")
|
tap.bail("\tERROR: another pacman session is on-going -- skipping")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -184,3 +184,15 @@ def mkdir(path):
|
||||||
elif os.path.isfile(path):
|
elif os.path.isfile(path):
|
||||||
raise OSError("'%s' already exists and is not a directory" % path)
|
raise OSError("'%s' already exists and is not a directory" % path)
|
||||||
os.makedirs(path, 0o755)
|
os.makedirs(path, 0o755)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Locking
|
||||||
|
#
|
||||||
|
def ispacmanlocked():
|
||||||
|
if not os.path.exists(PM_LOCK):
|
||||||
|
return False
|
||||||
|
|
||||||
|
with open(PM_LOCK, 'r') as f:
|
||||||
|
pid = f.read().strip()
|
||||||
|
|
||||||
|
return pid.isdigit() and os.path.exists(f'/proc/{pid}')
|
||||||
|
|
Loading…
Add table
Reference in a new issue