2.1.5 sys_syslog系统调用

2.1.5  sys_syslog系统调用

系统调用sys_syslog根据参数type的命令执行相应的操作。参数type定义的命令列出如下:

0 -- 关闭日志,当前没实现。
1 -- 打开日志,当前没实现。
2 -- 从环形缓冲区读取日志消息。
3 -- 读取保留在环形缓冲区的所有消息。
4 -- 读取并清除保留在环形缓冲区的所有消息。
5 -- 清除环形缓冲区。
6 -- 关闭printk到控制台的打印。
7 -- 开启printk到控制台的打印。
8 -- 设置打印到控制台的消息的日志级别。
9 -- 返回日志缓冲区中没读取的字符数。
10 -- 返回日志缓冲区的大小。

sys_syslog函数列出如下(在linux26/kernel/printk.c中):

asmlinkage long sys_syslog(int type, char __user * buf, int len)
{
return do_syslog(type, buf, len);
}

int do_syslog(int type, char __user *buf, int len)
{
unsigned long i, j, limit, count;
int do_clear = 0;
char c;
int error = 0;

error = security_syslog(type); //检查是否调用这个函数的权限
if (error)
return error;

switch (type) {
case 0:/* 关闭日志 */
break;
case 1:/* 打开日志*/
break;
case 2:/*读取日志信息*/
error = -EINVAL;
if (!buf || len < 0)
goto out;
error = 0;
if (!len)
goto out;
if (!access_ok(VERIFY_WRITE, buf, len)) { //验证是否有写的权限
error = -EFAULT;
goto out;
}
//当log_start - log_end为0时,表示环形缓冲区无数据可读,把当前进程放入
                  等待队列log_wait
error = wait_event_interruptible(log_wait, (log_start - log_end));
if (error)
goto out;
i = 0;
spin_lock_irq(&logbuf_lock);
while (!error && (log_start != log_end) && i < len) {
c = LOG_BUF(log_start); //从环形缓冲区得到读取位置log_start
log_start++;
spin_unlock_irq(&logbuf_lock);
error = __put_user(c,buf); //将c地址的字符传递到用户空间的buf中
buf++;
i++;
cond_resched(); //条件调度,让其他进程有运行时间
spin_lock_irq(&logbuf_lock);
}
spin_unlock_irq(&logbuf_lock);
if (!error)
error = i;
break;
case 4:/* 读/清除上一次内核消息*/
do_clear = 1;
/* FALL THRU */
case 3:/*读取上一次内核消息*/
error = -EINVAL;
if (!buf || len < 0) 
goto out;
error = 0;
if (!len) //读取长度为0
goto out;
if (!access_ok(VERIFY_WRITE, buf, len)) { //验证有写权限
error = -EFAULT;
goto out;
}
count = len;
if (count > log_buf_len) 
count = log_buf_len;
spin_lock_irq(&logbuf_lock);
if (count > logged_chars) // logged_chars是上次读/清除以来产生的日志字符数
count = logged_chars;
if (do_clear)
logged_chars = 0;
limit = log_end; 
/* __put_user() 可以睡眠,当__put_user睡眠时,printk()可能覆盖写正在
拷贝到用户空间的消息,因此,这些消息被反方向拷贝,将buf覆盖部分的数据重写到buf的起始位置*/
for (i = 0; i < count && !error; i++) { //读取count个字符
j = limit-1-i;
if (j + log_buf_len < log_end)
break;
c = LOG_BUF(j); //从环形缓冲区得到读取位置j
spin_unlock_irq(&logbuf_lock);
  //将c位置的字符传递到用户空间的buf中,如果发生错误,将发生错误的c位置给error
error = __put_user(c,&buf[count-1-i]);
cond_resched();
spin_lock_irq(&logbuf_lock);
}
spin_unlock_irq(&logbuf_lock);

if (error)
break;
error = i;
if (i != count) { //表示__put_user没有拷贝完成
int offset = count-error;
/* 拷贝期间缓冲区溢出,纠正用户空间缓冲区*/
for (i = 0; i < error; i++) {
if (__get_user(c,&buf[i+offset]) ||
__put_user(c,&buf[i])) { //将覆盖部分的数据
                                                               重写到buf的起始位置
error = -EFAULT;
break;
}
cond_resched();
}
}
break;
case 5:/* 清除环形缓冲区*/
logged_chars = 0;
break;
case 6:/*关闭向控制台输出消息*/
console_loglevel = minimum_console_loglevel;
break;
case 7:/*开启向控制台输出消息*/
console_loglevel = default_console_loglevel;
break;
case 8:/* 设置打印到控制台的日志级别*/
error = -EINVAL;
if (len < 1 || len > 8)
goto out;
if (len < minimum_console_loglevel)
len = minimum_console_loglevel;
console_loglevel = len;
error = 0;
break;
case 9:/* 得到日志消息所占缓冲区的大小*/
error = log_end - log_start;
break;
case 10:/*返回环形缓冲区的大小*/
error = log_buf_len;
break;
default:
error = -EINVAL;
break;
}
out:
return error;
}

你可能感兴趣的:(c,linux,Security,user,Access)