/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * miav_server.cc * * Sat Aug 21 17:32:24 2004 * Copyright 2004 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of MIaV. * * MIaV 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. * * MIaV 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 MIaV; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ // For ETC #include "config.h" #include "configuration.h" #include "info_console.h" #include "server_status.h" #include #include #include #include "server.h" #include "tcp_socket.h" #include #include // For getpwent and getgrent #include #include #include #ifdef HAVE_GETOPT_H #include #elif defined(HAVE_STDLIB_H) // Solaris has getopt() here #include #else #error "Don't know where getopt() is prototyped" #endif static const char usage_str[] = "Usage: %s [options]\n" "Options:\n" " -c file Read configfile from 'file'\n" " -f Run in foreground mode (non-background mode)\n" " -u user Run as 'user' (overrides the configfile)\n" " -g group Run as 'group' (overrides the configfile)\n" " -h This message\n" ; int main(int argc, char *argv[]) { char *config_file = ETC"/miav.conf"; int optc; int lose = 0; bool foreground = false; char *user_opt = NULL; char *group_opt = NULL; // Parse the commandline while((optc = getopt(argc, argv, "c:fhu:g:")) != EOF) { switch(optc) { case 'c': config_file = strdup(optarg); if(!config_file) { fprintf(stderr, "Fatal: out of memory\n"); return 1; } break; case 'u': user_opt = strdup(optarg); if(!user_opt) { fprintf(stderr, "Fatal: out of memory\n"); return 1; } break; case 'g': group_opt = strdup(optarg); if(!group_opt) { fprintf(stderr, "Fatal: out of memory\n"); return 1; } break; case 'f': foreground = true; break; case 'h': fprintf(stdout, usage_str, argv[0]); return 0; default: lose++; break; } } if(lose) { // Error message was printed by getopt return 1; } fprintf(stderr, "Using config file [%s]\n", config_file); Configuration config(config_file); MIaV::initConfig(&config); InfoConsole info; MIaV::initInfo(&info); std::string user; if(user_opt) user = std::string(user_opt); else { if(config.get("server_user", &user)) info.error("Could not read symbol [server_user] from the conf file!"); } std::string group; if(group_opt) group = std::string(group_opt); else { if(config.get("server_group", &group)) info.error("Could not read symbol [server_group] from the conf file!"); } // Fetch user id int uid = -1; struct passwd *p = getpwent(); while(p) { if(strcmp(p->pw_name, user.c_str()) == 0) uid = p->pw_uid; p = getpwent(); } if(uid == -1) { fprintf(stderr, "Could not find user \"%s\" in /etc/passwd file.\n", user.c_str()); } // Fetch group id int gid = -1; struct group *g = getgrent(); while(g) { if(strcmp(g->gr_name, group.c_str()) == 0) gid = g->gr_gid; g = getgrent(); } if(gid == -1) { fprintf(stderr, "Could not find group \"%s\" in /etc/group file.\n", group.c_str()); } if(!foreground) { fprintf(stderr, "Entering daemon mode\n"); daemon(0,0); signal (SIGTERM, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGHUP, SIG_IGN); } else { fprintf(stderr, "Running in foreground mode.\n"); } int port; if(config.get("server_port", &port)) info.error("Could not read symbol [server_port] from the conf file!"); signal(SIGCLD, SIG_IGN); // Ved SIGCHILD til IGNORE maa wait/waitpid ikke kaldes // (ellers kommer der kernel-brok) pid_t childpid; childpid = fork(); switch(childpid) { case -1: MIaV::info->log("Fork error: %s", strerror(errno)); return 1; case 0: // fork() returns 0 to the child process if(server_status(port)) exit(1); return 0; default: // fork() returns new pid to the parent process break; } MIaV::info->info("Starting MIaV server v. %s", VERSION); MIaV::info->info("Listening on port %d", port); TCPSocket socket(port); /* if(socket.hasError()) { MIaV::info->error("Listening socket has errors, quitting."); return 1; } */ while(1) { TCPSocket csocket; if(socket.listen(&csocket)) { MIaV::info->error("Server socket has errors, quitting. %s", socket.error().c_str()); } /* if(socket.hasError()) { MIaV::info->error("Server socket has errors, quitting."); break; } */ /* if(csocket.hasError()) { MIaV::info->error("Child socket has errors, quitting."); break; } */ /* if(!csocket.isConnected()) { MIaV::info->error("Child socket is not connected, quitting."); break; } */ childpid = fork(); switch(childpid) { case -1: // fork() returns -1 on failure MIaV::info->log("Fork error: %s", strerror(errno)); return 1; case 0: // fork() returns 0 to the child process newConnection(&csocket); return 0; default: // fork() returns new pid to the parent process break; } } return 0; }