1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-06-09 06:10:42 +00:00

Add support for writing PID files

This commit is contained in:
Moritz Grimm 2017-07-10 11:39:00 +02:00
parent 781cfc12c7
commit 43e26549f9
11 changed files with 161 additions and 19 deletions

2
NEWS
View File

@ -12,6 +12,8 @@ Changes in 1.0.0, released on XXXX-XX-XX:
* The configuration file structure has changed.
* TagLib (its C wrapper library) is now a mandatory dependency
* Support the new '@b@' placeholder for separate album metadata.
* The command line option -p has been added, causing ezstream to write a
locked PID file to a given location
Changes in 0.6.0, released on 2015-01-18:

View File

@ -20,6 +20,7 @@
.Bk -words
.Op Fl hqrVv
.Fl c Ar configfile
.Op Fl p Ar pidfile
.Ek
.Nm
.Bk -words
@ -45,6 +46,20 @@ Use the XML configuration in
.It Fl h
Print a summary of available command line arguments with short descriptions
and exit.
.It Fl p Ar pidfile
Write the
.Nm
process ID
.Pq a single number
to
.Ar pidfile .
The file will be written even when it already exists.
A file lock is maintained until the main
.Nm
process terminates.
If the file cannot be written for any reason,
.Nm
will log this, but not consider it a fatal error.
.It Fl q
Be more quiet.
Suppress the output that external programs send to standard error.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (c) 2015, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -277,6 +277,13 @@ cfg_set_program_config_file(const char *file, const char **errstrp)
return (0);
}
int
cfg_set_program_pid_file(const char *file, const char **errstrp)
{
SET_STRLCPY(cfg.program.pid_file, file, errstrp);
return (0);
}
int
cfg_set_program_quiet_stderr(int quiet_stderr, const char **not_used)
{
@ -642,6 +649,12 @@ cfg_get_program_config_file(void)
return (cfg.program.config_file[0] ? cfg.program.config_file : NULL);
}
const char *
cfg_get_program_pid_file(void)
{
return (cfg.program.pid_file[0] ? cfg.program.pid_file : NULL);
}
int
cfg_get_program_quiet_stderr(void)
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (c) 2015, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -91,6 +91,7 @@ int cfg_file_check(const char *);
int cfg_set_program_name(const char *, const char **);
int cfg_set_program_config_type(enum cfg_config_type, const char **);
int cfg_set_program_config_file(const char *, const char **);
int cfg_set_program_pid_file(const char *, const char **);
int cfg_set_program_quiet_stderr(int, const char **);
int cfg_set_program_rtstatus_output(int, const char **);
int cfg_set_program_verbosity(unsigned int, const char **);
@ -137,6 +138,8 @@ enum cfg_config_type
cfg_get_program_config_type(void);
const char *
cfg_get_program_config_file(void);
const char *
cfg_get_program_pid_file(void);
int cfg_get_program_quiet_stderr(void);
int cfg_get_program_rtstatus_output(void);
unsigned int

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (c) 2015, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -37,6 +37,7 @@ struct cfg {
char name[PATH_MAX];
enum cfg_config_type config_type;
char config_file[PATH_MAX];
char pid_file[PATH_MAX];
int quiet_stderr;
int rtstatus_output;
unsigned int verbosity;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (c) 2015, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -32,10 +32,11 @@
#include "cmdline.h"
#include "playlist.h"
#define OPTSTRING "c:hqrs:Vv"
#define OPTSTRING "c:hp:qrs:Vv"
enum opt_vals {
OPT_CONFIGFILE = 'c',
OPT_HELP = 'h',
OPT_PIDFILE = 'p',
OPT_QUIETSTDERR = 'q',
OPT_RTSTATUS = 'r',
OPT_SHUFFLEFILE = 's',
@ -51,7 +52,7 @@ static void _set_program_name(const char *);
static void
_usage(void)
{
fprintf(stderr, "usage: %s [-hqrVv] -c cfgfile\n",
fprintf(stderr, "usage: %s [-hqrVv] -c cfgfile [-p pidfile]\n",
cfg_get_program_name());
fprintf(stderr, " %s -s file\n",
cfg_get_program_name());
@ -63,6 +64,7 @@ _usage_help(void)
fprintf(stderr, "\n");
fprintf(stderr, " -c cfgfile use XML configuration in cfgfile\n");
fprintf(stderr, " -h print this help and exit\n");
fprintf(stderr, " -p pidfile write PID to pidfile\n");
fprintf(stderr, " -q suppress STDERR output from external en-/decoders\n");
fprintf(stderr, " -r show real-time stream information on stdout\n");
fprintf(stderr, " -s file read lines from file, shuffle, print to STDOUT, then exit\n");
@ -125,6 +127,15 @@ cmdline_parse(int argc, char *argv[], int *ret_p)
_usage_help();
*ret_p = 0;
return (-1);
case OPT_PIDFILE:
if (0 > cfg_set_program_pid_file(optarg, &err_str)) {
fprintf(stderr, "-%c: argument %s\n",
OPT_PIDFILE, err_str);
_usage();
*ret_p = 2;
return (-1);
}
break;
case OPT_RTSTATUS:
cfg_set_program_rtstatus_output(1, NULL);
/* FALLTHROUGH */

View File

@ -1,7 +1,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009, 2015 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (C) 2007, 2009, 2015, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -801,6 +801,9 @@ main(int argc, char *argv[])
return (ez_shutdown(1));
}
if (0 > writePidfile(cfg_get_program_pid_file()))
log_syserr(WARNING, errno, cfg_get_program_pid_file());
if (0 > stream_connect(stream)) {
log_error("initial server connection failed");
return (ez_shutdown(1));

View File

@ -1,7 +1,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007, 2009 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (C) 2007, 2009, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -24,6 +24,9 @@
#include "compat.h"
#include <sys/types.h>
#include <sys/file.h>
#include <ctype.h>
#include <errno.h>
#include <langinfo.h>
@ -31,12 +34,12 @@
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_ICONV
# include <iconv.h>
#endif
#include "cfg.h"
#include "log.h"
#include "util.h"
#include "xalloc.h"
@ -45,7 +48,13 @@
# define BUFSIZ 1024
#endif
char * iconvert(const char *, const char *, const char *, int);
static char *pidfile_path;
static FILE *pidfile_file;
static pid_t pidfile_pid;
static unsigned int pidfile_numlocks;
static char * iconvert(const char *, const char *, const char *, int);
static void cleanupPidfile(void);
int
strrcmp(const char *s, const char *sub)
@ -105,7 +114,7 @@ UTF8toCHAR(const char *in_str, int mode)
return (iconvert(in_str, "UTF-8", codeset, mode));
}
char *
static char *
iconvert(const char *in_str, const char *from, const char *to, int mode)
{
#ifdef HAVE_ICONV
@ -205,6 +214,64 @@ iconvert(const char *in_str, const char *from, const char *to, int mode)
#endif /* HAVE_ICONV */
}
static void
cleanupPidfile(void)
{
if (NULL != pidfile_path && getpid() == pidfile_pid) {
(void)unlink(pidfile_path);
(void)fclose(pidfile_file);
}
}
int
writePidfile(const char *path)
{
int save_errno = 0;
pid_t pid;
if (NULL == path)
return (0);
xfree(pidfile_path);
pidfile_path = xstrdup(path);
if (NULL != pidfile_file)
fclose(pidfile_file);
if (NULL == (pidfile_file = fopen(pidfile_path, "w"))) {
save_errno = errno;
xfree(pidfile_path);
pidfile_path = NULL;
return (-1);
}
pid = getpid();
if (0 >= fprintf(pidfile_file, "%ld\n", (long)pid) ||
0 > fflush(pidfile_file) ||
0 > flock(fileno(pidfile_file), LOCK_EX))
goto error;
if (0 == pidfile_numlocks) {
pidfile_pid = pid;
if (0 != atexit(cleanupPidfile))
goto error;
pidfile_numlocks++;
}
return (0);
error:
save_errno = errno;
(void)unlink(pidfile_path);
xfree(pidfile_path);
pidfile_path = NULL;
(void)fclose(pidfile_file);
pidfile_file = NULL;
pidfile_pid = 0;
errno = save_errno;
return (-1);
}
char *
replaceString(const char *source, const char *from, const char *to)
{

View File

@ -1,7 +1,7 @@
/*
* ezstream - source client for Icecast with external en-/decoder support
* Copyright (C) 2003, 2004, 2005, 2006 Ed Zaleski <oddsock@oddsock.org>
* Copyright (C) 2007 Moritz Grimm <mgrimm@mrsserver.net>
* Copyright (C) 2007, 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -20,12 +20,13 @@
#define ICONV_TRANSLIT 1
#define ICONV_IGNORE 2
int strrcmp(const char *, const char *);
int strrcasecmp(const char *, const char *);
char * CHARtoUTF8(const char *, int);
char * UTF8toCHAR(const char *, int);
char * replaceString(const char *, const char *, const char *);
char * shellQuote(const char *);
int urlParse(const char *, char **, unsigned short *, char **);
int writePidfile(const char *);
int strrcmp(const char *, const char *);
int strrcasecmp(const char *, const char *);
char * CHARtoUTF8(const char *, int);
char * UTF8toCHAR(const char *, int);
char * replaceString(const char *, const char *, const char *);
char * shellQuote(const char *);
int urlParse(const char *, char **, unsigned short *, char **);
#endif /* __UTIL_H__ */

View File

@ -207,6 +207,14 @@ START_TEST(test_program_config_file)
}
END_TEST
START_TEST(test_program_pid_file)
{
ck_assert_ptr_eq(cfg_get_program_pid_file(), NULL);
TEST_STRLCPY(cfg_set_program_pid_file, cfg_get_program_pid_file,
PATH_MAX);
}
END_TEST
START_TEST(test_program_quiet_stderr)
{
ck_assert_int_eq(cfg_set_program_quiet_stderr(-1, NULL), 0);
@ -808,6 +816,7 @@ cfg_suite(void)
tcase_add_test(tc_program, test_program_name);
tcase_add_test(tc_program, test_program_config_type);
tcase_add_test(tc_program, test_program_config_file);
tcase_add_test(tc_program, test_program_pid_file);
tcase_add_test(tc_program, test_program_quiet_stderr);
tcase_add_test(tc_program, test_program_rtstatus_output);
tcase_add_test(tc_program, test_program_verbosity);

View File

@ -33,6 +33,22 @@ START_TEST(test_help)
}
END_TEST
START_TEST(test_pidfile)
{
char *argv[] =
{
"check_cmdline", "-p", "PIDFILE-TEST" , NULL
};
int argc = (int)(sizeof(argv) / sizeof(argv[0])) - 1;
int ret;
ck_assert_ptr_eq(cfg_get_program_pid_file(), NULL);
ck_assert_int_ne(cmdline_parse(argc, argv, &ret), 0);
ck_assert_int_eq(ret, 2);
ck_assert_str_eq(cfg_get_program_pid_file(), "PIDFILE-TEST");
}
END_TEST
START_TEST(test_quiet_stderr)
{
char *argv[] = { "check_cmdline", "-q", NULL };
@ -133,6 +149,7 @@ cmdline_suite(void)
tcase_add_checked_fixture(tc_cmdline, setup_checked, teardown_checked);
tcase_add_test(tc_cmdline, test_configfile);
tcase_add_test(tc_cmdline, test_help);
tcase_add_test(tc_cmdline, test_pidfile);
tcase_add_test(tc_cmdline, test_quiet_stderr);
tcase_add_test(tc_cmdline, test_rtstatus_output);
tcase_add_test(tc_cmdline, test_shuffle);