守护进程使用syslog函数打印信息(基于ARM-Linux)_syslog函数使用 termux-程序员宅基地

技术标签: 建立开发环境  

本文将描述在使用inetd守护进程时,如何通过syslog函数打印消息到日志文件。

为什么需要这样做呢?根据《UNIX网络编程 卷1:套接字联网API》一书第13章的描述:由于守护进程没有控制终端,它们不能把消fprintf到stderr上。

从守护进程中登记消息的常用技巧就是调用syslog函数。

而sysolog函数需要syslogd服务的支持。因此在编译busybox时需要使能syslogd。



Linux系统启动后,需要打开syslogd服务。先来看看syslogd的命令选项:

[root@BGM /]#syslogd -h
syslogd: invalid option -- 'h'
BusyBox v1.16.0 (2013-04-15 16:07:27 CST) multi-call binary.

Usage: syslogd [OPTIONS]

System logging utility.
Note that this version of syslogd ignores /etc/syslog.conf.

Options:
        -n              Run in foreground
        -O FILE         Log to given file (default:/var/log/messages)
        -l n            Set local log level
        -S              Smaller logging output
        -s SIZE         Max size (KB) before rotate (default:200KB, 0=off)
        -b N            N rotated logs to keep (default:1, max=99, 0=purge)
        -R HOST[:PORT]  Log to IP or hostname on PORT (default PORT=514/UDP)
        -L              Log locally and via network (default is network only if -R)
        -D              Drop duplicates
        -C[size(KiB)]   Log to shared mem buffer (read it using logread)

这里我们注意到该syslogd不支持/etc/syslog.conf文件。

我们需要使用-L选项,让消息输出到本地(locally),其次其默认的本地输出文件为/var/log/message,

如果要修改输出文件,则使用-O选项。

因此,我这里使用的syslogd命令如下:

/sbin/syslogd -L

这里建议将该命令添加到系统的启动脚本中。

为了测试函数需要编写一个简单的TCP服务器程序和相应的客户程序,参照《UNIX网络编程 卷1:套接字联网API》的13.6小结编写测试用例,

程序如下:

服务器程序:

int main(void)
{
	socklen_t len;
	struct sockaddr *cliaddr;
	char buf[MAX_TCPSERV_BUF];

	int ret, tmp;

	openlog("bgmtcpserv", LOG_PID, 0);

	dc = malloc(sizeof(struct data_content));
	if(!dc){
		perror("Unable to malloc data_content ");
		exit -1;
	}

	cliaddr = malloc(sizeof(struct sockaddr_storage));
	if(!cliaddr){
		perror("Unable to malloc sockaddr_storage ");
		exit -1;
	}

	len = sizeof(struct sockaddr_storage);
	if (getpeername(0, cliaddr, &len) == -1){
		perror("Getpeername error ");
		exit -1;
	}
	
	syslog(LOG_USER|LOG_ALERT, "Connecting from %s\n", Sock_ntop(cliaddr,len));
	
	close(0); 
	closelog();
	exit(0);
}
/* include sock_ntop */
char *
sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
    char        portstr[8];
    static char str[128];        /* Unix domain is largest */

    switch (sa->sa_family) {
    case AF_INET: {
        struct sockaddr_in    *sin = (struct sockaddr_in *) sa;

        if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)
            return(NULL);
        if (ntohs(sin->sin_port) != 0) {
            snprintf(portstr, sizeof(portstr), ":%d", ntohs(sin->sin_port));
            strcat(str, portstr);
        }
        return(str);
    }
/* end sock_ntop */

#ifdef    IPV6
    case AF_INET6: {
        struct sockaddr_in6    *sin6 = (struct sockaddr_in6 *) sa;

        str[0] = '[';
        if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, sizeof(str) - 1) == NULL)
            return(NULL);
        if (ntohs(sin6->sin6_port) != 0) {
            snprintf(portstr, sizeof(portstr), "]:%d", ntohs(sin6->sin6_port));
            strcat(str, portstr);
            return(str);
        }
        return (str + 1);
    }
#endif
/*
#ifdef    AF_UNIX
    case AF_UNIX: {
        struct sockaddr_un    *unp = (struct sockaddr_un *) sa;

             OK to have no pathname bound to the socket: happens on
               every connect() unless client calls bind() first. 
        if (unp->sun_path[0] == 0)
            strcpy(str, "(no pathname bound)");
        else
            snprintf(str, sizeof(str), "%s", unp->sun_path);
        return(str);
    }
#endif*/

// #ifdef    HAVE_SOCKADDR_DL_STRUCT
//     case AF_LINK: {
//         struct sockaddr_dl    *sdl = (struct sockaddr_dl *) sa;

//         if (sdl->sdl_nlen > 0)
//             snprintf(str, sizeof(str), "%*s (index %d)",
//                      sdl->sdl_nlen, &sdl->sdl_data[0], sdl->sdl_index);
//         else
//             snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);
//         return(str);
//     }
// #endif
    default:
        snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
                 sa->sa_family, salen);
        return(str);
    }
    return (NULL);
}

char *
Sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
    char    *ptr;

    if ( (ptr = sock_ntop(sa, salen)) == NULL)
        perror("sock_ntop error");    /* inet_ntop() sets errno */
    return(ptr);
}

客户端程序:

#define SERV_PORT 30001
#define SERVIPADDR "192.168.0.200"

ssize_t						/* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
	size_t	nleft;
	ssize_t	nread;
	char	*ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;		/* and call read() again */
			else
				return(-1);
		} else if (nread == 0)
			break;				/* EOF */

		nleft -= nread;
		ptr   += nread;
	}
	return(n - nleft);		/* return >= 0 */
}

int main(void)
{
	int sockfd, ret;
	struct sockaddr_in  servaddr;
	int n;
	char buf[512] ;
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0){
		perror("Socket error");
		return -1;
	}
	
	memset(&servaddr, 0, sizeof(struct sockaddr_in));
	//bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(SERV_PORT);
	ret = inet_pton(AF_INET, SERVIPADDR, &servaddr.sin_addr);
	if(ret < 1){
		perror("Inet_pton error");
		return -1;
	}

	ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	if(ret < 0){
		perror("Connect error");
		return -1;
	}

	close(sockfd);
}

服务器程序编写完以后,为了让inetd能够调用我们的服务器程序,需要修改配置文件。

首先,修改/etc/services,增加如下:

mytcpser        30001/tcp                        # Used by BGM

其次,修改/etc/inetd.conf,增加如下:

mytcpser stream tcp nowait root /home/bgm/bgmtcpser bgmtcpser

这里的mytcpser需要和services文件中的第一个字段相同,其次/home/bgm/bgmtcpser为服务器程序所在的路径。

修改完配置文件后,将服务器程序bgmtcpser复制到/home/bgm目录下。

使用netstat 来查看是否inetd已经创建端口号为30001的监听套接字:

[root@BGM /]#netstat -an | grep 30001

tcp        0      0 0.0.0.0:30001           0.0.0.0:*               LISTEN   

然后我们执行客户程序cli,执行完以后我们查看/var/log/messages中的内容:
Jul 23 13:13:42 BGM user.alert bgmtcpserv[2587]: Connecting from 192.168.0.200:40571

这里的"Connecting from。。。"正是由syslog函数打印的。



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yj4231/article/details/9419823

智能推荐

Aubo机械臂初学(愁)——1、gazebo和Rviz联合仿真_aubo机械臂仿真-程序员宅基地

文章浏览阅读1.7k次,点赞5次,收藏33次。auboi5机械臂初学者遇到的各种问题合集_aubo机械臂仿真

POJ_1064_Cable master【二分】_poj - 1064 二分枚举答案 floor向下取整函数 原创-程序员宅基地

文章浏览阅读1.7k次。/*Cable masterTime Limit: 1000MS Memory Limit: 10000KTotal Submissions: 43878 Accepted: 9409DescriptionInhabitants of the Wonderland have decided to hold a regional programmi_poj - 1064 二分枚举答案 floor向下取整函数 原创

【前端学习】HTML学习笔记-table_table前端心得-程序员宅基地

文章浏览阅读88次。<table><colgroup><col bgcolor='red' width=200></colgroup><thead><tr><th></th></tr><tbody><tr><td></td></t..._table前端心得

CSS 之 line-height 实现单行文字垂直居中的原理_css height=line-height 可以垂直居中-程序员宅基地

文章浏览阅读1.5k次,点赞3次,收藏12次。基础知识line-height 与 font-size 的计算值之差(在 CSS 中成为“行间距”)分为两半,分别加到一个文本行内容的顶部和底部。我们暂且称之为顶部距离和底部距离,就是上图中的蓝色区域。也就是说: line-height = 顶部距离 + 内容高度(顶线和底线之间的距离) + 底部距离;顶部距离 = 底部距离;示例一: 当line-height 等于 height 时,文字垂直居中文本默认大小16px。结果:文字垂直居中。顶部距离 = 底部距离 = (line-heig_css height=line-height 可以垂直居中

uniapp实战——实现详情其他部分的结构_uniapp 实现关系图谱-程序员宅基地

文章浏览阅读241次。QQ 1274510382Wechat JNZ_aming商业联盟 QQ群538250800技术搞事 QQ群599020441解决方案 QQ群152889761加入我们 QQ群649347320共享学习 QQ群674240731纪年科技aming网络安全 ,深度学习,嵌入式,机器强化,生物智能,生命科学。叮叮叮:产品已上线 —>关注 官方认证-微信公众号——济南纪年信息科技有限公司民生项目:商城加盟/娱乐交友/创业商圈/外包兼职开发-项目发布/安全项目:态.._uniapp 实现关系图谱

如何查看其他人的ABAP authorization check log_查看authorization-程序员宅基地

文章浏览阅读375次。Created by Jerry Wang on Jul 29, 2014 Go to start of metadata在做middleware相关的scenario操作时,有时候需要evaluate其他user的authorization check log,例如在CRM tcode SMW01里发现BDoc state为validation error,点击show error butto..._查看authorization

随便推点

I.MX6 eMMC分区挂载-程序员宅基地

文章浏览阅读244次。/********************************************************************* * I.MX6 eMMC分区挂载 * 说明: * 如果想要修改分区的挂载情况,可以修改fstab.freescale文件。 * * ..._imx6 分区挂载

【opencv-python】霍夫圆检测_霍夫圆圆心检测python-程序员宅基地

文章浏览阅读6.7k次,点赞10次,收藏55次。霍夫变换检测直线的原理是利用累加器找到最大的(ρ,θ)(ρ,θ)(ρ,θ)数对,如文章所述。圆形的数学表达式为(x−xcenter)2+(y−ycenter)2=r2(x-x_{center})^2+(y-y_{center})^2=r^2(x−xcenter​)2+(y−ycenter​)2=r2,其中(xcenter,ycenter)(x_{center},y_{center})(xcenter​,ycenter​)为圆心坐标,rrr为圆的直径。因此可知一个圆需要xcenter,ycenter,rx_{_霍夫圆圆心检测python

码仔精选,Android面试题-程序员宅基地

文章浏览阅读171次。码个蛋(codeegg) 第 822次推文码妞看世界1.Java创建对象的几种方式使用new关键字使用Class类的newInstance方法使用Constructor类的newIn..._码个蛋 《每日一道面试题》 第一期

Milking Time (poj 3616 简单DP)_poj milking time-程序员宅基地

文章浏览阅读2.5k次,点赞3次,收藏5次。题意:给个时间长度n,m个工作时间段和每个时间段能完成的工作量,一次只能做一个工作并且一旦开始做就要把它做完,要求选择的两个工作时间段之间至少相差r时间(中间需要休息嘛)求选择那些工作n时间内能完成的最大工作量。输出最大值。思路:先按工作的结束时间从小到大排序,再动态规划。dp[i]表示从头开始取到第i段所获得的最大值。二重循环,如果第i段之前的某个段的结束时间加上r小于等于第i段的开始时间,则更新dp[i]。_poj milking time

GDCM:gdcm::Global的测试程序_gbcm main show main screen-程序员宅基地

文章浏览阅读333次。GDCM:gdcm::Global的测试程序GDCM:gdcm::Global的测试程序GDCM:gdcm::Global的测试程序#include "gdcmGlobal.h"#include "gdcmDicts.h"#include "gdcmDict.h"#include "gdcmDefs.h"int TestGlobal(int, char *[]){ // case 1 // Get the global singleton: gdcm::Trace::DebugOn_gbcm main show main screen

理解 OAuth 2.0_shanks user-agent-程序员宅基地

文章浏览阅读278次。转载自http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html作者:阮一峰日期:2014年5月12日OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749。更新:我后来又写了一组三篇的《OAuth 2.0 教程》,更加通俗,并带有代码实例,欢迎阅读。一、应用场景..._shanks user-agent