root/fs/open.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_ustat
  2. sys_statfs
  3. sys_fstatfs
  4. sys_truncate
  5. sys_ftruncate
  6. sys_utime
  7. sys_access
  8. sys_chdir
  9. sys_chroot
  10. sys_fchmod
  11. sys_chmod
  12. sys_fchown
  13. sys_chown
  14. sys_open
  15. sys_creat
  16. close_fp
  17. sys_close
  18. kill_wait
  19. sys_vhangup

   1 /*
   2  *  linux/fs/open.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/vfs.h>
   8 #include <linux/types.h>
   9 #include <linux/utime.h>
  10 #include <linux/errno.h>
  11 #include <linux/fcntl.h>
  12 #include <linux/stat.h>
  13 #include <linux/string.h>
  14 #include <linux/sched.h>
  15 #include <linux/kernel.h>
  16 #include <linux/signal.h>
  17 #include <linux/tty.h>
  18 #include <linux/time.h>
  19 
  20 #include <asm/segment.h>
  21 
  22 extern void fcntl_remove_locks(struct task_struct *, struct file *);
  23 
  24 struct file_operations * chrdev_fops[MAX_CHRDEV] = {
  25         NULL,
  26 };
  27 
  28 struct file_operations * blkdev_fops[MAX_BLKDEV] = {
  29         NULL,
  30 };
  31 
  32 int sys_ustat(int dev, struct ustat * ubuf)
     /* [previous][next][first][last][top][bottom][index][help] */
  33 {
  34         return -ENOSYS;
  35 }
  36 
  37 int sys_statfs(const char * path, struct statfs * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         struct inode * inode;
  40         int error;
  41 
  42         verify_area(buf, sizeof(struct statfs));
  43         error = namei(path,&inode);
  44         if (error)
  45                 return error;
  46         if (!inode->i_sb->s_op->statfs) {
  47                 iput(inode);
  48                 return -ENOSYS;
  49         }
  50         inode->i_sb->s_op->statfs(inode->i_sb, buf);
  51         iput(inode);
  52         return 0;
  53 }
  54 
  55 int sys_fstatfs(unsigned int fd, struct statfs * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         struct inode * inode;
  58         struct file * file;
  59 
  60         verify_area(buf, sizeof(struct statfs));
  61         if (fd >= NR_OPEN || !(file = current->filp[fd]))
  62                 return -EBADF;
  63         if (!(inode = file->f_inode))
  64                 return -ENOENT;
  65         if (!inode->i_sb->s_op->statfs)
  66                 return -ENOSYS;
  67         inode->i_sb->s_op->statfs(inode->i_sb, buf);
  68         return 0;
  69 }
  70 
  71 int sys_truncate(const char * path, unsigned int length)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73         struct inode * inode;
  74         int error;
  75 
  76         error = namei(path,&inode);
  77         if (error)
  78                 return error;
  79         if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) {
  80                 iput(inode);
  81                 return -EACCES;
  82         }
  83         if (IS_RDONLY(inode)) {
  84                 iput(inode);
  85                 return -EROFS;
  86         }
  87         inode->i_size = length;
  88         if (inode->i_op && inode->i_op->truncate)
  89                 inode->i_op->truncate(inode);
  90         inode->i_atime = inode->i_mtime = CURRENT_TIME;
  91         inode->i_dirt = 1;
  92         error = notify_change(inode);
  93         iput(inode);
  94         return error;
  95 }
  96 
  97 int sys_ftruncate(unsigned int fd, unsigned int length)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99         struct inode * inode;
 100         struct file * file;
 101 
 102         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 103                 return -EBADF;
 104         if (!(inode = file->f_inode))
 105                 return -ENOENT;
 106         if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
 107                 return -EACCES;
 108         inode->i_size = length;
 109         if (inode->i_op && inode->i_op->truncate)
 110                 inode->i_op->truncate(inode);
 111         inode->i_atime = inode->i_mtime = CURRENT_TIME;
 112         inode->i_dirt = 1;
 113         return notify_change(inode);
 114 }
 115 
 116 /* If times==NULL, set access and modification to current time,
 117  * must be owner or have write permission.
 118  * Else, update from *times, must be owner or super user.
 119  */
 120 int sys_utime(char * filename, struct utimbuf * times)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122         struct inode * inode;
 123         long actime,modtime;
 124         int error;
 125 
 126         error = namei(filename,&inode);
 127         if (error)
 128                 return error;
 129         if (IS_RDONLY(inode)) {
 130                 iput(inode);
 131                 return -EROFS;
 132         }
 133         if (times) {
 134                 if ((current->euid != inode->i_uid) && !suser()) {
 135                         iput(inode);
 136                         return -EPERM;
 137                 }
 138                 actime = get_fs_long((unsigned long *) &times->actime);
 139                 modtime = get_fs_long((unsigned long *) &times->modtime);
 140         } else {
 141                 if ((current->euid != inode->i_uid) &&
 142                     !permission(inode,MAY_WRITE)) {
 143                         iput(inode);
 144                         return -EACCES;
 145                 }
 146                 actime = modtime = CURRENT_TIME;
 147         }
 148         inode->i_atime = actime;
 149         inode->i_mtime = modtime;
 150         inode->i_ctime = CURRENT_TIME;
 151         inode->i_dirt = 1;
 152         error = notify_change(inode);
 153         iput(inode);
 154         return error;
 155 }
 156 
 157 /*
 158  * XXX should we use the real or effective uid?  BSD uses the real uid,
 159  * so as to make this call useful to setuid programs.
 160  */
 161 int sys_access(const char * filename,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 162 {
 163         struct inode * inode;
 164         int res, i_mode;
 165 
 166         mode &= 0007;
 167         res = namei(filename,&inode);
 168         if (res)
 169                 return res;
 170         i_mode = res = inode->i_mode & 0777;
 171         iput(inode);
 172         if (current->uid == inode->i_uid)
 173                 res >>= 6;
 174         else if (in_group_p(inode->i_gid))
 175                 res >>= 3;
 176         if ((res & 0007 & mode) == mode)
 177                 return 0;
 178         /*
 179          * XXX we are doing this test last because we really should be
 180          * swapping the effective with the real user id (temporarily),
 181          * and then calling suser() routine.  If we do call the
 182          * suser() routine, it needs to be called last. 
 183          */
 184         if ((!current->uid) &&
 185             (!(mode & 1) || (i_mode & 0111)))
 186                 return 0;
 187         return -EACCES;
 188 }
 189 
 190 int sys_chdir(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         struct inode * inode;
 193         int error;
 194 
 195         error = namei(filename,&inode);
 196         if (error)
 197                 return error;
 198         if (!S_ISDIR(inode->i_mode)) {
 199                 iput(inode);
 200                 return -ENOTDIR;
 201         }
 202         if (!permission(inode,MAY_EXEC)) {
 203                 iput(inode);
 204                 return -EACCES;
 205         }
 206         iput(current->pwd);
 207         current->pwd = inode;
 208         return (0);
 209 }
 210 
 211 int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213         struct inode * inode;
 214         int error;
 215 
 216         error = namei(filename,&inode);
 217         if (error)
 218                 return error;
 219         if (!S_ISDIR(inode->i_mode)) {
 220                 iput(inode);
 221                 return -ENOTDIR;
 222         }
 223         if (!suser()) {
 224                 iput(inode);
 225                 return -EPERM;
 226         }
 227         iput(current->root);
 228         current->root = inode;
 229         return (0);
 230 }
 231 
 232 int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         struct inode * inode;
 235         struct file * file;
 236 
 237         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 238                 return -EBADF;
 239         if (!(inode = file->f_inode))
 240                 return -ENOENT;
 241         if ((current->euid != inode->i_uid) && !suser())
 242                 return -EPERM;
 243         if (IS_RDONLY(inode))
 244                 return -EROFS;
 245         inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
 246         if (!suser() && !in_group_p(inode->i_gid))
 247                 inode->i_mode &= ~S_ISGID;
 248         inode->i_ctime = CURRENT_TIME;
 249         inode->i_dirt = 1;
 250         return notify_change(inode);
 251 }
 252 
 253 int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255         struct inode * inode;
 256         int error;
 257 
 258         error = namei(filename,&inode);
 259         if (error)
 260                 return error;
 261         if ((current->euid != inode->i_uid) && !suser()) {
 262                 iput(inode);
 263                 return -EPERM;
 264         }
 265         if (IS_RDONLY(inode)) {
 266                 iput(inode);
 267                 return -EROFS;
 268         }
 269         inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
 270         if (!suser() && !in_group_p(inode->i_gid))
 271                 inode->i_mode &= ~S_ISGID;
 272         inode->i_ctime = CURRENT_TIME;
 273         inode->i_dirt = 1;
 274         error = notify_change(inode);
 275         iput(inode);
 276         return error;
 277 }
 278 
 279 int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281         struct inode * inode;
 282         struct file * file;
 283 
 284         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 285                 return -EBADF;
 286         if (!(inode = file->f_inode))
 287                 return -ENOENT;
 288         if (IS_RDONLY(inode))
 289                 return -EROFS;
 290         if (user == (uid_t) -1)
 291                 user = inode->i_uid;
 292         if (group == (gid_t) -1)
 293                 group = inode->i_gid;
 294         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 295              (in_group_p(group) || group == inode->i_gid)) ||
 296             suser()) {
 297                 inode->i_uid = user;
 298                 inode->i_gid = group;
 299                 inode->i_ctime = CURRENT_TIME;
 300                 inode->i_dirt = 1;
 301                 return notify_change(inode);
 302         }
 303         return -EPERM;
 304 }
 305 
 306 int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308         struct inode * inode;
 309         int error;
 310 
 311         error = lnamei(filename,&inode);
 312         if (error)
 313                 return error;
 314         if (IS_RDONLY(inode)) {
 315                 iput(inode);
 316                 return -EROFS;
 317         }
 318         if (user == (uid_t) -1)
 319                 user = inode->i_uid;
 320         if (group == (gid_t) -1)
 321                 group = inode->i_gid;
 322         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 323              (in_group_p(group) || group == inode->i_gid)) ||
 324             suser()) {
 325                 inode->i_uid = user;
 326                 inode->i_gid = group;
 327                 inode->i_ctime = CURRENT_TIME;
 328                 inode->i_dirt = 1;
 329                 error = notify_change(inode);
 330                 iput(inode);
 331                 return error;
 332         }
 333         iput(inode);
 334         return -EPERM;
 335 }
 336 
 337 /*
 338  * Note that while the flag value (low two bits) for sys_open means:
 339  *      00 - read-only
 340  *      01 - write-only
 341  *      10 - read-write
 342  *      11 - special
 343  * it is changed into
 344  *      00 - no permissions needed
 345  *      01 - read-permission
 346  *      10 - write-permission
 347  *      11 - read-write
 348  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 349  * used by symlinks.
 350  */
 351 int sys_open(const char * filename,int flag,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 352 {
 353         struct inode * inode;
 354         struct file * f;
 355         int i,fd;
 356 
 357         for(fd=0 ; fd<NR_OPEN ; fd++)
 358                 if (!current->filp[fd])
 359                         break;
 360         if (fd>=NR_OPEN)
 361                 return -EMFILE;
 362         FD_CLR(fd,&current->close_on_exec);
 363         f = get_empty_filp();
 364         if (!f)
 365                 return -ENFILE;
 366         current->filp[fd] = f;
 367         f->f_flags = flag;
 368         f->f_mode = (flag+1) & O_ACCMODE;
 369         if (f->f_mode)
 370                 flag++;
 371         if (flag & (O_TRUNC | O_CREAT))
 372                 flag |= 2;
 373         i = open_namei(filename,flag,mode,&inode,NULL);
 374         if (i) {
 375                 current->filp[fd]=NULL;
 376                 f->f_count--;
 377                 return i;
 378         }
 379         if (flag & O_TRUNC) {
 380                 inode->i_size = 0;
 381                 if (inode->i_op && inode->i_op->truncate)
 382                         inode->i_op->truncate(inode);
 383                 if ((i = notify_change(inode))) {
 384                         iput(inode);
 385                         current->filp[fd] = NULL;
 386                         f->f_count--;
 387                         return i;
 388                 }
 389         }
 390         if (!IS_RDONLY(inode)) {
 391                 inode->i_atime = CURRENT_TIME;
 392                 inode->i_dirt = 1;
 393         }
 394         f->f_inode = inode;
 395         f->f_pos = 0;
 396         f->f_reada = 0;
 397         f->f_op = NULL;
 398         if (inode->i_op)
 399                 f->f_op = inode->i_op->default_file_ops;
 400         if (f->f_op && f->f_op->open) {
 401                 i = f->f_op->open(inode,f);
 402                 if (i) {
 403                         iput(inode);
 404                         f->f_count--;
 405                         current->filp[fd]=NULL;
 406                         return i;
 407                 }
 408         }
 409         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 410         return (fd);
 411 }
 412 
 413 int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {
 415         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 416 }
 417 
 418 int close_fp(struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420         struct inode *inode;
 421 
 422         if (filp->f_count == 0) {
 423                 printk("Close: file count is 0\n");
 424                 return 0;
 425         }
 426         inode = filp->f_inode;
 427         if (inode && S_ISREG(inode->i_mode))
 428                 fcntl_remove_locks(current, filp);
 429         if (filp->f_count > 1) {
 430                 filp->f_count--;
 431                 return 0;
 432         }
 433         if (filp->f_op && filp->f_op->release)
 434                 filp->f_op->release(inode,filp);
 435         filp->f_count--;
 436         filp->f_inode = NULL;
 437         iput(inode);
 438         return 0;
 439 }
 440 
 441 int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {       
 443         struct file * filp;
 444 
 445         if (fd >= NR_OPEN)
 446                 return -EINVAL;
 447         FD_CLR(fd, &current->close_on_exec);
 448         if (!(filp = current->filp[fd]))
 449                 return -EINVAL;
 450         current->filp[fd] = NULL;
 451         return (close_fp (filp));
 452 }
 453 
 454 /*
 455  * This routine is used by vhangup.  It send's sigkill to everything
 456  * waiting on a particular wait_queue.  It assumes root privledges.
 457  * We don't want to destroy the wait queue here, because the caller
 458  * should call wake_up immediately after calling kill_wait.
 459  */
 460 static void kill_wait(struct wait_queue **q, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 461 {
 462         struct wait_queue *next;
 463         struct wait_queue *tmp;
 464         struct task_struct *p;
 465 
 466         if (!q || !(next = *q))
 467                 return;
 468         do { 
 469                 tmp = next;
 470                 next = tmp->next;
 471                 if ((p = tmp->task) != NULL)
 472                         send_sig (sig, p , 1);
 473         } while (next && next != *q);
 474 }
 475 
 476 /*
 477  * This routine looks through all the process's and closes any
 478  * references to the current processes tty.  To avoid problems with
 479  * process sleeping on an inode which has already been iput, anyprocess
 480  * which is sleeping on the tty is sent a sigkill (It's probably a rogue
 481  * process.)  Also no process should ever have /dev/console as it's
 482  * controlling tty, or have it open for reading.  So we don't have to
 483  * worry about messing with all the daemons abilities to write messages
 484  * to the console.  (Besides they should be using syslog.)
 485  */
 486 int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 487 {
 488         int j;
 489         struct task_struct ** process;
 490         struct file *filep;
 491         struct inode *inode;
 492         struct tty_struct *tty;
 493         extern int kill_pg (int pgrp, int sig, int priv);
 494 
 495         if (!suser())
 496                 return -EPERM;
 497         /* See if there is a controlling tty. */
 498         if (current->tty < 0)
 499                 return 0;
 500         /* send the SIGHUP signal. */
 501         tty = TTY_TABLE(current->tty);
 502         if (tty && tty->pgrp > 0)
 503                 kill_pg(tty->pgrp, SIGHUP, 0);
 504 
 505         for (process = task + 0; process < task + NR_TASKS; process++) {
 506                 for (j = 0; j < NR_OPEN; j++) {
 507                         if (!*process)
 508                                 break;
 509                         if (!(filep = (*process)->filp[j]))
 510                                 continue;
 511                         if (!(inode = filep->f_inode))
 512                                 continue;
 513                         if (!S_ISCHR(inode->i_mode))
 514                                 continue;
 515                         if ((MAJOR(inode->i_rdev) == 5 ||
 516                              MAJOR(inode->i_rdev) == 4 ) &&
 517                             (MAJOR(filep->f_rdev) == 4 &&
 518                              MINOR(filep->f_rdev) == MINOR (current->tty))) {
 519                   /* so now we have found something to close.  We
 520                      need to kill every process waiting on the
 521                      inode. */
 522                                 (*process)->filp[j] = NULL;
 523                                 kill_wait (&inode->i_wait, SIGKILL);
 524 
 525                   /* now make sure they are awake before we close the
 526                      file. */
 527 
 528                                 wake_up (&inode->i_wait);
 529 
 530                   /* finally close the file. */
 531 
 532                                 FD_CLR(j, &(*process)->close_on_exec);
 533                                 close_fp (filep);
 534                         }
 535                 }
 536         /* can't let them keep a reference to it around.
 537            But we can't touch current->tty until after the
 538            loop is complete. */
 539 
 540                 if (*process && (*process)->tty == current->tty && *process != current) {
 541                         (*process)->tty = -1;
 542                 }
 543         }
 544    /* need to do tty->session = 0 */
 545         tty = TTY_TABLE(MINOR(current->tty));
 546         if (tty) {
 547                 tty->session = 0;
 548                 tty->pgrp = -1;
 549                 current->tty = -1;
 550         }
 551         return 0;
 552 }
 553 

/* [previous][next][first][last][top][bottom][index][help] */