📄 sys.c
字号:
/* * linux/kernel/sys.c * * Copyright (C) 1991, 1992 Linus Torvalds */#include <linux/module.h>#include <linux/mm.h>#include <linux/utsname.h>#include <linux/mman.h>#include <linux/smp_lock.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/prctl.h>#include <linux/init.h>#include <linux/highuid.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/unistd.h>#include <asm/fcntl.h>#include <asm/types.h>#include <asm/stat.h>#include <asm/errno.h>/* * this is where the system-wide overflow UID and GID are defined, for * architectures that now have 32-bit UID/GID but didn't in the past */int overflowuid = DEFAULT_OVERFLOWUID;int overflowgid = DEFAULT_OVERFLOWGID;/* * the same as above, but for filesystems which can only store a 16-bit * UID and GID. as such, this is needed on all architectures */int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;/* * this indicates whether you can reboot with ctrl-alt-del: the default is yes */int C_A_D = 1;int cad_pid = 1;/* * Notifier list for kernel code which wants to be called * at shutdown. This is used to stop any idling DMA operations * and the like. */static struct notifier_block *reboot_notifier_list;rwlock_t notifier_lock = RW_LOCK_UNLOCKED;/** * notifier_chain_register - Add notifier to a notifier chain * @list: Pointer to root list pointer * @n: New entry in notifier chain * * Adds a notifier to a notifier chain. * * Currently always returns zero. */int notifier_chain_register(struct notifier_block **list, struct notifier_block *n){ write_lock(¬ifier_lock); while (*list) { if (n->priority > (*list)->priority) break; list = &((*list)->next); } n->next = *list; *list = n; write_unlock(¬ifier_lock); return 0;}/** * notifier_chain_unregister - Remove notifier from a notifier chain * @nl: Pointer to root list pointer * @n: New entry in notifier chain * * Removes a notifier from a notifier chain. * * Returns zero on success, or %-ENOENT on failure. */int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n){ write_lock(¬ifier_lock); while ((*nl) != NULL) { if ((*nl) == n) { *nl = n->next; write_unlock(¬ifier_lock); return 0; } nl = &((*nl)->next); } write_unlock(¬ifier_lock); return -ENOENT;}/** * notifier_call_chain - Call functions in a notifier chain * @n: Pointer to root pointer of notifier chain * @val: Value passed unmodified to notifier function * @v: Pointer passed unmodified to notifier function * * Calls each function in a notifier chain in turn. * * If the return value of the notifier can be and'd * with %NOTIFY_STOP_MASK, then notifier_call_chain * will return immediately, with the return value of * the notifier function which halted execution. * Otherwise, the return value is the return value * of the last notifier function called. */int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v){ int ret = NOTIFY_DONE; struct notifier_block *nb = *n; while (nb) { ret = nb->notifier_call(nb, val, v); if (ret & NOTIFY_STOP_MASK) { return ret; } nb = nb->next; } return ret;}/** * register_reboot_notifier - Register function to be called at reboot time * @nb: Info about notifier function to be called * * Registers a function with the list of functions * to be called at reboot time. * * Currently always returns zero, as notifier_chain_register * always returns zero. */int register_reboot_notifier(struct notifier_block *nb){ return notifier_chain_register(&reboot_notifier_list, nb);}/** * unregister_reboot_notifier - Unregister previously registered reboot notifier * @nb: Hook to be unregistered * * Unregisters a previously registered reboot * notifier function. * * Returns zero on success, or %-ENOENT on failure. */int unregister_reboot_notifier(struct notifier_block *nb){ return notifier_chain_unregister(&reboot_notifier_list, nb);}asmlinkage int sys_mycopy(int SourceFile,int DestFile,char *Buffer,int BUFFER_SIZE){ int BytesReaded, BytesWrited; char *ptr; /* Read content from the Fromfile */ while (BytesReaded = sys_read(SourceFile, Buffer, BUFFER_SIZE)) { /* An error occurt when reading */ if ((BytesReaded == -1) && (errno != EINTR)) return 1; else if (BytesReaded > 0) { ptr = Buffer; while (BytesWrited = sys_write(DestFile, ptr, BytesReaded)) { /* An errot occurt when writing */ if ((BytesWrited == -1) && (errno != EINTR)) return 2; /* Finish */ else if (BytesWrited == BytesReaded) break; else if (BytesWrited > 0){ ptr += BytesWrited; BytesReaded -= BytesWrited; } } /* An errot occurt when writing */ if (BytesWrited == -1) return 2; } } return 0;}asmlinkage long sys_ni_syscall(void){ return -ENOSYS;}static int proc_sel(struct task_struct *p, int which, int who){ if (p->pid) { switch (which) { case PRIO_PROCESS: if (!who && p == current) return 1; return (p->pid == who); case PRIO_PGRP: if (!who) who = current->pgrp; return (p->pgrp == who); case PRIO_USER: if (!who) who = current->uid; return (p->uid == who); } } return 0;}asmlinkage long sys_setpriority(int which, int who, int niceval){ struct task_struct *p; int error; if (which > 2 || which < 0) return -EINVAL; /* normalize: avoid signed division (rounding problems) */ error = -ESRCH; if (niceval < -20) niceval = -20; if (niceval > 19) niceval = 19; read_lock(&tasklist_lock); for_each_task(p) { if (!proc_sel(p, which, who)) continue; if (p->uid != current->euid && p->uid != current->uid && !capable(CAP_SYS_NICE)) { error = -EPERM; continue; } if (error == -ESRCH) error = 0; if (niceval < p->nice && !capable(CAP_SYS_NICE)) error = -EACCES; else p->nice = niceval; } read_unlock(&tasklist_lock); return error;}/* * Ugh. To avoid negative return values, "getpriority()" will * not return the normal nice-value, but a negated value that * has been offset by 20 (ie it returns 40..1 instead of -20..19) * to stay compatible. */asmlinkage long sys_getpriority(int which, int who){ struct task_struct *p; long retval = -ESRCH; if (which > 2 || which < 0) return -EINVAL; read_lock(&tasklist_lock); for_each_task(p) { long niceval; if (!proc_sel(p, which, who)) continue; niceval = 20 - p->nice; if (niceval > retval) retval = niceval; } read_unlock(&tasklist_lock); return retval;}/* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers * so that some mistake won't make this reboot the whole machine. * You can also set the meaning of the ctrl-alt-del-key here. * * reboot doesn't sync: do that yourself before calling this. */asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg){ char buffer[256]; /* We only trust the superuser with rebooting the system. */ if (!capable(CAP_SYS_BOOT)) return -EPERM; /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && magic2 != LINUX_REBOOT_MAGIC2B)) return -EINVAL; lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); printk(KERN_EMERG "Restarting system.\n"); machine_restart(NULL); break; case LINUX_REBOOT_CMD_CAD_ON: C_A_D = 1; break; case LINUX_REBOOT_CMD_CAD_OFF: C_A_D = 0; break; case LINUX_REBOOT_CMD_HALT: notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); printk(KERN_EMERG "System halted.\n"); machine_halt(); do_exit(0); break; case LINUX_REBOOT_CMD_POWER_OFF: notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); printk(KERN_EMERG "Power down.\n"); machine_power_off(); do_exit(0); break; case LINUX_REBOOT_CMD_RESTART2: if (strncpy_from_user(&buffer[0], (char *) arg, sizeof(buffer) - 1) < 0) { unlock_kernel(); return -EFAULT; } buffer[sizeof(buffer) - 1] = '\0'; notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer); printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer); machine_restart(buffer); break; default: unlock_kernel(); return -EINVAL; } unlock_kernel(); return 0;}static void deferred_cad(void *dummy){ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); machine_restart(NULL);}/* * This function gets called by ctrl-alt-del - ie the keyboard interrupt. * As it's called within an interrupt, it may NOT sync: the only choice * is whether to reboot at once, or just ignore the ctrl-alt-del. */void ctrl_alt_del(void){ static struct tq_struct cad_tq = { routine:deferred_cad, }; if (C_A_D) schedule_task(&cad_tq); else kill_proc(cad_pid, SIGINT, 1);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -