Commit 9613d8fe authored by Daniel Salzman's avatar Daniel Salzman

knot: process functions cleanup

parent 38ab4787
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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
......@@ -14,26 +14,25 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <grp.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <urcu.h>
#include "knot/common/log.h"
#include "knot/common/pid.h"
#include "knot/common/process.h"
#include "knot/conf/conf.h"
#include "libknot/libknot.h"
#include "libknot/errcode.h"
char* pid_filename()
static char* pid_filename()
{
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_RUNDIR);
......@@ -46,64 +45,64 @@ char* pid_filename()
return pidfile;
}
pid_t pid_read(const char* fn)
static pid_t pid_read(const char *filename)
{
char buf[64];
if (fn) {
FILE *fp = fopen(fn, "r");
if (!fp) {
return KNOT_ENOENT;
}
if (filename == NULL) {
return 0;
}
int readb = 0;
int rc = fread(buf, 1, 1, fp);
while (rc > 0) {
if (++readb == sizeof(buf) - 1) {
break;
}
rc = fread(buf + readb, 1, 1, fp);
}
buf[readb] = '\0';
fclose(fp);
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
return 0;
}
// Check read result
if (readb < 1) {
return KNOT_ENOENT;
char buf[64];
int readb = 0;
while (fread(buf + readb, 1, 1, fp) > 0) {
if (++readb >= sizeof(buf) - 1) {
break;
}
}
buf[readb] = '\0';
fclose(fp);
// Convert pid
char* ep = 0;
unsigned long pid = strtoul(buf, &ep, 10);
if ((errno == ERANGE) ||
(*ep && !isspace((unsigned char)(*ep)))) {
return KNOT_ERANGE;
}
/* Check read result. */
if (readb < 1) {
return 0;
}
return (pid_t)pid;
/* Convert pid. */
errno = 0;
char *end = 0;
unsigned long pid = strtoul(buf, &end, 10);
if (end == buf || *end != '\0'|| errno != 0) {
return 0;
}
return KNOT_EINVAL;
return (pid_t)pid;
}
int pid_write(const char* fn)
static int pid_write(const char *filename)
{
if (!fn)
if (filename == NULL) {
return KNOT_EINVAL;
}
/* Convert. */
char buf[64];
int len = 0;
len = snprintf(buf, sizeof(buf), "%lu", (unsigned long) getpid());
if (len < 0)
return KNOT_EINVAL;
len = snprintf(buf, sizeof(buf), "%lu", (unsigned long)getpid());
if (len < 0 || len >= sizeof(buf)) {
return KNOT_ENOMEM;
}
/* Create file. */
int ret = KNOT_EOK;
int fd = open(fn, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP);
int fd = open(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP);
if (fd >= 0) {
if (write(fd, buf, len) != len)
ret = KNOT_ERROR;
if (write(fd, buf, len) != len) {
ret = knot_map_errno();
}
close(fd);
} else {
ret = knot_map_errno();
......@@ -112,16 +111,44 @@ int pid_write(const char* fn)
return ret;
}
int pid_remove(const char* fn)
char *pid_check_and_create()
{
if (unlink(fn) < 0) {
return KNOT_EINVAL;
struct stat st;
char *pidfile = pid_filename();
pid_t pid = pid_read(pidfile);
/* Check PID for existence and liveness. */
if (pid > 0 && pid_running(pid)) {
log_error("server PID found, already running");
free(pidfile);
return NULL;
} else if (stat(pidfile, &st) == 0) {
log_warning("removing stale PID file '%s'", pidfile);
pid_cleanup(pidfile);
}
return KNOT_EOK;
/* Create a PID file. */
int ret = pid_write(pidfile);
if (ret != KNOT_EOK) {
log_error("failed to create a PID file '%s' (%s)", pidfile,
knot_strerror(ret));
free(pidfile);
return NULL;
}
return pidfile;
}
int pid_running(pid_t pid)
void pid_cleanup()
{
char *pidfile = pid_filename();
if (pidfile != NULL) {
(void)unlink(pidfile);
free(pidfile);
}
}
bool pid_running(pid_t pid)
{
return kill(pid, 0) == 0;
}
......@@ -139,7 +166,7 @@ int proc_update_privileges(int uid, int gid)
struct passwd *pw;
if ((pw = getpwuid(uid)) == NULL) {
log_warning("failed to get passwd entry for UID '%d' (%s)",
uid, strerror(errno));
uid, strerror(errno));
} else {
if (initgroups(pw->pw_name, gid) < 0) {
log_warning("failed to set supplementary groups "
......@@ -155,41 +182,16 @@ int proc_update_privileges(int uid, int gid)
log_info("changing GID to '%d'", gid);
if (setregid(gid, gid) < 0) {
log_error("failed to change GID to '%d'", gid);
return KNOT_ERROR;
}
}
if ((uid_t)uid != getuid()) {
log_info("changing UID to '%d'", uid);
if (setreuid(uid, uid) < 0) {
log_error("failed to change UID to '%d'", uid);
return KNOT_ERROR;
}
}
return KNOT_EOK;
}
char *pid_check_and_create()
{
struct stat st;
char* pidfile = pid_filename();
pid_t pid = pid_read(pidfile);
/* Check PID for existence and liveness. */
if (pid > 0 && pid_running(pid)) {
log_error("server PID found, already running");
free(pidfile);
return NULL;
} else if (stat(pidfile, &st) == 0) {
log_warning("removing stale PID file '%s'", pidfile);
pid_remove(pidfile);
}
/* Create a PID file. */
int ret = pid_write(pidfile);
if (ret != KNOT_EOK) {
log_error("failed to create a PID file '%s'", pidfile);
free(pidfile);
return NULL;
}
return pidfile;
}
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
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
......@@ -14,63 +14,33 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file process.h
*
* \author Marek Vavrusa <marek.vavrusa@nic.cz>
* \file
*
* \brief Functions for POSIX process handling.
*
* \addtogroup ctl
* \addtogroup knot
* @{
*/
#pragma once
#include <stdbool.h>
#include <unistd.h>
/*!
* \brief Return a filename of the default compiled database file.
*
* \retval Filename of the database file.
* \retval NULL if not exists.
*/
char* pid_filename();
/*!
* \brief Read PID from given file.
*
* \param fn Filename containing PID.
*
* \retval PID on success (positive integer).
* \retval KNOT_EINVAL on null path.
* \retval KNOT_ENOENT if the filename content cannot be read.
* \retval KNOT_ERANGE if the stored PID is out of range.
*/
pid_t pid_read(const char* fn);
/*!
* \brief Write PID to given file.
*
* \param fn Filename containing PID.
* \brief Check if PID file exists and create it if possible.
*
* \retval KNOT_EOK on success.
* \retval KNOT_EINVAL on null path.
* \retval KNOT_ENOENT filename cannot be opened for writing.
* \retval KNOT_ERROR unspecified error.
* \retval NULL if failed.
* \retval Created PID file path.
*/
int pid_write(const char* fn);
char *pid_check_and_create();
/*!
* \brief Remove file containing PID.
* \brief Remove PID file.
*
* \param fn Filename containing PID.
*
* \warning Filename content won't be checked.
*
* \retval KNOT_EOK on success.
* \retval KNOT_EINVAL failed to remove filename.
* \warning PID file content won't be checked.
*/
int pid_remove(const char* fn);
void pid_cleanup();
/*!
* \brief Return true if the PID is running.
......@@ -80,7 +50,7 @@ int pid_remove(const char* fn);
* \retval 1 if running.
* \retval 0 if not running (or error).
*/
int pid_running(pid_t pid);
bool pid_running(pid_t pid);
/*!
* \brief Update process privileges to new UID/GID.
......@@ -93,11 +63,4 @@ int pid_running(pid_t pid);
*/
int proc_update_privileges(int uid, int gid);
/*!
* \brief Check if PID file exists and create it if possible.
* \retval NULL if failed
* \retval Created PID file path
*/
char *pid_check_and_create();
/*! @} */
......@@ -108,14 +108,6 @@ static int make_daemon(int nochdir, int noclose)
return 0;
}
/*! \brief PID file cleanup handler. */
static void pid_cleanup(char *pidfile)
{
if (pidfile && pid_remove(pidfile) < 0) {
log_warning("failed to remove PID file");
}
}
/*! \brief SIGINT signal handler. */
static void interrupt_handle(int signum)
{
......@@ -414,9 +406,8 @@ int main(int argc, char **argv)
/* Check and create PID file. */
long pid = (long)getpid();
char *pidfile = NULL;
if (daemonize) {
pidfile = pid_check_and_create();
char *pidfile = pid_check_and_create();
if (pidfile == NULL) {
server_wait(&server);
server_deinit(&server);
......@@ -426,6 +417,7 @@ int main(int argc, char **argv)
}
log_info("PID stored in '%s'", pidfile);
free(pidfile);
if (chdir(daemon_root) != 0) {
log_warning("failed to change working directory to %s",
daemon_root);
......@@ -455,7 +447,7 @@ int main(int argc, char **argv)
server_wait(&server);
server_deinit(&server);
rcu_unregister_thread();
pid_cleanup(pidfile);
pid_cleanup();
log_close();
conf_free(conf(), false);
return EXIT_FAILURE;
......@@ -478,6 +470,9 @@ int main(int argc, char **argv)
log_info("updating zone timers database");
write_timer_db(server.timers_db, server.zone_db);
/* Cleanup PID file. */
pid_cleanup();
/* Free server and configuration. */
server_deinit(&server);
conf_free(conf(), false);
......@@ -485,9 +480,6 @@ int main(int argc, char **argv)
/* Unhook from RCU. */
rcu_unregister_thread();
/* Cleanup PID file. */
pid_cleanup(pidfile);
log_info("shutting down");
log_close();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment