xref: /openbmc/linux/fs/ext2/ioctl.c (revision 1da177e4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * linux/fs/ext2/ioctl.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 1993, 1994, 1995
51da177e4SLinus Torvalds  * Remy Card (card@masi.ibp.fr)
61da177e4SLinus Torvalds  * Laboratoire MASI - Institut Blaise Pascal
71da177e4SLinus Torvalds  * Universite Pierre et Marie Curie (Paris VI)
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include "ext2.h"
111da177e4SLinus Torvalds #include <linux/time.h>
121da177e4SLinus Torvalds #include <linux/sched.h>
131da177e4SLinus Torvalds #include <asm/current.h>
141da177e4SLinus Torvalds #include <asm/uaccess.h>
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
181da177e4SLinus Torvalds 		unsigned long arg)
191da177e4SLinus Torvalds {
201da177e4SLinus Torvalds 	struct ext2_inode_info *ei = EXT2_I(inode);
211da177e4SLinus Torvalds 	unsigned int flags;
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds 	ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds 	switch (cmd) {
261da177e4SLinus Torvalds 	case EXT2_IOC_GETFLAGS:
271da177e4SLinus Torvalds 		flags = ei->i_flags & EXT2_FL_USER_VISIBLE;
281da177e4SLinus Torvalds 		return put_user(flags, (int __user *) arg);
291da177e4SLinus Torvalds 	case EXT2_IOC_SETFLAGS: {
301da177e4SLinus Torvalds 		unsigned int oldflags;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 		if (IS_RDONLY(inode))
331da177e4SLinus Torvalds 			return -EROFS;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
361da177e4SLinus Torvalds 			return -EACCES;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 		if (get_user(flags, (int __user *) arg))
391da177e4SLinus Torvalds 			return -EFAULT;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 		if (!S_ISDIR(inode->i_mode))
421da177e4SLinus Torvalds 			flags &= ~EXT2_DIRSYNC_FL;
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds 		oldflags = ei->i_flags;
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 		/*
471da177e4SLinus Torvalds 		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
481da177e4SLinus Torvalds 		 * the relevant capability.
491da177e4SLinus Torvalds 		 *
501da177e4SLinus Torvalds 		 * This test looks nicer. Thanks to Pauline Middelink
511da177e4SLinus Torvalds 		 */
521da177e4SLinus Torvalds 		if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
531da177e4SLinus Torvalds 			if (!capable(CAP_LINUX_IMMUTABLE))
541da177e4SLinus Torvalds 				return -EPERM;
551da177e4SLinus Torvalds 		}
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 		flags = flags & EXT2_FL_USER_MODIFIABLE;
581da177e4SLinus Torvalds 		flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
591da177e4SLinus Torvalds 		ei->i_flags = flags;
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 		ext2_set_inode_flags(inode);
621da177e4SLinus Torvalds 		inode->i_ctime = CURRENT_TIME_SEC;
631da177e4SLinus Torvalds 		mark_inode_dirty(inode);
641da177e4SLinus Torvalds 		return 0;
651da177e4SLinus Torvalds 	}
661da177e4SLinus Torvalds 	case EXT2_IOC_GETVERSION:
671da177e4SLinus Torvalds 		return put_user(inode->i_generation, (int __user *) arg);
681da177e4SLinus Torvalds 	case EXT2_IOC_SETVERSION:
691da177e4SLinus Torvalds 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
701da177e4SLinus Torvalds 			return -EPERM;
711da177e4SLinus Torvalds 		if (IS_RDONLY(inode))
721da177e4SLinus Torvalds 			return -EROFS;
731da177e4SLinus Torvalds 		if (get_user(inode->i_generation, (int __user *) arg))
741da177e4SLinus Torvalds 			return -EFAULT;
751da177e4SLinus Torvalds 		inode->i_ctime = CURRENT_TIME_SEC;
761da177e4SLinus Torvalds 		mark_inode_dirty(inode);
771da177e4SLinus Torvalds 		return 0;
781da177e4SLinus Torvalds 	default:
791da177e4SLinus Torvalds 		return -ENOTTY;
801da177e4SLinus Torvalds 	}
811da177e4SLinus Torvalds }
82