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

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