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