成长值: 63385
|
楼主 |
发表于 2010-8-20 17:22:43
|
显示全部楼层
if (pi[0] != 3) die_pipe(); //确保向子进程能够读到硬编码的fd 3
switch(child = fork()) { //建立子进程执行subprogram给出的程式,一般是一个检验用户名和密码的程式
case -1:
die_fork();
case 0:
close(pi[1]);
sig_pipedefault();//子进程执行checkpassword或vchkpw之类的程式,检验密码,如果认证通过
execvp(*childargs,childargs);//这些再调用qmail-pop3d
_exit(1);
}
//父进程向子进程的fd3传送用户名及密码,这是一个约定。如果你要写自已的检验密码的程式,记得
//从fd3读密码哦。
close(pi[0]);
substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf);
if (substdio_put(&ssup,user,userlen) == -1) die_write();
if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write();
//父进程向子进程传送<进程ID.当前时间@主机名>
if (substdio_puts(&ssup,"<") == -1) die_write();
if (substdio_puts(&ssup,unique) == -1) die_write();
if (substdio_puts(&ssup,hostname) == -1) die_write();
if (substdio_put(&ssup,">",2) == -1) die_write();
if (substdio_flush(&ssup) == -1) die_write();
close(pi[1]);
//清除密码及用户名缓冲区
byte_zero(pass,str_len(pass));
byte_zero(upbuf,sizeof upbuf);
if (wait_pid(&wstat,child) == -1) die();//等待子进程结束
if (wait_crashed(wstat)) die_childcrashed();
if (wait_exitcode(wstat)) die_badauth();
//完成一次pop3对话退出
die();
}
//显示欢迎信息
void pop3_greet()
{
char *s;
s = unique;
s += fmt_uint(s,getpid());
*s++ = '.';
s += fmt_ulong(s,(unsigned long) now());
*s++ = '@';
*s++ = 0;
puts("+OK <");
puts(unique);
puts(hostname);
puts(">\\r\\n");
flush();
}
//设置标志,初始化用户名变量
void pop3_user(arg) char *arg;
{
if (!*arg) { err_syntax(); return; }
okay();
seenuser = 1; //user命令已经执行的标志
if (!stralloc_copys(&username,arg)) die_nomem(); //将参数存入username
if (!stralloc_0(&username)) die_nomem();
}
void pop3_pass(arg) char *arg;
{
if (!seenuser) { err_wantuser(); return; }//如果没有执行user命令,返回
if (!*arg) { err_syntax(); return; }
doanddie(username.s,username.len,arg);//调用子进程验正密码并等待它完成
}
void pop3_apop(arg) char *arg;//用户名及密码在一个命令中给出的情况,见user,pass
{
char *space;
space = arg + str_chr(arg,' ');
if (!*space) { err_syntax(); return; }
*space++ = 0;
doanddie(arg,space - arg,space);
}
struct commands pop3commands[] = {//命令及相应的处理函数表
{ "user", pop3_user, 0 }
, { "pass", pop3_pass, 0 }
, { "apop", pop3_apop, 0 }
, { "quit", pop3_quit, 0 }
, { "noop", okay, 0 }
, { 0, err_authoriz, 0 }
} ;
void main(argc,argv)
int argc;
char **argv;
{
sig_alarmcatch(die);//捕获sigalrm信号
sig_pipeignore();//忽略pipe信号
hostname = argv[1]; //hostname 指向 程式的第一个参数
if (!hostname) die_usage();
childargs = argv + 2;
if (!*childargs) die_usage();
pop3_greet();//显示欢迎信息后进入命令循环,等待用户命令
commands(&ssin,pop3commands);
die();
}
qmail-start.c 分析
Programmer:夜未眠
Comefrom:ChongQing Gearbox co.,ltd
qmail-start 是很简单的一个程式,他完成qmail-send,qmail-clean,qmail-lspawn,qmail-rspawn,splogger的启动,并通过管道将他们联系在一起,当然不是网状连接.具体如下
代码:
=====================================
qmail-lspawn fd0 <-------- qmail-send fd1
qmail-lspawn fd1 --------> qmail-send fd2
qmail-rspawn fd0 <-------- qmail-send fd3
qmail-rspawn fd1 --------> qmail-send fd4
qmail-clean fd0 <-------- qmail-send fd5
qmail-clean fd1 --------> qmail-send fd6
=====================================
理解他们之间的关系(注意方向)对于理解qmail-send源代码非常重要。仔细再看一次。
因为其比较简单,所以这里就不对他的源代码作过细的分析:
代码:
char *(qsargs[]) = { "qmail-send", 0 };
char *(qcargs[]) = { "qmail-clean", 0 };
char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 };
char *(qrargs[]) = { "qmail-rspawn", 0 };
void die() { _exit(111); }
int pi0[2]; //splogger qmail
int pi1[2]; //qmail-lspawn fd0 <-------- qmail-send fd1
int pi2[2]; //qmail-lspawn fd1 --------> qmail-send fd2
int pi3[2]; //qmail-rspawn fd0 <-------- qmail-send fd3
int pi4[2]; //qmail-rspawn fd1 --------> qmail-send fd4
int pi5[2]; //qmail-clean fd0 <-------- qmail-send fd5
int pi6[2]; //qmail-clean fd1 --------> qmail-send fd6
void close23456() { close(2); close(3); close(4); close(5); close(6); }
//****************//
//因为没有关闭pi0.
//所以所有的子进程都可以通过写pi0来记录maillog.
void closepipes() {
close(pi1[0]); close(pi1[1]); close(pi2[0]); close(pi2[1]);
close(pi3[0]); close(pi3[1]); close(pi4[0]); close(pi4[1]);
close(pi5[0]); close(pi5[1]); close(pi6[0]); close(pi6[1]);
}
void main(argc,argv)
int argc;
char **argv;
{
if (chdir("/") == -1) die();
umask(077);
if (prot_gid(auto_gidq) == -1) die();
if (fd_copy(2,0) == -1) die();
if (fd_copy(3,0) == -1) die();
if (fd_copy(4,0) == -1) die();
if (fd_copy(5,0) == -1) die();
if (fd_copy(6,0) == -1) die();
if (argv[1]) {
qlargs[1] = argv[1];
++argv;
}
if (argv[1]) {
if (pipe(pi0) == -1) die();
switch(fork()) {
case -1:
die();
case 0:
if (prot_gid(auto_gidn) == -1) die();
if (prot_uid(auto_uidl) == -1) die();
close(pi0[1]);
if (fd_move(0,pi0[0]) == -1) die();//重定向pi0[0]到splogger的fd0
close23456();
execvp(argv[1],argv + 1);//启动splogger
die();
}
close(pi0[0]);
if (fd_move(1,pi0[1]) == -1) die();
}
if (pipe(pi1) == -1) die();
if (pipe(pi2) == -1) die();
if (pipe(pi3) == -1) die();
if (pipe(pi4) == -1) die();
if (pipe(pi5) == -1) die();
if (pipe(pi6) == -1) die();
switch(fork()) {//启动qmail-lspawn
case -1: die();
case 0:
if (fd_copy(0,pi1[0]) == -1) die();
if (fd_copy(1,pi2[1]) == -1) die();
close23456();
closepipes();
execvp(*qlargs,qlargs);
die();
}
switch(fork()) {//启动qmail-rspawn
case -1: die();
case 0:
if (prot_uid(auto_uidr) == -1) die();
if (fd_copy(0,pi3[0]) == -1) die();
if (fd_copy(1,pi4[1]) == -1) die();
close23456();
closepipes();
execvp(*qrargs,qrargs);
die();
}
switch(fork()) {//启动qmail-clean
case -1: die();
case 0:
if (prot_uid(auto_uidq) == -1) die();
if (fd_copy(0,pi5[0]) == -1) die();
if (fd_copy(1,pi6[1]) == -1) die();
close23456();
closepipes();
execvp(*qcargs,qcargs);
die();
}
if (prot_uid(auto_uids) == -1) die();
if (fd_copy(0,1) == -1) die(); //重定向管道,把qmail-send 与上面各进程联系起来。
if (fd_copy(1,pi1[1]) == -1) die();
if (fd_copy(2,pi2[0]) == -1) die();
if (fd_copy(3,pi3[1]) == -1) die();
if (fd_copy(4,pi4[0]) == -1) die();
if (fd_copy(5,pi5[1]) == -1) die();
if (fd_copy(6,pi6[0]) == -1) die();
closepipes();
execvp(*qsargs,qsargs);//最后启动qmail-send
die();
}
==完==
qmail-pop3d源代码分析
Programmer:夜未眠
Comefrom: ChongQing Gearbox co.,ltd
关键数据结构
队列: --> prioq
这个数据结构在很多qmail很多程式中都有用到,最好记下来 |
7#
2010-8-20 17:22:43
回复(0)
收起回复
|