日志
rsyslogd
是常用的Linux日志系统,可以处理用户进程和内核日志。
用户进程调用syslog
函数生成系统日志,输出到/dev/log中,rsyslogd
监听该文件以获取用户进程的输出。具体见书
P
115
P_{115}
P115页
syslog
#include<syslog.h>
void syslog(int priority, const char* message, ...);
该函数采用可变参数来结构化输出,prioritiy是设施值和日志级别的按位或。设施值的默认值是LONG_USER,日志级别有:
另外openlog
可以改变syslog的默认输出方式,从而结构化日志内容。
用户信息
UID, EUID, GID, EGID
大部分服务器需要以root身份启动,但不以root身份运行。
切换用户
将以root身份启动的进程切换为普通身份运行
bool switch_to_user(uid_t user_id, gid_t gp_id) {
if (user_id == 0 && gp_id == 0) {
// user已经是root了
return false;
}
gid_t gid = getgid();
uid_t uid = getuid();
// 确保当前用户只有两种状态:root或者目标用户
if ((gid != 0 || uid != 0) && ((gid != gp_id || (uid != user_id)))) {
return false;
}
// 已经是目标用户
if (uid != 0) {
return true;
}
// 切换到目标用户
if (setgid(gp_id) < 0 || setuid(user_id) < 0) {
return false;
}
return true;
}
进程间关系
进程组
pit_t getpgid(pid_t pid)
返回进程所属的进程组的PGID
int setpgid(pid_t pid, pid_t pgid)
将pid进程的进程组的PGID设置为pgid,如果pid和pgid相同,则该进程被设置为进程组首领。如果pid为0,则表示设置当前进程的PGID为pgid,如果pgid为0,则使用pid作为目标pgid。
系统资源限制
#include<sys/resource.h>
int getrlimit(int resource, struct rlimit* rlim);
int setrlimit(int resource, const struct rlimit* rlim);
strcut rlim{
rlim_t rlim_cur;
rlim_t rlim_max;
};
改变工作目录
#include<unistd.h>
char* getcwd(char* buf, size_t size);
int chdir(const char* path);
buf指向的内存用来存储当前工作目录的绝对路径名,其大小用size指定,如果当前工作目录的绝对路径长度超过了size(包含’\0’),则getcwd返回NULL。
如果buf为NULL
且size非0,则getcwd
在内部使用malloc
动态分配内存,并将进程的当前工作目录存储在其中,这种情况我们需要自己释放这块内存。
getcwd
成功时返回一个指向目标存储区的指针(buf‘指向的缓存区或自动分配的缓存区)。
chdir
函数的path指定要切换到的目标目录。
改变进程根目录的函数时int chroot(const char* path)
。chroot
不改变进程的当前工作目录,所以调用后依然需要使用chdir("/")
来切换到新的根目录。切换根目录后之前打开的fd依然有效。
区别:chdir
在当前工作目录切换,chroot
可以改变根目录。
服务器程序后台化——守护进程
以守护进程进程的形式将服务器程序后台化。
守护进程:守护进程是运行在后台的一种生存期长的特殊进程。它独立于控制终端,处理一些系统级别任务。
如何实现:
- 创建子进程,终止父进程。方法是调用fork() 产生一个子进程,然后使父进程退出。
- 调用setsid() 创建一个新会话。
- 将当前目录更改为根目录。使用fork() 创建的子进程也继承了父进程的当前工作目录。
- 重设文件权限掩码。文件权限掩码是指屏蔽掉文件权限中的对应位。
- 关闭不再需要的文件描述符。子进程从父进程继承打开的文件描述符。
bool deamonize(){
// 创建子进程,关闭父进程,以使程序在后台运行
pid_t pid = fork();
if(pid < 0){
return false;
}else if(pid > 0){
exit(0);
}
// 设置文件权限掩码,当进程创建新文件(调用open)时,文件的权限将是mode & 0777;
umask(0);
pid_t sid = setsid();
if(sid < 0) return false;
if((chdir("/")) < 0) return false;
// 关闭标准输入输出设备和错误输出设备,并将标准输入输出、错误都定向到/del/null文件
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
// 关闭打开的文件描述符
//...
return true;
}
Linux有库函数
#include<unistd.h>
int daemon(int nochdir, int noclose);
nochdir
指定是否改变工作目录,传递0则工作目录设置为’/’,否则继续使用当前工作根目录。
noclose
为0时,标准输入输出错误将被定向到/dev/null
文件,否则依然使用原来的设备。
函数调用成功返回0,失败返回-1.