linux-old/kernel/sys.c
<<
>>
Prefs
   1/*
   2 *  linux/kernel/sys.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/config.h>
   8#include <linux/errno.h>
   9#include <linux/sched.h>
  10#include <linux/kernel.h>
  11#include <linux/times.h>
  12#include <linux/utsname.h>
  13#include <linux/param.h>
  14#include <linux/resource.h>
  15#include <linux/signal.h>
  16#include <linux/string.h>
  17#include <linux/ptrace.h>
  18#include <linux/stat.h>
  19#include <linux/mman.h>
  20#include <linux/mm.h>
  21#include <linux/fcntl.h>
  22#include <linux/acct.h>
  23#include <linux/tty.h>
  24#include <linux/smp.h>
  25#include <linux/smp_lock.h>
  26#include <linux/notifier.h>
  27#include <linux/reboot.h>
  28#include <linux/prctl.h>
  29
  30#include <asm/uaccess.h>
  31#include <asm/io.h>
  32
  33/*
  34 * this indicates whether you can reboot with ctrl-alt-del: the default is yes
  35 */
  36
  37int C_A_D = 1;
  38
  39
  40/*
  41 *      Notifier list for kernel code which wants to be called
  42 *      at shutdown. This is used to stop any idling DMA operations
  43 *      and the like. 
  44 */
  45
  46struct notifier_block *reboot_notifier_list = NULL;
  47
  48int register_reboot_notifier(struct notifier_block * nb)
  49{
  50        return notifier_chain_register(&reboot_notifier_list, nb);
  51}
  52
  53int unregister_reboot_notifier(struct notifier_block * nb)
  54{
  55        return notifier_chain_unregister(&reboot_notifier_list, nb);
  56}
  57
  58
  59
  60extern void adjust_clock(void);
  61
  62asmlinkage int sys_ni_syscall(void)
  63{
  64        return -ENOSYS;
  65}
  66
  67static int proc_sel(struct task_struct *p, int which, int who)
  68{
  69        if(p->pid)
  70        {
  71                switch (which) {
  72                        case PRIO_PROCESS:
  73                                if (!who && p == current)
  74                                        return 1;
  75                                return(p->pid == who);
  76                        case PRIO_PGRP:
  77                                if (!who)
  78                                        who = current->pgrp;
  79                                return(p->pgrp == who);
  80                        case PRIO_USER:
  81                                if (!who)
  82                                        who = current->uid;
  83                                return(p->uid == who);
  84                }
  85        }
  86        return 0;
  87}
  88
  89asmlinkage int sys_setpriority(int which, int who, int niceval)
  90{
  91        struct task_struct *p;
  92        unsigned int priority;
  93        int error;
  94
  95        if (which > 2 || which < 0)
  96                return -EINVAL;
  97
  98        /* normalize: avoid signed division (rounding problems) */
  99        error = ESRCH;
 100        priority = niceval;
 101        if (niceval < 0)
 102                priority = -niceval;
 103        if (priority > 20)
 104                priority = 20;
 105        priority = (priority * DEF_PRIORITY + 10) / 20 + DEF_PRIORITY;
 106
 107        if (niceval >= 0) {
 108                priority = 2*DEF_PRIORITY - priority;
 109                if (!priority)
 110                        priority = 1;
 111        }
 112
 113        read_lock(&tasklist_lock);
 114        for_each_task(p) {
 115                if (!proc_sel(p, which, who))
 116                        continue;
 117                if (p->uid != current->euid &&
 118                        p->uid != current->uid && !suser()) {
 119                        error = EPERM;
 120                        continue;
 121                }
 122                if (error == ESRCH)
 123                        error = 0;
 124                if (priority > p->priority && !suser())
 125                        error = EACCES;
 126                else
 127                        p->priority = priority;
 128        }
 129        read_unlock(&tasklist_lock);
 130
 131        return -error;
 132}
 133
 134/*
 135 * Ugh. To avoid negative return values, "getpriority()" will
 136 * not return the normal nice-value, but a value that has been
 137 * offset by 20 (ie it returns 0..40 instead of -20..20)
 138 */
 139asmlinkage int sys_getpriority(int which, int who)
 140{
 141        struct task_struct *p;
 142        long max_prio = -ESRCH;
 143
 144        if (which > 2 || which < 0)
 145                return -EINVAL;
 146
 147        read_lock(&tasklist_lock);
 148        for_each_task (p) {
 149                if (!proc_sel(p, which, who))
 150                        continue;
 151                if (p->priority > max_prio)
 152                        max_prio = p->priority;
 153        }
 154        read_unlock(&tasklist_lock);
 155
 156        /* scale the priority from timeslice to 0..40 */
 157        if (max_prio > 0)
 158                max_prio = (max_prio * 20 + DEF_PRIORITY/2) / DEF_PRIORITY;
 159        return max_prio;
 160}
 161
 162
 163extern asmlinkage int sys_kill(int, int);
 164
 165/*
 166 * Reboot system call: for obvious reasons only root may call it,
 167 * and even root needs to set up some magic numbers in the registers
 168 * so that some mistake won't make this reboot the whole machine.
 169 * You can also set the meaning of the ctrl-alt-del-key here.
 170 *
 171 * reboot doesn't sync: do that yourself before calling this.
 172 *
 173 */
 174asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg)
 175{
 176        char buffer[256];
 177
 178        /* We only trust the superuser with rebooting the system. */
 179        if (!suser())
 180                return -EPERM;
 181
 182        /* For safety, we require "magic" arguments. */
 183        if (magic1 != LINUX_REBOOT_MAGIC1 ||
 184            (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A))
 185                return -EINVAL;
 186
 187        lock_kernel();
 188        switch (cmd) {
 189        case LINUX_REBOOT_CMD_RESTART:
 190                notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
 191                printk(KERN_EMERG "Restarting system.\n");
 192                machine_restart(NULL);
 193                break;
 194
 195        case LINUX_REBOOT_CMD_CAD_ON:
 196                C_A_D = 1;
 197                break;
 198
 199        case LINUX_REBOOT_CMD_CAD_OFF:
 200                C_A_D = 0;
 201                break;
 202
 203        case LINUX_REBOOT_CMD_HALT:
 204                notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
 205                printk(KERN_EMERG "System halted.\n");
 206                machine_halt();
 207                do_exit(0);
 208                break;
 209
 210        case LINUX_REBOOT_CMD_POWER_OFF:
 211                notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
 212                printk(KERN_EMERG "Power down.\n");
 213                machine_power_off();
 214                do_exit(0);
 215                break;
 216
 217        case LINUX_REBOOT_CMD_RESTART2:
 218                if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
 219                        unlock_kernel();
 220                        return -EFAULT;
 221                }
 222                buffer[sizeof(buffer) - 1] = '\0';
 223
 224                notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
 225                printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
 226                machine_restart(buffer);
 227                break;
 228
 229        default:
 230                unlock_kernel();
 231                return -EINVAL;
 232                break;
 233        };
 234        unlock_kernel();
 235        return 0;
 236}
 237
 238/*
 239 * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
 240 * As it's called within an interrupt, it may NOT sync: the only choice
 241 * is whether to reboot at once, or just ignore the ctrl-alt-del.
 242 */
 243void ctrl_alt_del(void)
 244{
 245        if (C_A_D) {
 246                notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
 247                machine_restart(NULL);
 248        } else
 249                kill_proc(1, SIGINT, 1);
 250}
 251        
 252
 253/*
 254 * Unprivileged users may change the real gid to the effective gid
 255 * or vice versa.  (BSD-style)
 256 *
 257 * If you set the real gid at all, or set the effective gid to a value not
 258 * equal to the real gid, then the saved gid is set to the new effective gid.
 259 *
 260 * This makes it possible for a setgid program to completely drop its
 261 * privileges, which is often a useful assertion to make when you are doing
 262 * a security audit over a program.
 263 *
 264 * The general idea is that a program which uses just setregid() will be
 265 * 100% compatible with BSD.  A program which uses just setgid() will be
 266 * 100% compatible with POSIX w/ Saved ID's. 
 267 *
 268 * SMP: There are not races, the gid's are checked only by filesystem
 269 *      operations (as far as semantic preservation is concerned).
 270 */
 271asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
 272{
 273        int old_rgid = current->gid;
 274        int old_egid = current->egid;
 275
 276        if (rgid != (gid_t) -1) {
 277                if ((old_rgid == rgid) ||
 278                    (current->egid==rgid) ||
 279                    suser())
 280                        current->gid = rgid;
 281                else
 282                        return -EPERM;
 283        }
 284        if (egid != (gid_t) -1) {
 285                if ((old_rgid == egid) ||
 286                    (current->egid == egid) ||
 287                    (current->sgid == egid) ||
 288                    suser())
 289                        current->fsgid = current->egid = egid;
 290                else {
 291                        current->gid = old_rgid;
 292                        return -EPERM;
 293                }
 294        }
 295        if (rgid != (gid_t) -1 ||
 296            (egid != (gid_t) -1 && egid != old_rgid))
 297                current->sgid = current->egid;
 298        current->fsgid = current->egid;
 299        if (current->egid != old_egid)
 300                current->dumpable = 0;
 301        return 0;
 302}
 303
 304/*
 305 * setgid() is implemented like SysV w/ SAVED_IDS 
 306 *
 307 * SMP: Same implicit races as above.
 308 */
 309asmlinkage int sys_setgid(gid_t gid)
 310{
 311        int old_egid = current->egid;
 312
 313        if (suser())
 314                current->gid = current->egid = current->sgid = current->fsgid = gid;
 315        else if ((gid == current->gid) || (gid == current->sgid))
 316                current->egid = current->fsgid = gid;
 317        else
 318                return -EPERM;
 319
 320        if (current->egid != old_egid)
 321                current->dumpable = 0;
 322        return 0;
 323}
 324  
 325static char acct_active = 0;
 326static struct file acct_file;
 327
 328int acct_process(long exitcode)
 329{
 330   struct acct ac;
 331   unsigned long fs;
 332
 333   if (acct_active) {
 334      strncpy(ac.ac_comm, current->comm, ACCT_COMM);
 335      ac.ac_comm[ACCT_COMM-1] = '\0';
 336      ac.ac_utime = current->times.tms_utime;
 337      ac.ac_stime = current->times.tms_stime;
 338      ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
 339      ac.ac_etime = CURRENT_TIME - ac.ac_btime;
 340      ac.ac_uid   = current->uid;
 341      ac.ac_gid   = current->gid;
 342      ac.ac_tty   = (current)->tty == NULL ? -1 :
 343          kdev_t_to_nr(current->tty->device);
 344      ac.ac_flag  = 0;
 345      if (current->flags & PF_FORKNOEXEC)
 346         ac.ac_flag |= AFORK;
 347      if (current->flags & PF_SUPERPRIV)
 348         ac.ac_flag |= ASU;
 349      if (current->flags & PF_DUMPCORE)
 350         ac.ac_flag |= ACORE;
 351      if (current->flags & PF_SIGNALED)
 352         ac.ac_flag |= AXSIG;
 353      ac.ac_minflt = current->min_flt;
 354      ac.ac_majflt = current->maj_flt;
 355      ac.ac_exitcode = exitcode;
 356
 357      /* Kernel segment override */
 358      fs = get_fs();
 359      set_fs(KERNEL_DS);
 360
 361      acct_file.f_op->write(acct_file.f_dentry->d_inode, &acct_file,
 362                             (char *)&ac, sizeof(struct acct));
 363      set_fs(fs);
 364   }
 365   return 0;
 366}
 367
 368asmlinkage int sys_acct(const char *name)
 369{
 370        int error = -EPERM;
 371
 372        lock_kernel();
 373        if (!suser())
 374                goto out;
 375
 376        if (name == (char *)0) {
 377                if (acct_active) {
 378                        if (acct_file.f_op->release)
 379                                acct_file.f_op->release(acct_file.f_dentry->d_inode, &acct_file);
 380
 381                        if (acct_file.f_dentry != NULL)
 382                                dput(acct_file.f_dentry);
 383
 384                        acct_active = 0;
 385                }
 386                error = 0;
 387        } else {
 388                error = -EBUSY;
 389                if (!acct_active) {
 390                        struct dentry *dentry;
 391                        struct inode *inode;
 392                        char *tmp;
 393
 394                        tmp = getname(name);
 395                        error = PTR_ERR(tmp);
 396                        if (IS_ERR(tmp))
 397                                goto out;
 398
 399                        dentry = open_namei(tmp, O_RDWR, 0600);
 400                        putname(tmp);
 401
 402                        error = PTR_ERR(dentry);
 403                        if (IS_ERR(dentry))
 404                                goto out;
 405                        inode = dentry->d_inode;
 406
 407                        error = -EACCES;
 408                        if (!S_ISREG(inode->i_mode)) {
 409                                dput(dentry);
 410                                goto out;
 411                        }
 412
 413                        error = -EIO;
 414                        if (!inode->i_op || !inode->i_op->default_file_ops || 
 415                            !inode->i_op->default_file_ops->write) {
 416                                dput(dentry);
 417                                goto out;
 418                        }
 419
 420                        acct_file.f_mode = 3;
 421                        acct_file.f_flags = 0;
 422                        acct_file.f_count = 1;
 423                        acct_file.f_dentry = dentry;
 424                        acct_file.f_pos = inode->i_size;
 425                        acct_file.f_reada = 0;
 426                        acct_file.f_op = inode->i_op->default_file_ops;
 427
 428                        if(acct_file.f_op->open) {
 429                                error = acct_file.f_op->open(inode, &acct_file);
 430                                if (error) {
 431                                        dput(dentry);
 432                                        goto out;
 433                                }
 434                        }
 435
 436                        acct_active = 1;
 437                        error = 0;
 438                }
 439        }
 440out:
 441        unlock_kernel();
 442        return error;
 443}
 444
 445
 446/*
 447 * Unprivileged users may change the real uid to the effective uid
 448 * or vice versa.  (BSD-style)
 449 *
 450 * If you set the real uid at all, or set the effective uid to a value not
 451 * equal to the real uid, then the saved uid is set to the new effective uid.
 452 *
 453 * This makes it possible for a setuid program to completely drop its
 454 * privileges, which is often a useful assertion to make when you are doing
 455 * a security audit over a program.
 456 *
 457 * The general idea is that a program which uses just setreuid() will be
 458 * 100% compatible with BSD.  A program which uses just setuid() will be
 459 * 100% compatible with POSIX w/ Saved ID's. 
 460 */
 461asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
 462{
 463        int old_ruid, old_euid, new_ruid;
 464
 465        new_ruid = old_ruid = current->uid;
 466        old_euid = current->euid;
 467        if (ruid != (uid_t) -1) {
 468                if ((old_ruid == ruid) || 
 469                    (current->euid==ruid) ||
 470                    suser())
 471                        new_ruid = ruid;
 472                else
 473                        return -EPERM;
 474        }
 475        if (euid != (uid_t) -1) {
 476                if ((old_ruid == euid) ||
 477                    (current->euid == euid) ||
 478                    (current->suid == euid) ||
 479                    suser())
 480                        current->fsuid = current->euid = euid;
 481                else
 482                        return -EPERM;
 483        }
 484        if (ruid != (uid_t) -1 ||
 485            (euid != (uid_t) -1 && euid != old_ruid))
 486                current->suid = current->euid;
 487        current->fsuid = current->euid;
 488        if (current->euid != old_euid)
 489                current->dumpable = 0;
 490
 491        if(new_ruid != old_ruid) {
 492                /* What if a process setreuid()'s and this brings the
 493                 * new uid over his NPROC rlimit?  We can check this now
 494                 * cheaply with the new uid cache, so if it matters
 495                 * we should be checking for it.  -DaveM
 496                 */
 497                charge_uid(current, -1);
 498                current->uid = new_ruid;
 499                if(new_ruid)
 500                        charge_uid(current, 1);
 501        }
 502        return 0;
 503}
 504
 505/*
 506 * setuid() is implemented like SysV w/ SAVED_IDS 
 507 * 
 508 * Note that SAVED_ID's is deficient in that a setuid root program
 509 * like sendmail, for example, cannot set its uid to be a normal 
 510 * user and then switch back, because if you're root, setuid() sets
 511 * the saved uid too.  If you don't like this, blame the bright people
 512 * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
 513 * will allow a root program to temporarily drop privileges and be able to
 514 * regain them by swapping the real and effective uid.  
 515 */
 516asmlinkage int sys_setuid(uid_t uid)
 517{
 518        int old_euid = current->euid;
 519        int old_ruid, new_ruid;
 520
 521        old_ruid = new_ruid = current->uid;
 522        if (suser())
 523                new_ruid = current->euid = current->suid = current->fsuid = uid;
 524        else if ((uid == current->uid) || (uid == current->suid))
 525                current->fsuid = current->euid = uid;
 526        else
 527                return -EPERM;
 528
 529        if (current->euid != old_euid)
 530                current->dumpable = 0;
 531
 532        if(new_ruid != old_ruid) {
 533                /* See comment above about NPROC rlimit issues... */
 534                charge_uid(current, -1);
 535                current->uid = new_ruid;
 536                if(new_ruid)
 537                        charge_uid(current, 1);
 538        }
 539        return 0;
 540}
 541
 542
 543/*
 544 * This function implementes a generic ability to update ruid, euid,
 545 * and suid.  This allows you to implement the 4.4 compatible seteuid().
 546 */
 547asmlinkage int sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 548{
 549        if (current->uid != 0 && current->euid != 0 && current->suid != 0) {
 550                if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
 551                    (ruid != current->euid) && (ruid != current->suid))
 552                        return -EPERM;
 553                if ((euid != (uid_t) -1) && (euid != current->uid) &&
 554                    (euid != current->euid) && (euid != current->suid))
 555                        return -EPERM;
 556                if ((suid != (uid_t) -1) && (suid != current->uid) &&
 557                    (suid != current->euid) && (suid != current->suid))
 558                        return -EPERM;
 559        }
 560        if (ruid != (uid_t) -1) {
 561                /* See above commentary about NPROC rlimit issues here. */
 562                charge_uid(current, -1);
 563                current->uid = ruid;
 564                if(ruid)
 565                        charge_uid(current, 1);
 566        }
 567        if (euid != (uid_t) -1) {
 568                if (euid != current->euid)
 569                        current->dumpable = 0;
 570                current->euid = euid;
 571                current->fsuid = euid;
 572        }
 573        if (suid != (uid_t) -1)
 574                current->suid = suid;
 575        return 0;
 576}
 577
 578asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
 579{
 580        int retval;
 581
 582        if (!(retval = put_user(current->uid, ruid)) &&
 583            !(retval = put_user(current->euid, euid)))
 584                retval = put_user(current->suid, suid);
 585
 586        return retval;
 587}
 588
 589/*
 590 * Same as above, but for rgid, egid, sgid.
 591 */
 592asmlinkage int sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 593{
 594        if (current->uid != 0 && current->euid != 0 && current->suid != 0) {
 595                if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
 596                    (rgid != current->egid) && (rgid != current->sgid))
 597                        return -EPERM;
 598                if ((egid != (gid_t) -1) && (egid != current->gid) &&
 599                    (egid != current->egid) && (egid != current->sgid))
 600                        return -EPERM;
 601                if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
 602                    (sgid != current->egid) && (sgid != current->sgid))
 603                        return -EPERM;
 604        }
 605        if (rgid != (gid_t) -1)
 606                current->gid = rgid;
 607        if (egid != (gid_t) -1) {
 608                if (egid != current->egid)
 609                        current->dumpable = 0;
 610                current->egid = egid;
 611                current->fsgid = egid;
 612        }
 613        if (sgid != (gid_t) -1)
 614                current->sgid = sgid;
 615        return 0;
 616}
 617
 618asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 619{
 620        int retval;
 621
 622        if (!(retval = put_user(current->gid, rgid)) &&
 623            !(retval = put_user(current->egid, egid)))
 624                retval = put_user(current->sgid, sgid);
 625
 626        return retval;
 627}
 628
 629
 630/*
 631 * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
 632 * is used for "access()" and for the NFS daemon (letting nfsd stay at
 633 * whatever uid it wants to). It normally shadows "euid", except when
 634 * explicitly set by setfsuid() or for access..
 635 */
 636asmlinkage int sys_setfsuid(uid_t uid)
 637{
 638        int old_fsuid;
 639
 640        old_fsuid = current->fsuid;
 641        if (uid == current->uid || uid == current->euid ||
 642            uid == current->suid || uid == current->fsuid || suser())
 643                current->fsuid = uid;
 644        if (current->fsuid != old_fsuid)
 645                current->dumpable = 0;
 646
 647        return old_fsuid;
 648}
 649
 650/*
 651 * Samma på svenska..
 652 */
 653asmlinkage int sys_setfsgid(gid_t gid)
 654{
 655        int old_fsgid;
 656
 657        old_fsgid = current->fsgid;
 658        if (gid == current->gid || gid == current->egid ||
 659            gid == current->sgid || gid == current->fsgid || suser())
 660                current->fsgid = gid;
 661        if (current->fsgid != old_fsgid)
 662                current->dumpable = 0;
 663
 664        return old_fsgid;
 665}
 666
 667asmlinkage long sys_times(struct tms * tbuf)
 668{
 669        /*
 670         *      In the SMP world we might just be unlucky and have one of
 671         *      the times increment as we use it. Since the value is an
 672         *      atomically safe type this is just fine. Conceptually its
 673         *      as if the syscall took an instant longer to occur.
 674         */
 675        if (tbuf)
 676                if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
 677                        return -EFAULT;
 678        return jiffies;
 679}
 680
 681/*
 682 * This needs some heavy checking ...
 683 * I just haven't the stomach for it. I also don't fully
 684 * understand sessions/pgrp etc. Let somebody who does explain it.
 685 *
 686 * OK, I think I have the protection semantics right.... this is really
 687 * only important on a multi-user system anyway, to make sure one user
 688 * can't send a signal to a process owned by another.  -TYT, 12/12/91
 689 *
 690 * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
 691 * LBT 04.03.94
 692 */
 693
 694asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
 695{
 696        struct task_struct * p;
 697        int err = -EINVAL;
 698
 699        if (!pid)
 700                pid = current->pid;
 701        if (!pgid)
 702                pgid = pid;
 703        if (pgid < 0)
 704                return -EINVAL;
 705
 706        if((p = find_task_by_pid(pid)) == NULL)
 707                return -ESRCH;
 708
 709        /* From this point forward we keep holding onto the tasklist lock
 710         * so that our parent does not change from under us. -DaveM
 711         */
 712        read_lock(&tasklist_lock);
 713        err = -ESRCH;
 714        if (p->p_pptr == current || p->p_opptr == current) {
 715                err = -EPERM;
 716                if (p->session != current->session)
 717                        goto out;
 718                err = -EACCES;
 719                if (p->did_exec)
 720                        goto out;
 721        } else if (p != current)
 722                goto out;
 723        err = -EPERM;
 724        if (p->leader)
 725                goto out;
 726        if (pgid != pid) {
 727                struct task_struct * tmp;
 728                for_each_task (tmp) {
 729                        if (tmp->pgrp == pgid &&
 730                            tmp->session == current->session)
 731                                goto ok_pgid;
 732                }
 733                goto out;
 734        }
 735
 736ok_pgid:
 737        p->pgrp = pgid;
 738        err = 0;
 739out:
 740        /* All paths lead to here, thus we are safe. -DaveM */
 741        read_unlock(&tasklist_lock);
 742        return err;
 743}
 744
 745asmlinkage int sys_getpgid(pid_t pid)
 746{
 747        if (!pid) {
 748                return current->pgrp;
 749        } else {
 750                struct task_struct *p = find_task_by_pid(pid);
 751
 752                if(p)
 753                        return p->pgrp;
 754                else
 755                        return -ESRCH;
 756        }
 757}
 758
 759asmlinkage int sys_getpgrp(void)
 760{
 761        /* SMP - assuming writes are word atomic this is fine */
 762        return current->pgrp;
 763}
 764
 765asmlinkage int sys_getsid(pid_t pid)
 766{
 767        if (!pid) {
 768                return current->session;
 769        } else {
 770                struct task_struct *p = find_task_by_pid(pid);
 771
 772                if(p)
 773                        return p->session;
 774                else
 775                        return -ESRCH;
 776        }
 777}
 778
 779asmlinkage int sys_setsid(void)
 780{
 781        struct task_struct * p;
 782        int err = -EPERM;
 783
 784        read_lock(&tasklist_lock);
 785        for_each_task(p) {
 786                if (p->pgrp == current->pid)
 787                        goto out;
 788        }
 789
 790        current->leader = 1;
 791        current->session = current->pgrp = current->pid;
 792        current->tty = NULL;
 793        current->tty_old_pgrp = 0;
 794        err = current->pgrp;
 795out:
 796        read_unlock(&tasklist_lock);
 797        return err;
 798}
 799
 800/*
 801 * Supplementary group ID's
 802 */
 803asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
 804{
 805        int i;
 806        
 807        /*
 808         *      SMP: Nobody else can change our grouplist. Thus we are
 809         *      safe.
 810         */
 811
 812        if (gidsetsize < 0)
 813                return -EINVAL;
 814        i = current->ngroups;
 815        if (gidsetsize) {
 816                if (i > gidsetsize)
 817                        return -EINVAL;
 818                if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
 819                        return -EFAULT;
 820        }
 821        return i;
 822}
 823
 824/*
 825 *      SMP: Our groups are not shared. We can copy to/from them safely
 826 *      without another task interfering.
 827 */
 828 
 829asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
 830{
 831        if (!suser())
 832                return -EPERM;
 833        if ((unsigned) gidsetsize > NGROUPS)
 834                return -EINVAL;
 835        if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
 836                return -EFAULT;
 837        current->ngroups = gidsetsize;
 838        return 0;
 839}
 840
 841int in_group_p(gid_t grp)
 842{
 843        if (grp != current->fsgid) {
 844                int i = current->ngroups;
 845                if (i) {
 846                        gid_t *groups = current->groups;
 847                        do {
 848                                if (*groups == grp)
 849                                        goto out;
 850                                groups++;
 851                                i--;
 852                        } while (i);
 853                }
 854                return 0;
 855        }
 856out:
 857        return 1;
 858}
 859
 860asmlinkage int sys_newuname(struct new_utsname * name)
 861{
 862        if (!name)
 863                return -EFAULT;
 864        if (copy_to_user(name,&system_utsname,sizeof *name))
 865                return -EFAULT;
 866        return 0;
 867}
 868
 869asmlinkage int sys_sethostname(char *name, int len)
 870{
 871        if (!suser())
 872                return -EPERM;
 873        if (len < 0 || len > __NEW_UTS_LEN)
 874                return -EINVAL;
 875        if(copy_from_user(system_utsname.nodename, name, len))
 876                return -EFAULT;
 877        system_utsname.nodename[len] = 0;
 878#ifdef CONFIG_TRANS_NAMES
 879        translations_dirty = 1;
 880#endif
 881        return 0;
 882}
 883
 884asmlinkage int sys_gethostname(char *name, int len)
 885{
 886        int i;
 887
 888        if (len < 0)
 889                return -EINVAL;
 890        i = 1 + strlen(system_utsname.nodename);
 891        if (i > len)
 892                i = len;
 893        return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0;
 894}
 895
 896/*
 897 * Only setdomainname; getdomainname can be implemented by calling
 898 * uname()
 899 */
 900asmlinkage int sys_setdomainname(char *name, int len)
 901{
 902        if (!suser())
 903                return -EPERM;
 904        if (len < 0 || len > __NEW_UTS_LEN)
 905                return -EINVAL;
 906        if(copy_from_user(system_utsname.domainname, name, len))
 907                return -EFAULT;
 908        system_utsname.domainname[len] = 0;
 909#ifdef CONFIG_TRANS_NAMES
 910        translations_dirty = 1;
 911#endif
 912        return 0;
 913}
 914
 915asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
 916{
 917        if (resource >= RLIM_NLIMITS)
 918                return -EINVAL;
 919        else
 920                return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
 921                        ? -EFAULT : 0;
 922}
 923
 924asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
 925{
 926        struct rlimit new_rlim, *old_rlim;
 927
 928        if (resource >= RLIM_NLIMITS)
 929                return -EINVAL;
 930        if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
 931                return -EFAULT;
 932        old_rlim = current->rlim + resource;
 933        if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
 934             (new_rlim.rlim_max > old_rlim->rlim_max)) &&
 935            !suser())
 936                return -EPERM;
 937        if (resource == RLIMIT_NOFILE) {
 938                if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
 939                        return -EPERM;
 940        }
 941        *old_rlim = new_rlim;
 942        return 0;
 943}
 944
 945/*
 946 * It would make sense to put struct rusage in the task_struct,
 947 * except that would make the task_struct be *really big*.  After
 948 * task_struct gets moved into malloc'ed memory, it would
 949 * make sense to do this.  It will make moving the rest of the information
 950 * a lot simpler!  (Which we're not doing right now because we're not
 951 * measuring them yet).
 952 *
 953 * This is SMP safe.  Either we are called from sys_getrusage on ourselves
 954 * below (we know we aren't going to exit/disappear and only we change our
 955 * rusage counters), or we are called from wait4() on a process which is
 956 * either stopped or zombied.  In the zombied case the task won't get
 957 * reaped till shortly after the call to getrusage(), in both cases the
 958 * task being examined is in a frozen state so the counters won't change.
 959 */
 960int getrusage(struct task_struct *p, int who, struct rusage *ru)
 961{
 962        struct rusage r;
 963
 964        memset((char *) &r, 0, sizeof(r));
 965        switch (who) {
 966                case RUSAGE_SELF:
 967                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
 968                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
 969                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
 970                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
 971                        r.ru_minflt = p->min_flt;
 972                        r.ru_majflt = p->maj_flt;
 973                        r.ru_nswap = p->nswap;
 974                        break;
 975                case RUSAGE_CHILDREN:
 976                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
 977                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
 978                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
 979                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
 980                        r.ru_minflt = p->cmin_flt;
 981                        r.ru_majflt = p->cmaj_flt;
 982                        r.ru_nswap = p->cnswap;
 983                        break;
 984                default:
 985                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
 986                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
 987                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
 988                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
 989                        r.ru_minflt = p->min_flt + p->cmin_flt;
 990                        r.ru_majflt = p->maj_flt + p->cmaj_flt;
 991                        r.ru_nswap = p->nswap + p->cnswap;
 992                        break;
 993        }
 994        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 995}
 996
 997asmlinkage int sys_getrusage(int who, struct rusage *ru)
 998{
 999        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
1000                return -EINVAL;
1001        return getrusage(current, who, ru);
1002}
1003
1004asmlinkage int sys_umask(int mask)
1005{
1006        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
1007        return mask;
1008}
1009    
1010asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
1011                         unsigned long arg4, unsigned long arg5)
1012{
1013        int error = 0;
1014        int sig;
1015
1016        switch (option) {
1017                case PR_SET_PDEATHSIG:
1018                        sig = arg2;
1019                        if (sig > _NSIG) {
1020                                error = -EINVAL;
1021                                break;
1022                        }
1023                        current->pdeath_signal = sig;
1024                        break;
1025                default:
1026                        error = -EINVAL;
1027                        break;
1028        }
1029        return error;
1030}
1031
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.