Rev 59 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* Copyright (C) 2015 by Andreas Theofilu <andreas@theosys.at>
*
* All rights reserved. No warranty, explicit or implicit, provided.
*
* NOTICE: All information contained herein is, and remains
* the property of Andreas Theofilu and his suppliers, if any.
* The intellectual and technical concepts contained
* herein are proprietary to Andreas Theofilu and its suppliers and
* may be covered by European and Foreign Patents, patents in process,
* and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Andreas Theofilu.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <libgen.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#ifndef __APPLE__
#include <wait.h>
#endif
#include <syslog.h>
#include <errno.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <dirent.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <pwd.h>
#include <grp.h>
#include "config.h"
#include "helplib.h"
#include "mdb.h"
#include "play.h"
#ifndef SIGCLD
# define SIGCLD SIGCHLD
#endif
static pthread_t pthr_pars, pthr_cmds;
struct SOCKETS soc;
/* Prototypes */
void daemon_start(int ignsigcld);
void sig_child (int x);
void changeToUser(char *, char *);
void *pthr_parser(void *pV_data);
void *thread_wait(void *pV_data);
int main(int argc, char **argv)
{
readConf();
memset (&playCurrent, 0, sizeof(ST_PLAYING));
/* Now daemonize this application */
daemon_start(1);
changeToUser(&configs.User[0], &configs.Grp[0]);
handleInit();
/* Prepare the thread attributes */
if (pthread_attr_init(&pattr) != 0)
{
syslog(LOG_DAEMON,"Error getting thread attributes.");
return FALSE;
}
if (pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED) != 0)
{
syslog(LOG_DAEMON,"Error setting thread attributes.");
return FALSE;
}
/* Now start our Thread */
if (pthread_create(&pthr_pars, &pattr, pthr_parser, (void *)0) != 0)
{
syslog (LOG_DAEMON, "Create of thread \"pthr_parser\" failed!");
return 1;
}
while (1)
sleep(3600);
return 0;
}
/*
* Detach application from console and make it a daemon.
*/
void daemon_start (int ignsigcld)
{
int childpid, fd;
char hv0[64];
if (getpid () == 1)
goto out;
#ifdef SIGTTOU
signal (SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal (SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal (SIGTSTP, SIG_IGN);
#endif
if ((childpid = fork ()) < 0)
fprintf (stderr, "Can't fork this child\n");
else if (childpid > 0)
exit (0); /* Parent */
if (setpgrp () == -1)
fprintf (stderr, "Can't change process group\n");
signal (SIGHUP, SIG_IGN);
if ((childpid = fork ()) < 0)
syslog (LOG_DAEMON, "Can't fork second child");
else if (childpid > 0)
exit (0); /* first child */
/* second child */
out:
for (fd = 0; fd < NOFILE; fd++)
close (fd);
errno = 0;
chdir ("/");
umask (0);
#ifdef SIGCLD
if (ignsigcld)
signal (SIGCLD, SIG_IGN);
else
signal(SIGCLD, &sig_child);
#endif
/* Create PID file */
if ((fd = open(configs.Pidfile, O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
{
syslog(LOG_WARNING, "Can't create PID file %s: %s", configs.Pidfile, strerror(errno));
return;
}
sprintf(&hv0[0], "%d", getpid());
write(fd, hv0, strlen(hv0));
close(fd);
}
void sig_child (int x)
{
#if defined(BSD) && !defined(sinix) && !defined(Linux)
int pid;
int status;
while ((pid = wait4 (0, &status, WNOHANG, (struct rusage *)0)) > 0)
sleep(1);
#endif
}
void changeToUser(char *usr, char *grp)
{
gid_t gr_gid;
if (usr && strlen(usr))
{
/* get uid */
struct passwd *userpwd;
struct group *usergrp = NULL;
if ((userpwd = getpwnam(usr)) == NULL)
{
syslog(LOG_DAEMON, "no such user: %s", usr);
exit(EXIT_FAILURE);
}
if (grp != NULL && strlen(grp) && (usergrp = getgrnam(grp)) == NULL)
{
if (grp && strlen(grp))
syslog(LOG_WARNING, "no such group: %s", grp);
gr_gid = userpwd->pw_gid;
}
else if (usergrp != NULL)
gr_gid = usergrp->gr_gid;
else
gr_gid = userpwd->pw_gid;
if (setgid(gr_gid) == -1)
{
syslog(LOG_DAEMON, "cannot setgid of user %s: %s", usr, strerror(errno));
exit(EXIT_FAILURE);
}
#ifdef _BSD_SOURCE
/* init suplementary groups
* (must be done before we change our uid)
*/
if (initgroups(usr, gr_gid) == -1)
syslog(LOG_DAEMON, "cannot init suplementary groups of user %s: %s", usr, strerror(errno));
#endif
/* set uid */
if (setuid(userpwd->pw_uid) == -1)
{
syslog(LOG_DAEMON, "cannot change to uid of user %s: %s\n", usr, strerror(errno));
exit(EXIT_FAILURE);
}
if (userpwd->pw_dir)
setenv("HOME", userpwd->pw_dir, 1);
}
}
void *pthr_parser(void *pV_data)
{
char str[INET_ADDRSTRLEN];
/* socket structure */
struct sockaddr_in client1, server1;
struct servent *serviceInfo;
int s1, s;
socklen_t length;
/* struct SOCKETS soc; */
/* socket server */
if (configs.port > 0)
server1.sin_port = htons(configs.port);
else if ((serviceInfo = getservbyname ("mdb", "tcp")))
server1.sin_port = serviceInfo->s_port;
else
{
syslog(LOG_DAEMON,"Error: No TCP port defined!");
pthread_exit(NULL);
exit(EXIT_FAILURE);
}
server1.sin_family = AF_INET;
server1.sin_addr.s_addr = INADDR_ANY;
s = socket(AF_INET,SOCK_STREAM,0);
if (s < 0)
{
syslog (LOG_DAEMON, "Error in socket: %s",strerror(errno));
pthread_exit(NULL);
exit(EXIT_FAILURE);
}
if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
{
syslog (LOG_DAEMON, "Error in bind: %s", strerror(errno));
pthread_exit(NULL);
exit(EXIT_FAILURE);
}
if (listen (s, 5) < 0)
{
syslog (LOG_DAEMON, "Error in listen: %s", strerror(errno));
pthread_exit(NULL);
exit(EXIT_FAILURE);
}
length = sizeof(client1);
syslog (LOG_DEBUG, "Server ready: %d",s);
while (1)
{
/* int childpid, status; */
if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
{
syslog (LOG_DAEMON, "Error in accept: %d: %s", s1, strerror(errno));
continue;
}
inet_ntop(AF_INET, &(client1.sin_addr), str, INET_ADDRSTRLEN);
syslog (LOG_INFO, "Connected to client %s", str);
soc.sockfd = s;
soc.newfd = s1;
/* start a new thread to parse the commands */
if (pthread_create(&pthr_cmds, &pattr, processCommands, (void *)&soc) != 0)
{
syslog (LOG_DAEMON,"Creation of thread \"pthr_cmds\" failed!");
close(s1);
close(s);
pthread_exit(NULL);
return NULL;
}
/* if ((childpid = fork()) < 0)
syslog(LOG_DAEMON, "Can't fork a child: %s", strerror(errno));
if (childpid == 0)
{
/ Child process /
processCommands((void *)&soc);
exit(EXIT_SUCCESS);
}
#if defined(BSD) && !defined(Linux)
while (wait3 (&status, WNOHANG, (struct rusage *)0) > 0)
sleep(1);
#else
while (waitpid(-1, &status, WNOHANG) > 0)
sleep(1);
#endif
close(s1); */
}
close (s);
pthread_exit(NULL);
return NULL;
}