[devel] getopt
Alexey Tourbin
=?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Чт Июн 19 23:11:40 MSD 2003
Господа, есть такой код, который парсит аргументы командной строки два
раза, и оба -- без использования getopt. Как его лучше переписать?
----------- следующая часть -----------
/* main.c - Command line parsing, intialisation and server start
Copyright (C) 2000, 2001 Thomas Moestl
This file is part of the pdnsd package.
pdnsd 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, or (at your option)
any later version.
pdnsd 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 pdsnd; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* in order to use O_NOFOLLOW on Linux: */
#define _GNU_SOURCE
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <syslog.h>
#include <pwd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "consts.h"
#include "cache.h"
#include "status.h"
#include "servers.h"
#include "dns_answer.h"
#include "dns_query.h"
#include "error.h"
#include "helpers.h"
#include "icmp.h"
#if !defined(lint) && !defined(NO_RCSIDS)
static char rcsid[]="$Id: main.c,v 1.42 2001/05/30 21:04:15 tmm Exp $";
#endif
#ifdef DEBUG_YY
extern int yydebug;
#endif
int daemon_p=0;
int debug_p=0;
int verbosity=VERBOSITY;
pthread_t main_thread;
#if DEBUG>0
FILE *dbg_file;
#endif
#ifdef ENABLE_IPV4
int run_ipv4=DEFAULT_IPV4;
#endif
#ifdef ENABLE_IPV6
int run_ipv6=DEFAULT_IPV6;
#endif
int tcp_socket=-1;
int udp_socket=-1;
sigset_t sigs_msk;
char pidfile[MAXPATH]="\0";
int stat_pipe=0;
int notcp=0;
int sigr=0;
/* These are some init steps we have to call before we get daemon on linux, but need
* do call after daemonizing on other OSes.
* Theay are also the last steps before we drop privileges. */
int final_init()
{
#ifndef NO_TCP_SERVER
if (!notcp)
tcp_socket=init_tcp_socket();
#endif
udp_socket=init_udp_socket();
if (tcp_socket==-1 && udp_socket==-1) {
log_error("tcp and udp initialization failed. Exiting.");
exit(1);
}
if (global.strict_suid) {
if (!run_as(global.run_as)) {
log_error("Could not change user and group id to those of run_as user %s",global.run_as);
return 0;
}
}
return 1;
}
/* Print version and licensing information */
void print_info (void)
{
printf("pdnsd - dns proxy daemon, version %s\n\n",VERSION);
printf("pdnsd is free software; you can redistribute it and/or modify\n");
printf("it under the terms of the GNU General Public License as published by\n");
printf("the Free Software Foundation; either version 2, or (at your option)\n");
printf("any later version.\n\n");
printf("pdnsd is distributed in the hope that it will be useful,\n");
printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
printf("GNU General Public License for more details.\n\n");
printf("You should have received a copy of the GNU General Public License\n");
printf("along with pdsnd; see the file COPYING. If not, write to\n");
printf("the Free Software Foundation, 59 Temple Place - Suite 330,\n");
printf("Boston, MA 02111-1307, USA.\n");
}
/* Print the help page */
void print_help (void)
{
printf("\n\nUsage: pdnsd [-h] [-V] [-s] [-d] [-g] [-vn] [-mxx] [-c file]");
#ifdef ENABLE_IPV4
printf(" [-4]");
#endif
#ifdef ENABLE_IPV6
printf(" [-6]");
#endif
printf("\n\n");
printf("Options:\n");
printf("-h\t\t--or--\n");
printf("--help\t\tprint this help page and exit.\n");
printf("-V\t\t--or--\n");
printf("--version\tprint version information and exit.\n");
printf("--pdnsd-user\tprint the user pdnsd will run as and exit.\n");
printf("-s\t\t--or--\n");
printf("--status\tEnable status control socket the temp directory\n");
printf("-d\t\t--or--\n");
printf("--daemon\tStart pdnsd in daemon mode (as background process.)\n");
printf("-g\t\t--or--\n");
printf("--debug\t\tPrint some debug messages on the console or to the\n");
printf("\t\tfile pdnsd.debug in your cache directory (in daemon mode).\n");
printf("-t\t\t--or--\n");
printf("--tcp\t\tEnables the TCP server thread. pdnsd will then serve\n");
printf("\t\tTCP and UDP queries.\n");
printf("-p\t\tWrites the pid the server runs as to a specified filename.\n");
printf("\t\tWorks only in daemon mode.\n");
printf("-vn\t\tsets the verbosity of pdnsd. n is a numeric argument from 0\n");
printf("\t\t(normal operation) to 3 (many messages for debugging).\n");
printf("\t\tUse like -v2\n");
printf("-mxx\t\tsets the query method pdnsd uses. Possible values for xx are:\n");
printf("\t\tuo (UDP only), to (TCP only), and tu (TCP or, if the server\n");
printf("\t\tdoes not support this, UDP). Use like -muo. Preset: %s\n",
M_PRESET==UDP_ONLY?"-muo":(M_PRESET==TCP_ONLY?"-mto":"mtu"));
printf("-c\t\t--or--\n");
printf("--config-file\tspecifies the file the configuration is read from.\n");
printf("\t\tDefault is %s/pdnsd.conf\n",CONFDIR);
#ifdef ENABLE_IPV4
printf("-4\t\tenables IPv4 support. IPv6 support is automatically\n");
printf("\t\tdisabled (should it be available). %s by default.\n",DEFAULT_IPV4?"On":"Off");
#endif
#ifdef ENABLE_IPV6
printf("-6\t\tenables IPv6 support. IPv4 support is automatically\n");
printf("\t\tdisabled (should it be available). %s by default.\n",DEFAULT_IPV6?"On":"Off");
#endif
printf("\n\n\"no\" can be prepended to the --status, --daemon, --debug and --tcp\n");
printf("options (e.g. --notcp) to reverse their effect.\n");
}
/*
* Argument parsing, init, server startup
*/
int main(int argc,char *argv[])
{
int i,sig,pfd,np=0;
struct passwd *pws;
char *conf_file=CONFDIR"/pdnsd.conf";
#if DEBUG>0
char dbgdir[MAXPATH];
#endif
FILE *pf;
#ifndef O_NOFOLLOW
struct stat so, sn;
#endif
main_thread=pthread_self();
#ifdef DEBUG_YY
yydebug=1;
#endif
/* We parse the command line two times, because the command-line options shall override the ones
* given in the config file */
for (i=1;i<argc;i++) {
if (strcmp(argv[i],"-h")==0 || strcmp(argv[i],"--help")==0) {
print_info();
print_help();
exit(1);
} else if (strcmp(argv[i],"-V")==0 || strcmp(argv[i],"--version")==0) {
print_info();
exit(1);
} else if (strcmp(argv[i],"-c")==0 || strcmp(argv[i],"--config-file")==0) {
if (i<argc-1) {
i++;
conf_file=argv[i];
} else {
fprintf(stderr,"Error: file name expected after -c option.\n");
exit(1);
}
}
}
init_cache();
read_config_file(conf_file);
for (i=1;i<argc;i++) {
if (strcmp(argv[i],"-s")==0 || strcmp(argv[i],"--status")==0) {
stat_pipe=1;
} else if (strcmp(argv[i],"--nostatus")==0) {
stat_pipe=0;
} else if (strcmp(argv[i],"-d")==0 || strcmp(argv[i],"--daemon")==0) {
daemon_p=1;
} else if (strcmp(argv[i],"--nodaemon")==0) {
daemon_p=0;
} else if (strcmp(argv[i],"-t")==0 || strcmp(argv[i],"--tcp")==0) {
notcp=0;
} else if (strcmp(argv[i],"--notcp")==0) {
notcp=1;
} else if (strcmp(argv[i],"-p")==0) {
if (i<argc-1) {
i++;
if (strlen(argv[i]) >= sizeof(pidfile)) {
fprintf(stderr,"Error: pidfile name too long.\n");
exit(1);
}
strncpy(pidfile,argv[i],sizeof(pidfile));
pidfile[sizeof(pidfile)-1]='\0';
} else {
fprintf(stderr,"Error: file name expected after -p option.\n");
exit(1);
}
} else if (strncmp(argv[i],"-v",2)==0) {
if (strlen(argv[i])!=3 || !isdigit(argv[i][2])) {
fprintf(stderr,"Error: one digit expected after -v option (like -v2).\n");
exit(1);
}
verbosity=argv[i][2]-'0';
} else if (strncmp(argv[i],"-m",2)==0) {
if (strlen(argv[i])!=4) {
fprintf(stderr,"Error: uo, to or tu expected after the -m option (like -muo).\n");
exit(1);
}
if (strcmp(&argv[i][2],"uo")==0) {
#ifdef NO_UDP_QUERIES
fprintf(stderr,"Error: pdnsd was compiled without UDP support.\n");
exit(1);
#else
query_method=UDP_ONLY;
#endif
} else if (strcmp(&argv[i][2],"to")==0) {
#ifdef NO_TCP_QUERIES
fprintf(stderr,"Error: pdnsd was compiled without TCP support.\n");
exit(1);
#else
query_method=TCP_ONLY;
#endif
} else if (strcmp(&argv[i][2],"tu")==0) {
#if defined(NO_UDP_QUERIES) || defined(NO_TCP_QUERIES)
fprintf(stderr,"Error: pdnsd was not compiled with UDP and TCP support.\n");
exit(1);
#else
query_method=TCP_UDP;
#endif
} else {
fprintf(stderr,"Error: uo, to or tu expected after the -m option (like -muo).\n");
exit(1);
}
} else if (strcmp(argv[i],"-4")==0) {
#ifdef ENABLE_IPV4
run_ipv4=1;
# ifdef ENABLE_IPV6
run_ipv6=0;
# endif
#else
fprintf(stderr,"Error: -4: pdnsd was compiled without IPv4 support.\n");
exit(1);
#endif
} else if (strcmp(argv[i],"-6")==0) {
#ifdef ENABLE_IPV6
run_ipv6=1;
# ifdef ENABLE_IPV4
run_ipv4=0;
# endif
#else
fprintf(stderr,"Error: -6: pdnsd was compiled without IPv6 support.\n");
exit(1);
#endif
} else if (strcmp(argv[i],"-g")==0 || strcmp(argv[i],"--debug")==0) {
#if DEBUG>0
debug_p=1;
#else
fprintf(stderr,"pdnsd was compiled without debugging support. -g has no effect.\n");
#endif
} else if (strcmp(argv[i],"--nodebug")==0) {
debug_p=0;
} else if (strcmp(argv[i],"--pdnsd-user")==0) {
if (global.run_as[0]) {
printf("%s\n",global.run_as);
} else {
if ((pws=getpwuid(getuid()))) {
printf("%s\n",pws->pw_name);
} else {
printf("%i\n",getuid());
}
}
exit(0);
} else if (strcmp(argv[i],"-c")==0 || strcmp(argv[i],"--config-file")==0) {
/* at this point, it is already checked that a file name arg follows. */
i++;
} else {
fprintf(stderr,"Error: unknown option: %s\n",argv[i]);
exit(1);
}
}
if (!(global.run_as[0] && global.strict_suid)) {
struct passwd *pws=getpwuid(getuid());
char *un=pws?pws->pw_name:"(unknown)";
servparm_t *sp;
for (i=0; i<da_nel(servers); i++) {
sp=DA_INDEX(servers,i,servparm_t);
if (sp->uptest==C_EXEC && sp->uptest_usr[0]=='\0') {
/* No explicit uptest user given. If we run_as and strict_suid, we assume that
* this is safe. If not - warn. */
fprintf(stderr,"Warning: uptest command \"%s\" will implicitely be executed as user %s!\n",sp->uptest_cmd, un);
}
}
}
if (daemon_p && pidfile[0]) {
if (unlink(pidfile)!=0 && errno!=ENOENT) {
log_error("Error: could not unlink pid file %s: %s\n",pidfile, strerror(errno));
exit(1);
}
#ifdef O_NOFOLLOW
if ((pfd=open(pidfile,O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0600))==-1) {
#else
/*
* No O_NOFOLLOW. Nevertheless, this not a hole, since the
* directory for pidfiles should not be world writeable.
* OS's that do not support O_NOFOLLOW are currently not
* supported, this is just-in-case code.
*/
if ((pfd=open(pidfile,O_WRONLY|O_CREAT|O_EXCL, 0600))==-1) {
#endif
log_error("Error: could not open pid file %s: %s\n",pidfile, strerror(errno));
exit(1);
}
if (!(pf=fdopen(pfd,"w"))) {
log_error("Error: could not open pid file %s: %s\n",pidfile, strerror(errno));
exit(1);
}
}
for (i=0;i<da_nel(servers);i++) {
if (DA_INDEX(servers,i,servparm_t)->uptest==C_PING)
np=1;
}
if (np)
init_ping_socket();
if (!init_rng())
exit(1);
#if TARGET==TARGET_LINUX
if (!final_init())
exit(1);
#endif
signal(SIGPIPE, SIG_IGN);
umask(0077); /* for security reasons */
if (daemon_p) {
/* become a daemon */
i=fork();
if (i==-1) {
log_error("Could not become a daemon: fork failed: %s\n",strerror(errno));
exit(1);
}
if (i!=0)
exit(0); /* exit parent */
/* dissociate from controlling terminal */
if (setsid()==-1) {
log_error("Could not become a daemon: setsid failed: %s",strerror(errno));
_exit(1);
}
i=fork();
if (i==-1) {
log_error("Could not become a daemon: fork failed: %s",strerror(errno));
_exit(1);
}
if (i!=0)
_exit(0); /* exit parent, so we are no session group leader */
chdir("/");
if (pidfile[0]) {
fprintf(pf,"%i\n",getpid());
fclose(pf);
}
if ((i=open("/dev/null",O_RDONLY))==-1) {
log_error("Could not become a daemon: open for /dev/null failed: %s",strerror(errno));
_exit(1);
}
dup2(i,0);
close(i);
if ((i=open("/dev/null",O_WRONLY))==-1) {
log_error("Could not become a daemon: open for /dev/null failed: %s",strerror(errno));
_exit(1);
}
dup2(i,1);
dup2(i,2);
close(i);
openlog("pdnsd",LOG_PID,LOG_DAEMON);
syslog(LOG_INFO,"pdnsd-%s starting.",VERSION);
closelog();
#if DEBUG>0
if (debug_p) {
if (snprintf(dbgdir, sizeof(dbgdir), "%s/pdnsd.debug", global.cache_dir) < sizeof(dbgdir)) {
if (!(dbg_file=fopen(dbgdir,"w")))
debug_p=0;
} else
debug_p=0;
}
#endif
} else {
#if DEBUG>0
dbg_file=stdout;
#endif
printf("pdnsd-%s starting.\n",VERSION);
DEBUG_MSGC("Debug messages activated\n");
}
#if TARGET!=TARGET_LINUX
if (!final_init())
_exit(1);
#endif
#ifdef ENABLE_IPV4
if (run_ipv4)
DEBUG_MSGC("Using IPv4.\n");
#endif
#ifdef ENABLE_IPV6
if (run_ipv6)
DEBUG_MSGC("Using IPv6.\n");
#endif
init_log();
/* Before this point, cache accesses are not locked because we are single-threaded. */
init_cache_lock();
read_disk_cache();
/* This must be done before any other thread is started to avoid races. */
if (stat_pipe)
init_stat_sock();
sigemptyset(&sigs_msk);
sigaddset(&sigs_msk,SIGILL);
sigaddset(&sigs_msk,SIGABRT);
sigaddset(&sigs_msk,SIGFPE);
sigaddset(&sigs_msk,SIGSEGV);
sigaddset(&sigs_msk,SIGTERM);
if (!daemon_p) {
sigaddset(&sigs_msk,SIGINT);
sigaddset(&sigs_msk,SIGQUIT);
}
#if TARGET==TARGET_LINUX
pthread_sigmask(SIG_BLOCK,&sigs_msk,NULL);
#endif
/* Generate a key for storing our thread id's */
if (pthread_key_create(&thrid_key, NULL) != 0) {
log_error("pthread_key_create failed.");
_exit(1);
}
start_servstat_thread();
#if TARGET==TARGET_LINUX
if (!global.strict_suid) {
if (!run_as(global.run_as)) {
log_error("Could not change user and group id to those of run_as user %s",global.run_as);
_exit(1);
}
}
#endif
if (stat_pipe)
start_stat_sock();
start_dns_servers();
DEBUG_MSGC("All threads started successfully.\n");
#if TARGET==TARGET_LINUX
pthread_sigmask(SIG_BLOCK,&sigs_msk,NULL);
#endif
waiting=1;
sigwait(&sigs_msk,&sig);
DEBUG_MSGC("Signal caught, writing disk cache.\n");
write_disk_cache();
destroy_cache();
log_warn("Caught signal %i. Exiting.",sig);
if (sig==SIGSEGV || sig==SIGILL || sig==SIGBUS)
crash_msg("This is a fatal signal probably triggered by a bug.");
if (ping_isocket!=-1)
close(ping_isocket);
#ifdef ENABLE_IPV6
if (ping6_isocket!=-1)
close(ping6_isocket);
#endif
if (stat_pipe) {
unlink(sock_path); /* Delete the socket */
}
free_rng();
#if DEBUG>0
if (debug_p && daemon_p)
fclose(dbg_file);
#endif
_exit(0);
}
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип : application/pgp-signature
Размер : 189 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url : <http://lists.altlinux.org/pipermail/devel/attachments/20030619/e364a109/attachment-0001.bin>
Подробная информация о списке рассылки Devel