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         inode->i_dirt = 1;
 247         return notify_change(inode);
 248 }
 249 
 250 int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252         struct inode * inode;
 253         int error;
 254 
 255         error = namei(filename,&inode);
 256         if (error)
 257                 return error;
 258         if ((current->euid != inode->i_uid) && !suser()) {
 259                 iput(inode);
 260                 return -EPERM;
 261         }
 262         if (IS_RDONLY(inode)) {
 263                 iput(inode);
 264                 return -EROFS;
 265         }
 266         inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
 267         inode->i_dirt = 1;
 268         error = notify_change(inode);
 269         iput(inode);
 270         return error;
 271 }
 272 
 273 int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275         struct inode * inode;
 276         struct file * file;
 277 
 278         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 279                 return -EBADF;
 280         if (!(inode = file->f_inode))
 281                 return -ENOENT;
 282         if (IS_RDONLY(inode))
 283                 return -EROFS;
 284         if (user == (uid_t) -1)
 285                 user = inode->i_uid;
 286         if (group == (gid_t) -1)
 287                 group = inode->i_gid;
 288         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 289              (in_group_p(group) || group == inode->i_gid)) ||
 290             suser()) {
 291                 inode->i_uid = user;
 292                 inode->i_gid = group;
 293                 inode->i_dirt = 1;
 294                 return notify_change(inode);
 295         }
 296         return -EPERM;
 297 }
 298 
 299 int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301         struct inode * inode;
 302         int error;
 303 
 304         error = lnamei(filename,&inode);
 305         if (error)
 306                 return error;
 307         if (IS_RDONLY(inode)) {
 308                 iput(inode);
 309                 return -EROFS;
 310         }
 311         if (user == (uid_t) -1)
 312                 user = inode->i_uid;
 313         if (group == (gid_t) -1)
 314                 group = inode->i_gid;
 315         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 316              (in_group_p(group) || group == inode->i_gid)) ||
 317             suser()) {
 318                 inode->i_uid = user;
 319                 inode->i_gid = group;
 320                 inode->i_dirt = 1;
 321                 error = notify_change(inode);
 322                 iput(inode);
 323                 return error;
 324         }
 325         iput(inode);
 326         return -EPERM;
 327 }
 328 
 329 /*
 330  * Note that while the flag value (low two bits) for sys_open means:
 331  *      00 - read-only
 332  *      01 - write-only
 333  *      10 - read-write
 334  *      11 - special
 335  * it is changed into
 336  *      00 - no permissions needed
 337  *      01 - read-permission
 338  *      10 - write-permission
 339  *      11 - read-write
 340  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 341  * used by symlinks.
 342  */
 343 int sys_open(const char * filename,int flag,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 344 {
 345         struct inode * inode;
 346         struct file * f;
 347         int i,fd;
 348 
 349         for(fd=0 ; fd<NR_OPEN ; fd++)
 350                 if (!current->filp[fd])
 351                         break;
 352         if (fd>=NR_OPEN)
 353                 return -EMFILE;
 354         FD_CLR(fd,&current->close_on_exec);
 355         f = get_empty_filp();
 356         if (!f)
 357                 return -ENFILE;
 358         current->filp[fd] = f;
 359         f->f_flags = flag;
 360         f->f_mode = (flag+1) & O_ACCMODE;
 361         if (f->f_mode)
 362                 flag++;
 363         if (flag & (O_TRUNC | O_CREAT))
 364                 flag |= 2;
 365         i = open_namei(filename,flag,mode,&inode,NULL);
 366         if (i) {
 367                 current->filp[fd]=NULL;
 368                 f->f_count--;
 369                 return i;
 370         }
 371         if (flag & O_TRUNC) {
 372                 inode->i_size = 0;
 373                 if (inode->i_op && inode->i_op->truncate)
 374                         inode->i_op->truncate(inode);
 375                 if ((i = notify_change(inode))) {
 376                         iput(inode);
 377                         current->filp[fd] = NULL;
 378                         f->f_count--;
 379                         return i;
 380                 }
 381         }
 382         if (!IS_RDONLY(inode)) {
 383                 inode->i_atime = CURRENT_TIME;
 384                 inode->i_dirt = 1;
 385         }
 386         f->f_inode = inode;
 387         f->f_pos = 0;
 388         f->f_reada = 0;
 389         f->f_op = NULL;
 390         if (inode->i_op)
 391                 f->f_op = inode->i_op->default_file_ops;
 392         if (f->f_op && f->f_op->open) {
 393                 i = f->f_op->open(inode,f);
 394                 if (i) {
 395                         iput(inode);
 396                         f->f_count--;
 397                         current->filp[fd]=NULL;
 398                         return i;
 399                 }
 400         }
 401         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 402         return (fd);
 403 }
 404 
 405 int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 406 {
 407         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 408 }
 409 
 410 int close_fp(struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412         struct inode *inode;
 413 
 414         if (filp->f_count == 0) {
 415                 printk("Close: file count is 0\n");
 416                 return 0;
 417         }
 418         inode = filp->f_inode;
 419         if (S_ISREG(inode->i_mode))
 420                 fcntl_remove_locks(current, filp);
 421         if (filp->f_count > 1) {
 422                 filp->f_count--;
 423                 return 0;
 424         }
 425         if (filp->f_op && filp->f_op->release)
 426                 filp->f_op->release(inode,filp);
 427         filp->f_count--;
 428         filp->f_inode = NULL;
 429         iput(inode);
 430         return 0;
 431 }
 432 
 433 int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {       
 435         struct file * filp;
 436 
 437         if (fd >= NR_OPEN)
 438                 return -EINVAL;
 439         FD_CLR(fd, &current->close_on_exec);
 440         if (!(filp = current->filp[fd]))
 441                 return -EINVAL;
 442         current->filp[fd] = NULL;
 443         return (close_fp (filp));
 444 }
 445 
 446 /*
 447  * This routine is used by vhangup.  It send's sigkill to everything
 448  * waiting on a particular wait_queue.  It assumes root privledges.
 449  * We don't want to destroy the wait queue here, because the caller
 450  * should call wake_up immediately after calling kill_wait.
 451  */
 452 static void kill_wait(struct wait_queue **q, int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454         struct wait_queue *next;
 455         struct wait_queue *tmp;
 456         struct task_struct *p;
 457 
 458         if (!q || !(next = *q))
 459                 return;
 460         do { 
 461                 tmp = next;
 462                 next = tmp->next;
 463                 if ((p = tmp->task) != NULL)
 464                         send_sig (sig, p , 1);
 465         } while (next && next != *q);
 466 }
 467 
 468 /*
 469  * This routine looks through all the process's and closes any
 470  * references to the current processes tty.  To avoid problems with
 471  * process sleeping on an inode which has already been iput, anyprocess
 472  * which is sleeping on the tty is sent a sigkill (It's probably a rogue
 473  * process.)  Also no process should ever have /dev/console as it's
 474  * controlling tty, or have it open for reading.  So we don't have to
 475  * worry about messing with all the daemons abilities to write messages
 476  * to the console.  (Besides they should be using syslog.)
 477  */
 478 int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 479 {
 480         int j;
 481         struct task_struct ** process;
 482         struct file *filep;
 483         struct inode *inode;
 484         struct tty_struct *tty;
 485         extern int kill_pg (int pgrp, int sig, int priv);
 486 
 487         if (!suser())
 488                 return -EPERM;
 489         /* send the SIGHUP signal. */
 490         kill_pg(current->pgrp, SIGHUP, 0);
 491         /* See if there is a controlling tty. */
 492         if (current->tty < 0)
 493                 return 0;
 494 
 495         for (process = task + 0; process < task + NR_TASKS; process++) {
 496                 for (j = 0; j < NR_OPEN; j++) {
 497                         if (!*process)
 498                                 break;
 499                         if (!(filep = (*process)->filp[j]))
 500                                 continue;
 501                         if (!(inode = filep->f_inode))
 502                                 continue;
 503                         if (!S_ISCHR(inode->i_mode))
 504                                 continue;
 505                         if ((MAJOR(inode->i_rdev) == 5 ||
 506                              MAJOR(inode->i_rdev) == 4 ) &&
 507                             (MAJOR(filep->f_rdev) == 4 &&
 508                              MINOR(filep->f_rdev) == MINOR (current->tty))) {
 509                   /* so now we have found something to close.  We
 510                      need to kill every process waiting on the
 511                      inode. */
 512                                 (*process)->filp[j] = NULL;
 513                                 kill_wait (&inode->i_wait, SIGKILL);
 514 
 515                   /* now make sure they are awake before we close the
 516                      file. */
 517 
 518                                 wake_up (&inode->i_wait);
 519 
 520                   /* finally close the file. */
 521 
 522                                 FD_CLR(j, &(*process)->close_on_exec);
 523                                 close_fp (filep);
 524                         }
 525                 }
 526         /* can't let them keep a reference to it around.
 527            But we can't touch current->tty until after the
 528            loop is complete. */
 529 
 530                 if (*process && (*process)->tty == current->tty && *process != current) {
 531                         (*process)->tty = -1;
 532                 }
 533         }
 534    /* need to do tty->session = 0 */
 535         tty = TTY_TABLE(MINOR(current->tty));
 536         if (tty) {
 537                 tty->session = 0;
 538                 tty->pgrp = -1;
 539                 current->tty = -1;
 540         }
 541         return 0;
 542 }
 543 

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