What is the meaning of F_GETFD in fcntl() function in unix ?, From what I understand it should return -1 if there is no file descriptor in the position specified.. If that's true, when would it happen ? when doing close to a file descriptor in that posstion, F_GETFD doesn't return -1 either..
This is a part of a program using F_GETFD and it will not return -1 if I close the x fd (thid fd entered 0 in the fd table since we closed 0 beforehand and did dup(x)):
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
void try(){
printf("got_sig\n");
}
int main(int argc, char *argv[]){
int x, stdout=1;
signal(SIGUSR1,&try);
x = open("t1.txt",O_RDWR|O_CREAT, 0666);
close(0);
dup(x);
close(x);
if (fcntl(0,F_GETFD)==-1)
printf("false\n");
kill(getpid(),SIGUSR1);
//close(x);
write(stdout,"BYE\n",4);
exit(0);
}
When will F_GETFD return -1 ?
From the man page of fcntl():
File descriptor flags
The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit
is set, the file descriptor will automatically be closed during a successful execve(2).
F_GETFD (void)
Return (as the function result) the file descriptor flags; arg
is ignored.
(Or see the POSIX standard text for fctnl(), if you care.)
So, fnctl(fd, F_GETFD) tells you if the file descriptor stays open over an execve() or not.
The usual error cases for fcntl() apply, so it would e.g. return -1 and set errno to EBADF if the fd you gave wasn't open. In your code, you called fcntl() on fd 0, which holds the dup'ed copy of x, and so is open. fcntl() would return -1 for the fd x, though, that's the one you explicitly closed.
Inspecting the implementation of do_fcntl in the Linux kernel, we can see that:
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
struct file *filp)
{
long err = -EINVAL;
switch (cmd) {
...
case F_GETFD:
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
break;
...
}
return err;
}
do_fcntl(F_GETFD) may return only FD_CLOEXEC or 0.
The syscall definition from here can return -EBADF in case of a bad file descriptor or the file descriptor was opened with O_PATH.
Judging from that, the fcntl(F_GETFD) will return only -1 with errno set to -9 (-EBADF), or return 0 or 1 (FD_CLOEXEC) on Linux 4.20. So the fcntl(F_GETFD) will return -1 in case of a bad file descriptor or file descriptor opened with O_PATH. Note that for other kernels it may be different and note that it can change over time.
Related
I am trying to write a simple FTP-like client-server network program on macOS using sendfile() function. After reading Apple's developer Manual on this topic, sadly I am still having trouble using it.
Code
// creation of fd
int fd = open("file_path", O_RDONLY);
off_t len = 0;
// the creation of sockets used in sendfile
getaddrinfo(NULL, port, &hints, &servinfo);
// p is iterating through servinfo (p=p->ai_next)
sockfd= socket(p->ai_family, p->ai_socktype, p->ai_protocol);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
bind(sockfd, p->ai_addr, p->ai_addrlen);
listen(sockfd, BACKLOG); //BACKLOG is a macro configuring pending connections
new_sockfd = accept(sockfd, (struct sockaddr*)&clients_addr, &sin_size);
// sendfile
if(sendfile(new_sockfd, fd, 0, &len, NULL, 0)==-1){
fprintf(stderr, "server sendfile errno: %d", errno);
// sorry I know this is not the best way to interpret the errno
}
The client got a message of "connection closed by peer" while the errno code has been set to 45;
I have checked the file descriptor fd using read() and printed it, it works fine;
You have got the arguments backwards. According to the documentation, error code ENOTSUP (which I assume is "operation not supported" - thanks to Jeremy Friesner for looking it up - you should print strerror(errno) as it's useful) means that fd is not a regular file.
fd is the first argument.
int sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);
The sendfile() system call sends a regular file specified by descriptor fd out a stream socket specified by descriptor s.
So your code isn't trying to send the file through the socket. It's trying to send the socket through the file, which doesn't make sense. Change the order.
I have a program that I want to use to read a file and output its last N characters (could be 50 or whatever that I have coded). From my piece of code, I get output that is question marks in diamond boxes,(unsupported unicode?)
I'm using lseek to set the cursor, could someone please assist me?
int main(int argc,char *argv[]){
int fd; //file descriptor to hold open info
int count=0; //to hold value of last 200th char number
char ch; //holds read char
char* outputString = "The file does not exist!\n";
if(!access("myFile.txt",F_OK)==0){
write(2,outputString,strlen(outputString));
exit(1);
}
fd = open("myFile.txt",O_RDONLY| O_NONBLOCK);
int ret = lseek(fd,200,SEEK_END); //get position of the last 200th item
while (ret!=0) {
write(1, &ch,1);
ret--;
}
close(fd);
return(0);
}
I don't want to use <stdio.h> functions so I'm using the file descriptors not making a FILE* object.
I slightly modified your attempt. The lseek(fd, 200, SEEK_END) seeks the file 200 characters past the end of file. If you want to read last 200 character from a file, you need to seek to 200 character to end of file, ie lseek(fd, -200, SEEK_END).
I places some comments in code to help explaining.
// please include headers when posting questions on stackoverflow
// It makes it way easier to reproduce and play with the code from others
#include <unistd.h>
#include <error.h>
// I use glibc error(3) to handle errors
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc,char *argv[]){
// no idea if a typo, myFile.txt != logfile.txt
if(!access("myFile.txt", F_OK) == 0) {
error(1, errno, "The file does not exist!");
exit(1);
}
int fd = open("logfile.txt", O_RDONLY | O_NONBLOCK);
if (fd == -1) {
error(1, errno, "Failed opening the file");
}
// move cursor position to the 200th characters from the end
int ret = lseek(fd, -200, SEEK_END);
if (ret == -1) {
error(1, errno, "Failed seeking the file");
}
// we break below
while (1) {
char ch = 0; // holds read char
ssize_t readed = read(fd, &ch, sizeof(ch));
if (readed == 0) {
// end-of-file, break
break;
} else if (readed == -1) {
// error handle
// actually we could handle `readed != 1`
error(1, errno, "Error reading from file");
}
// output the readed character on stdout
// note that `STDOUT_FILENO` as more readable alternative to plain `1`
write(STDOUT_FILENO, &ch, sizeof(ch));
}
close(fd);
return 0;
}
I wrote a program that returns an error code using processes.
The result of the work of the program, if at the entrance to it provide the command of a false, is 255.
However the command
false; echo $?
returns 1
Why it happens?
Solaris, unix
I found the file false.c in the source code, it returns 255 (not sure if this is the right command)
https://github.com/illumos/illumos-gate/blob/master/usr/src/cmd/false/false.c
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <wait.h>
main(int argc, char *argv[])
{
int status;
pid_t pid = fork();
if (pid == -1){
perror("fork error");
exit(-1);
}
if (pid == 0) {
execvp(argv[1], &argv[1]);
perror(argv[1]);
exit(-5);
}
if( wait(&status) == -1){
perror("wait");
exit(-1);
}
if(WIFEXITED(status))
printf("exit status: %d\n",WEXITSTATUS(status));
exit(0);
}
UNIX (Linux, Solaris, BSD, etc.) exit codes may only be 0 - 255, where 0 is good and non-zero is an error. Exit codes are not signed, so the -1 may be converted to another (non-zero) value, as are values over 255.
I have a file called myhj.txt which I hid with using this command from cmd attrib +h +s +r myhj.txt. Now I can't open the file with standart fopen() function in C, so I have decided to use GetFileAttributes() function which does not return an error. According to MSDN, when the function succeeds the return value is File Attribute Constants
I don't know how to get their values as the program crushes when it tries to run printf() down below. Also would it work stable when the file is hidden? How do I access a hidden file with all of its values?
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
FILE *log;
int main(int argc, char *argv[]) {
if(GetFileAttributes("myhj.txt") == INVALID_FILE_ATTRIBUTES){
printf("invalid get last error %d", GetLastError());
}else{
printf("%s", FILE_ATTRIBUTE_DIRECTORY);
}
}
It crashes because %s expects a null-terminated string but the FILE_ATTRIBUTE_* constants are integers instead, so it ends up trying to read a string from an invalid memory address. Use %d instead:
printf("%d", FILE_ATTRIBUTE_DIRECTORY);
GetFileAttributes() returns a DWORD, which is an unsigned int, so use %u for it:
DWORD att = GetFileAttributes("myhj.txt");
if (att == INVALID_FILE_ATTRIBUTES) {
printf("invalid get last error %d", GetLastError());
}
else {
printf("%u", att);
}
To check for specific values, test each bit separately using the bitwise AND operator (&):
DWORD att = GetFileAttributes("file.ext");
if (att == INVALID_FILE_ATTRIBUTES) {
printf("error!\n");
}
else
{
if (att & FILE_ATTRIBUTE_DIRECTORY) printf("directory\n");
if (att & FILE_ATTRIBUTE_HIDDEN) printf("hidden\n");
...
}
If you set the read-only attribute on a file, you cannot perform destructive operations on it...
I have two questions as I'm trying device drivers as a beginner.
I created one module , loaded it, it dynamically took major number 251 say. Number of minor devices is kept 1 only i.e minor number 0. For testing , I tried echo and cat on the device file (created using mknod) and it works as expected. Now if I unload the module but don't remove /dev entry and again load the module with same major number and try writing/reading to same device file which was used previously, kernel crashes. I know we shouldn't do this but just want to understand what happens in this scenario which causes this crash. I think something that VFS does.
When I do cat on device file, the read keeps on happening indefinitely. why? To stop that needed to use offset manipulation. This looks to be because buffer length is coming as 32768 as default to read?
EDIT: further in this I added one ioctl function as below, then I'm getting error regarding the storage class of init and cleanup function, which work well if no ioctl is defined. Not getting the link between ioctl and the init/cleanup functions' storage class. Updated code is posted. Errors are below:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:95:12: error: invalid storage class for function ‘flow_init’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_init’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:98:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: In function ‘flow_ioctl’:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:112:13: error: invalid storage class for function ‘flow_terminate’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: error: invalid storage class for function ‘__inittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:119:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: invalid storage class for function ‘__exittest’
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: warning: ‘alias’ attribute ignored [-Wattributes]
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:120:1: error: expected declaration or statement at end of input
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c: At top level:
/home/diwakar/Documents/my_modules/first_test_module/flowTest.c:73:13: warning: ‘flow_ioctl’ defined but not used [-Wunused-function]
Below is the code:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#define SUCCESS 0
#define BUF_LEN 80
#define FLOWTEST_MAGIC 'f'
#define FLOW_QUERY _IOR(FLOWTEST_MAGIC,1,int)
MODULE_LICENSE("GPL");
int minor_num=0,i;
int num_devices=1;
int fopen=0,counter=0,ioctl_test;
static struct cdev ms_flow_cd;
static char c;
///// Open , close and rest of the things
static int flow_open(struct inode *f_inode, struct file *f_file)
{
printk(KERN_ALERT "flowtest device: OPEN\n");
return SUCCESS;
}
static ssize_t flow_read(struct file *f_file, char __user *buf, size_t
len, loff_t *off)
{
printk(KERN_INFO "flowtest Driver: READ()\nlength len=%d, Offset = %d\n",len,*off);
/* Check to avoid the infinitely printing on screen. Return 1 on first read, and 0 on subsequent read */
if(*off==1)
return 0;
printk(KERN_INFO "Copying...\n");
copy_to_user(buf,&c,1);
printk(KERN_INFO "Copied : %s\n",buf);
*off = *off+1;
return 1; // Return 1 on first read
}
static ssize_t flow_write(struct file *f_file, const char __user *buf,
size_t len, loff_t *off)
{
printk(KERN_INFO "flowtest Driver: WRITE()\n");
if (copy_from_user(&c,buf+len-2,1) != 0)
return -EFAULT;
else
{
printk(KERN_INFO "Length len = %d\n\nLast character written is - %c\n",len,*(buf+len-2));
return len;
}
}
static int flow_close(struct inode *i, struct file *f)
{
printk(KERN_INFO "ms_tty Device: CLOSE()\n");
return 0;
}
///* ioctl commands *///
static long flow_ioctl (struct file *filp,unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case FLOW_QUERY:
ioctl_test=51;
return ioctl_test;
default:
return -ENOTTY;
}
///////////////////File operations structure below/////////////////////////
struct file_operations flow_fops = {
.owner = THIS_MODULE,
.llseek = NULL,
.read = flow_read,
.write = flow_write,
.unlocked_ioctl = flow_ioctl,
.open = flow_open,
.release = flow_close
};
static int flow_init(void)
{
printk(KERN_ALERT "Here with flowTest module ... loading...\n");
int result=0;
dev_t dev=0;
result = alloc_chrdev_region(&dev, minor_num,
num_devices,"mod_flowtest"); // allocate major number dynamically.
i=MAJOR(dev);
printk(KERN_ALERT "Major allocated = %d",i);
cdev_init(&ms_flow_cd,&flow_fops);
cdev_add(&ms_flow_cd,dev,1);
return 0;
}
static void flow_terminate(void)
{
dev_t devno=MKDEV(i,0); // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
printk(KERN_ALERT "Going out... exiting...\n");
unregister_chrdev_region(devno,num_devices); //remove entry from the /proc/devices
}
module_init(flow_init);
module_exit(flow_terminate);
1- You're missing cdev_del() in your cleanup function. Which means the device stays registered, but the functions to handle it are unloaded, thus the crash. Also, cdev_add probably fails on the next load, but you don't know because you're not checking return values.
2- It looks ok... you modify offset, return the correct number of bytes, and then return 0 if offset is 1, which indicates EOF. But you should really check for *off >= 1.
EDIT-
The length passed into your read handler function comes all the way from user-land read(). If the user opens the device file and calls read(fd, buf, 32768);, that just means the user wants to read up to 32768 bytes of data. That length gets passed all the way to your read handler. If you don't have 32768 bytes of data to supply, you supply what you have, and return the length. Now, the user code isn't sure if that's the end of the file or not, so it tries for another 32768 read. You really have no data now, so you return 0, which tells the user code that it has hit EOF, so it stops.
In summary, what you're seeing as some sort of default value at the read handler is just the block size that the utility cat uses to read anything. If you want to see a different number show up at your read function, try using dd instead, since it lets you specify the block size.
dd if=/dev/flowtest of=/dev/null bs=512 count=1
In addition, this should read one block and stop, since you're specifying count=1. If you omit count=1, it will look more like cat, and try to read until EOF.
For 2, make sure you start your module as a char device when using mknod.
mknod /dev/you_device c major_number minor_number