/* * Kernel mode file operations wrappers. * * Author : Ramit Bhalla * Created : 18th August 2003 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * * Revision History : * * Version 1.0 * - Initial Release */ #ifndef __KERNEL__ #define __KERNEL__ #endif #include #include #include #include /*********************************************************************************************** * Function Name : kernel_fopen * * Details : This function opens/create a file in kernel mode. * * Arguments : filename - the name of the file to be opened * flags - same flags used by fopen() * mode - file permissions as used by fopen() * * Return Value : file pointer if successful * NULL if failed. ***********************************************************************************************/ struct file * kernel_fopen(const char * filename, unsigned int flags, int mode) { int orgfsuid, orgfsgid; struct file * file_ret; /* * Save uid and gid used for filesystem access. */ orgfsuid = current->fsuid; orgfsgid = current->fsgid; /* * Set user and group to 0 (root) */ current->fsuid = 0; current->fsgid = 0; /* * Open the file in kernel mode */ file_ret = filp_open(filename, flags, mode); /* * Restore the uid and gid */ current->fsuid = orgfsuid; current->fsgid = orgfsgid; /* * Check if the file was opened successfully * and return the file pointer of it was. */ return ((IS_ERR(file_ret)) ? NULL : file_ret); } /*********************************************************************************************** * Function Name : kernel_fclose * * Details : This function closes a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * * Return Value : 0 if successful * error code if failed. * -ENOENT if file pointer is not valid ***********************************************************************************************/ int kernel_fclose(struct file * file_ptr) { int orgfsuid, orgfsgid; int file_ret; /* * Check if the file pointer is valid */ if((NULL == file_ptr) || (IS_ERR(file_ptr))) return -ENOENT; /* * Save uid and gid used for filesystem access. */ orgfsuid = current->fsuid; orgfsgid = current->fsgid; /* * Set user and group to 0 (root) */ current->fsuid = 0; current->fsgid = 0; /* * Close the file in kernel mode (user_id = 0) */ file_ret = filp_close(file_ptr, 0); /* * Restore the uid and gid */ current->fsuid = orgfsuid; current->fsgid = orgfsgid; /* * Return the error code. */ return (file_ret); } /*********************************************************************************************** * Function Name : kernel_fseek * * Details : This function seeks the file position in a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * offset - offset into the file * whence - starting point (SEEK_CUR, SEEK_SET or SEEK_EMD) * * Return Value : new file position * -ENOENT if file pointer is not valid * -EINVAL if offset type is not valid ***********************************************************************************************/ loff_t kernel_fseek(struct file * file_ptr, int offset, int whence) { /* * Check for a valid file pointer */ if((NULL != file_ptr) && (!(IS_ERR(file_ptr)))) { /* * Check the operation to be performed */ switch(whence) { case SEEK_SET: file_ptr->f_pos = offset; /* Absolute offset */ break; case SEEK_CUR: file_ptr->f_pos += offset; /* Relative offset */ break; case SEEK_END: file_ptr->f_pos = file_ptr->f_dentry->d_inode->i_size - offset; /* Offset from the end of file */ break; default: return -EINVAL; /* Invalid offset type */ } /* * Check for boundary conditions */ if (file_ptr->f_pos < 0) file_ptr->f_pos = 0; /* * Return the current file pointer */ return (file_ptr->f_pos); } else return -ENOENT; /* File pointer does not exist */ } /*********************************************************************************************** * Function Name : kernel_fread * * Details : This function reads data from a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * buf - buffer to read data into * len - length of buffer to read * * Return Value : number of bytes read from the file * -ENOENT if file pointer is invalid * -ENOSYS if file read function is invalid * -EACCES if file read permissions are not valid * -EINVAL if length is not valid ***********************************************************************************************/ int kernel_fread(struct file * file_ptr, char * buf, int len) { int orgfsuid, orgfsgid; int file_ret; mm_segment_t orgfs; /* * Check if the file pointer is valid */ if((NULL == file_ptr) || (IS_ERR(file_ptr))) return -ENOENT; /* * Check for a valid file read function */ if(file_ptr->f_op->read == NULL) return -ENOSYS; /* * Check for access permissions */ if(((file_ptr->f_flags & O_ACCMODE) & (O_RDONLY | O_RDWR)) != 0) return -EACCES; /* * Check if there is a valid length */ if(0 >= len) return -EINVAL; /* * Save uid and gid used for filesystem access. */ orgfsuid = current->fsuid; orgfsgid = current->fsgid; /* * Set user and group to 0 (root) */ current->fsuid = 0; current->fsgid = 0; /* * Save FS register and set FS register to kernel * space, needed for read and write to accept * buffer in kernel space. */ orgfs = get_fs(); /* * Set the FS register to KERNEL mode. */ set_fs(KERNEL_DS); /* * Read the actual data from the file */ file_ret = file_ptr->f_op->read(file_ptr, buf, len, &file_ptr->f_pos); /* * Restore the FS register */ set_fs(orgfs); /* * Restore the uid and gid */ current->fsuid = orgfsuid; current->fsgid = orgfsgid; /* * Return the number of bytes read. */ return (file_ret); } /*********************************************************************************************** * Function Name : kernel_fgetc * * Details : This function reads a character from a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * * Return Value : character read from file * EOF if end of file * Error code if file cannot be read ***********************************************************************************************/ int kernel_fgetc(struct file * file_ptr) { int read_ret; char buf; /* * Read one byte from the file */ read_ret = kernel_fread(file_ptr, &buf, 1); /* * Check return value */ if (read_ret > 0) return buf; /* Return the character read */ else if (0 == read_ret) return -1; /* End of file */ else return read_ret; /* Error code */ } /*********************************************************************************************** * Function Name : kernel_fgets * * Details : This function reads a string from a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * str - buffer to read data into * len - length of buffer to read * * Return Value : number of bytes read if successful * Error code if there was an error reading from the file * -EINVAL if length is not valid ***********************************************************************************************/ int kernel_fgets(struct file * file_ptr, char * str, int len) { int file_ret, readlen; char * cp; /* * Check if there is a valid length */ if(0 >= len) return -EINVAL; /* * Read the actual data from the file and parse it */ for(cp = str, file_ret = -1, readlen = 0; readlen < len - 1; ++cp, ++readlen) { /* * Read one character from the file */ file_ret = kernel_fgetc(file_ptr); /* * Check for error in reading */ if(0 >= file_ret) break; /* End of file or error in file */ else *cp = file_ret; /* Update - actual data read */ /* * Check for a new line character */ if(*cp == '\n') { ++cp; ++readlen; break; } } /* * Last character of string is NULL */ *cp = (char) NULL; /* * Return the number of bytes read or error. */ return ((0 >= file_ret) ? file_ret : readlen); } /*********************************************************************************************** * Function Name : kernel_fwrite * * Details : This function writes data to a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * buf - buffer to write data from * len - length of buffer to write * * Return Value : number of bytes written to the file * -ENOENT if file pointer is invalid * -ENOSYS if file write function is invalid * -EACCES if file write permissions are not valid * -EINVAL if length is not valid ***********************************************************************************************/ int kernel_fwrite(struct file * file_ptr, char * buf, int len) { int orgfsuid, orgfsgid; int file_ret; mm_segment_t orgfs; /* * Check if the file pointer is valid */ if((NULL == file_ptr) || (IS_ERR(file_ptr))) return -ENOENT; /* * Check for a valid file write function */ if(file_ptr->f_op->write == NULL) return -ENOSYS; /* * Check for access permissions */ if(((file_ptr->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) != 0) return -EACCES; /* * Check if there is a valid length */ if(0 >= len) return -EINVAL; /* * Save uid and gid used for filesystem access. */ orgfsuid = current->fsuid; orgfsgid = current->fsgid; /* * Set user and group to 0 (root) */ current->fsuid = 0; current->fsgid = 0; /* * Save FS register and set FS register to kernel * space, needed for read and write to accept * buffer in kernel space. */ orgfs = get_fs(); /* * Set the FS register to KERNEL mode. */ set_fs(KERNEL_DS); /* * Read the actual data from the file */ file_ret = file_ptr->f_op->write(file_ptr, buf, len, &file_ptr->f_pos); /* * Restore the FS register */ set_fs(orgfs); /* * Restore the uid and gid */ current->fsuid = orgfsuid; current->fsgid = orgfsgid; /* * Return the number of bytes read. */ return (file_ret); } /*********************************************************************************************** * Function Name : kernel_fputc * * Details : This function writes a character to a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * buf - character to be written into file * * Return Value : character written to file * EOF if end of file * Error code if file cannot be written to ***********************************************************************************************/ int kernel_fputc(struct file * file_ptr, char buf) { int write_ret; /* * Write one byte to the file */ write_ret = kernel_fwrite(file_ptr, &buf, 1); /* * Check return value */ if (write_ret > 0) return buf; /* Return the character written */ else if (0 == write_ret) return -1; /* End of file */ else return write_ret; /* Error code */ } /*********************************************************************************************** * Function Name : kernel_fputs * * Details : This function writes a string to a file in kernel mode. * * Arguments : file_ptr - Pointer to the file ops structure * str - String to be written to file * * Return Value : number of characters written to file * Error code if not successful (value returned by kernel_fwrite) ***********************************************************************************************/ int kernel_fputs(struct file * file_ptr, char * str) { /* * Write to file */ return (kernel_fwrite(file_ptr, str, strlen(str))); } /*********************************************************************************************** * Function Name : kernel_fprintf * * Details : This function writes a to a file using the printf format in kernel mode. * The maximum data to be written is limited to 1024 bytes. * * Arguments : file_ptr - Pointer to the file ops structure * fmt - String formatting * ... - variable arguments * * Return Value : number of characters written to file * Error code if not successful (value returned by kernel_fwrite) ***********************************************************************************************/ int kernel_fprintf(struct file * file_ptr, const char * fmt, ...) { static char s_buf[1024]; va_list args; /* * Format the data to be written */ va_start(args, fmt); vsprintf(s_buf, fmt, args); va_end(args); /* * Write to file and return the error code */ return kernel_fputs(file_ptr, s_buf); }