Let's say I have a module which has this function my_open:
int my_open( struct inode *inode, struct file *filp ) {
filp->private_data = //allocate private data
if( filp->f_mode & FMODE_READ )
//handle read opening
if( filp->f_mode & FMODE_WRITE )
//handle write opening
if (MINOR( inode->i_rdev )==2){
filp->f_op = &my_fops2;
}
return 0;
}
how do I use this function from the shell/terminal?
This is either the open function for a device driver,
or it’s a sheep in wolf’s clothing [sic].
In the unlikely event that this is ordinary, vanilla user-level code,
compile it into an executable and use that. But if it is a device driver’s open function,
First of all,
determine whether it is compiled/linked into the currently running kernel.
If it isn’t, make it so (compile/link it into the kernel, and reboot).
Alternatively,
you may have the ability to load it into the kernel dynamically.
Exactly how to do that depends on your particular operating system
and is out of scope for this question.
Find out whether it is a block device or a character device,
and what its major device number is.
I can’t tell you specifically how to do that, either;
consult your local resources.
OK, let’s suppose that it is a character device with major number 42.
Look through /dev (with ls -l) for entries that begin with c
(for “character”) and contain 42, something
where the size should be, like this:
drwxr-xr-x 1 root root 512 Feb 10 2015 .
drwxr-xr-x 1 root root 1024 Feb 10 2015 ..
crw-rw-rw- 1 root root 42, 0 Aug 15 18:31 foo
crw-rw-rw- 1 root root 42, 2 Aug 15 18:31 fu
crw-rw-rw- 1 root root 42, 17 Aug 15 18:31 fubar
If you can’t find any, create some. See man mknod for details.
You should probably create one with minor device number 2
and at least one with a different number
(because the code treats 2 as a special case).
Do to the /dev/whatever files whatever you want to,
based on the intended function of the driver.
(Determining the intended function of the driver is out of scope.)
For instance, you might try things like
od -cb /dev/foo
echo "Hello, world." > /dev/fu
Naturally, if it’s a block device,
replace c in the above instructions with b.
Related
I was looking into the IO path of the Linux kernel, and towards the bottom in the function scsi_dispatch_cmd(), the driver code is invoked
rtn = host->hostt->queuecommand(host, cmd);
So, for my block device like /dev/sda/, is there a way to find out which hostt or scsi_host_template it is using. I want to check which function queuecommand is pointing to..
Just as a sketch of reflection on this subject.
In my machine for USB drive I can see this:
$ ls -l /dev/sdg
brw-rw---- 1 root disk 8, 96 Apr 27 01:21 /dev/sdg
$ ll /sys/dev/block/8\:96/device/drive
lrwxrwxrwx 1 root root 0 Apr 27 01:32 /sys/dev/block/8:96/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
So normally such block devices are handled through the regular Linux scsi disk driver. Which is related with e.g. usb handling:
$ lsmod | grep sd
sd_mod 49152 13
scsi_mod 225280 5 sd_mod,usb_storage,libata,uas,sg
In this particular case we can see the relation between queuecommand and mentioned drive:
$ grep queuecommand /proc/kallsyms
ffffffffc052be60 t uas_queuecommand [uas]
ffffffffc0582ad0 t queuecommand [usb_storage]
Now, being in Linux source dir:
$ grep -rnI '\.queuecommand =' | grep usb
drivers/usb/storage/uas.c:846: .queuecommand = uas_queuecommand,
drivers/usb/storage/scsiglue.c:609: .queuecommand = queuecommand,
Hope this will help you.
I am trying to debug a C program using GDB. But when I try to run it from inside gdb I get the following error :
note: the FATAL error line is user defined
gdb-peda$ run
Starting program: /home/masterdungeon/HTAOEBookPrograms/0x200/0x280/0x287/GameOfChance
**************** WELCOME to the GAME OF CHANCE *****************
This game will essentially tell you how lucky you are today ;)
---- New player ----
Please enter your name : user_gdb
[!!!] Fatal Error in register_user() while opening DATAFILE
: Permission denied
[Inferior 1 (process 10636) exited with code 0377]
Warning: not running
gdb-peda$
This program is actually a command line game named "GameOfChance" (from the book HTAOE). Whenever a user runs the program, the program first checks its UserID to see whether the user is already registered as a player in the DATAFILE. If there is no entry of that UID in the DATAFILE(i.e player not registered already), then the program allows to create a new player and accept a username, thus registering as a player with that UID and accepted username. But I think GDB does not have a UID since there is no entry of gdb in /etc/passwd. How do I make the program run while debugging and register GDB as a new player? Is it even possible ?
The code looks like this :
12 #define DATAFILE "/var/gameofchance.data" // File to store user data
46 int main(){
//lines of code
53 uid = getuid(); // get current user_id i.e player_id
54 player_exists = get_player_data(uid); // returns -1 if player does not exist
55 //otherwise returns 0 and puts all player data into struct player
56
57 if(player_exists == -1) {
58 register_player(uid);
59 }
//lines of code
148 return 0;
149 } //end main()
314 void register_player(int uid){
//lines of code
327 fd = open(DATAFILE, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
329
330 if(fd==-1){
331 fatal(" in register_user() while opening DATAFILE\n");
332 }
//lines of code
344 } //end register_player
the permissions for DATAFILE are :
-rw------- 1 root masterdungeon 240 Apr 19 13:54 gameofchance.data
the permissions for executable game GameOfChance are :
-rwsrwxr-x 1 root root 29064 Jan 4 19:45 GameOfChance
Another thing I couldn't understand is when I set a breakpoint at line 54 and check for value of uid I get 1000 as UID of GDB.
Breakpoint 16, main () at gameofchance.c:54
54 player_exists = get_player_data(uid); // returns -1 if player does not exist
gdb-peda$ x/wd &uid
0x7ffd4ed4aee8: 1000
How's it possible that GDB has userid of 1000 ? as there is no entry of gdb in /etc/passwd. 1000 is userid of masterdungeon.
Okay so it works when gdb is run using sudo gdb. But why do I have to run it as root to get it run nicely in GDB ?
Otherwise in BASH the program runs successfully as user masterdungeon. Only in GDB it require to be run as root
Does GDB have a userid?
Yes. Every process that runs, including GDB processes, has both an effective UID and a real UID. Often these are the same. But you seem to have a misunderstanding. These do not describe the process itself. Rather they describe the user on whose behalf the process is running.
How's it possible that GDB has userid of 1000 ? as there is no entry of gdb in /etc/passwd. 1000 is userid of masterdungeon.
Because you're running gdb as user "masterdungeon", or as another user with the same UID number.
Okay so it works when gdb is run using sudo gdb. But why do I have to run it as root to get it run nicely in GDB ?
Your data file is accessible only to root:
-rw------- 1 root masterdungeon 240 Apr 19 13:54 gameofchance.data
. When run directly, the program accommodates that by being root-owned and having its SUID bit set:
-rwsrwxr-x 1 root root 29064 Jan 4 19:45 GameOfChance
(note the "s" in the first triad of permission bits). That causes the program, when run directly, to run with the effective UID of root, even though root did not actually launch it. This is one of the cases where the effective and real UIDs differ. It is also a very poor use case for SUID, because SUID root programs present an existential security risk to the host system, and that risk is not justified for a game.
The risk would be much worse if the SUID bit were honored when the program is running under control of a debugger. A debugger can make arbitrary changes to program data and even binary code while the program is running, and that would present an easy vector for privilege escalation if SUID were honored in such contexts. Accordingly, the SUID bit on an executable has no effect when the program is run in a debugger. (See also Can gdb debug suid root programs?)
Thus, if you debug the program as a user other than root, it will not be able to open the data file, but if you use sudo to run the debugger then you obtain the needed privelege to access the data file through sudo, and the fact that the SUID bit on the executable is not honored is irrelevant.
The best way to debug the program is in its build environment, before installation, such that it is owned by you and does not need (or have) its SUID bit set. This may require some manipulation of where or how it looks for its data file, which should also be owned by you.
As for how the program is installed, you have a tension between priorities:
Programs available for all users to run should be owned by root and writable only by root, to make it difficult for other users to modify them or substitute different program for them, both of which could lead to data breach and (further) privilege escalation.
You apparently require that users running the game program be able to write to a shared data file. It's unclear what this file contains, but a shared high score list might be an example.
But you do not (presumably) want to allow users to manipulate the data file arbitrarily, under their own authority, lest they cheat in some way, or worse.
The easiest approach would be to give each user their own, unshared data file, created at need by the program within the user's home directory, and accessible to that user. Then you don't need to mess with SUID / SGID, nor do you need to have any concern about users interfering with each other. Sure, they may be able to cheat, but it will affect only them. And you will be able to debug the program with GDB.
If it is essential that the data file be both shared among program users and writable (via the program) to all of them, then a better approach than making the program SUID-root would be to make it SGID-some_group_not_root, and make the data file writable by that group. Better still, avoid the SGID bit, and just require users to be members of the chosen group in order to use the program. Do note that SGID is not honored when debugging, either.
The problem incident:
Our production system started denying services with an error message "Too many open files in system". Most of the services were affected, including inability to start a new ssh session, or even log in into virtual console from the physical terminal. Luckily, one root ssh session was open, so we could interact with the system (morale: keep one root session always open!). As a side effect, some services (named, dbus-daemon, rsyslogd, avahi-daemon) saturated the CPU (100% load). The system also serves a large directory via NFS to a very busy client which was backing up 50000 small files at the moment. Restarting all kinds of services and programs normalized their CPU behavior, but did not solve the "Too many open files in system" problem.
The suspected cause
Most likely, some program is leaking file handles. Probably the culprit is my tcl program, which also saturated the CPU (not normal). However, killing it did not help, but, most disturbingly, lsof would not reveal large amounts of open files.
Some evidence
We had to reboot, so whatever information was collected is all we have.
root#xeon:~# cat /proc/sys/fs/file-max
205900
root#xeon:~# lsof
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 8,6 4096 2 /
init 1 root rtd DIR 8,6 4096 2 /
init 1 root txt REG 8,6 124704 7979050 /sbin/init
init 1 root mem REG 8,6 42580 5357606 /lib/i386-linux-gnu/libnss_files-2.13.so
init 1 root mem REG 8,6 243400 5357572 /lib/i386-linux-gnu/libdbus-1.so.3.5.4
...
A pretty normal list, definitely not 200K files, more like two hundred.
This is probably, where the problem started:
less /var/log/syslog
Mar 27 06:54:01 xeon CRON[16084]: (CRON) error (grandchild #16090 failed with exit status 1)
Mar 27 06:54:21 xeon kernel: [8848865.426732] VFS: file-max limit 205900 reached
Mar 27 06:54:29 xeon postfix/master[1435]: warning: master_wakeup_timer_event: service pickup(public/pickup): Too many open files in system
Mar 27 06:54:29 xeon kernel: [8848873.611491] VFS: file-max limit 205900 reached
Mar 27 06:54:32 xeon kernel: [8848876.293525] VFS: file-max limit 205900 reached
netstat did not show noticeable anomalies either.
The man pages for ps and top do not indicate an ability to show open file count. Probably the problem will repeat itself after a few months (that was our uptime).
Any ideas on what else can be done to identify the open files?
UPDATE
This question has changed the meaning, after qehgt identified the likely cause.
Apart from the bug in NFS v4 code, I suspect there is a design limitation in Linux and kernel-leaked file handles can NOT be identified. Consequently, the original question transforms into:
"Who is responsible for file handles in the Linux kernel?" and "Where do I post that question?". The 1st answer was helpful, but I am willing to accept a better answer.
Probably the root cause is a bug in NFSv4 implementation: https://stackoverflow.com/a/5205459/280758
They have similar symptoms.
I want to be able to tell when my program's stdout is redirected to a file/device, and when it is left to print normally on the screen. How can this be done in C?
Update 1: From the comments, it seems to be system dependent. If so, then how can this be done with posix-compliant systems?
Perhaps isatty(stdout)?
Edit: As Roland and tripleee suggest, a better answer would be isatty(STDOUT_FILENO).
Look up isatty and more generally fileno.
I am afraid that you can't, at least with standard C in a platform independent manner. The idea behind standard input/output is that C will do it's IO from a standard place. That standard place could be a terminal or a file or anything else, that is not the consideration of C. So you can't detect what is standard IO currently used.
EDIT: If a platform specific solution is okay for you then please refer to other answers (and also edit the question accordingly).
If a Linux-specific solution is OK, you can examine the symlinks under the /proc directory for your process. E.g.,
$ exec 3>/dev/null
$ ls -l /proc/$$/fd
total 0
lrwx------ 1 root root 64 Sep 12 03:28 0 -> /dev/pts/1
lrwx------ 1 root root 64 Sep 12 03:29 1 -> /dev/pts/1
lrwx------ 1 root root 64 Sep 12 03:29 2 -> /dev/pts/1
lrwx------ 1 root root 64 Sep 12 03:29 255 -> /dev/pts/1
l-wx------ 1 root root 64 Sep 12 03:29 3 -> /dev/null
You might want to check this out:
http://www.cplusplus.com/reference/clibrary/cstdio/freopen/
I'm quoting from the link:
freopen
Reopen stream with different file or mode
freopen first tries to close any file already associated with the stream given as third parameter and disassociates it.
Then, whether that stream was successfuly closed or not, freopen opens the file whose name is passed in the first parameter, filename, and associates it with the specified stream just as fopen would do using the mode value specified as the second parameter.
This function is specially useful for redirecting predefined streams like stdin, stdout and stderr to specific files.
Though I'm not sure if this'll help you find out what it is pointing to in the first place.
I'm trying to use a somewhat old DAQ, and had to jump through a few hoops to get an old (circa 2004) device driver for it to compile (DTI-DT340 Linux-DAQ-PCI).
I've gotten to the point where it compiles, I can load the kernel module, it finds the card, and I can create the character devices using mknod.
But I can't seem to open these devices and keep getting errno 19 (ENODEV) 'No such device' when I try to
open("/dev/dt340/0",O_RDWR);
but mknod had no complaints about making it, and it's there:
# ls -l /dev/dt340/
total 0
crw-rw-r-- 1 root staff 250, 0 2009-04-23 11:02 0
crw-rw-r-- 1 root staff 250, 1 2009-04-23 11:02 1
crw-rw-r-- 1 root staff 250, 2 2009-04-23 11:02 2
crw-rw-r-- 1 root staff 250, 3 2009-04-23 11:02 3
Is there something I'm neglecting to do? What might be a reason open fails?
Here's the script I use to load the driver and make the devices.
#!/bin/bash
module="dt340"
device="dt340"
mode="664"
# invoke modprobe with all arguments we were passed
#/sbin/modprobe -t misc -lroot -f -s $module.o $* || exit 1
insmod $module.ko
# remove stale nodes
rm -f /dev/${device}/[0-3]
major=`awk "\\$2==\"$module\" {print \\$1}" /proc/devices`
mkdir -p /dev/${device}
mknod /dev/${device}/0 c $major 0
mknod /dev/${device}/1 c $major 1
mknod /dev/${device}/2 c $major 2
mknod /dev/${device}/3 c $major 3
# give appropriate group/permissions, and change the group
# not all distributions have staff; some have "users" instead
group="staff"
grep '^staff:' /etc/group > /dev/null || group="users"
chgrp $group /dev/${device}/[0-3]
chmod $mode /dev/${device}/[0-3]
Some additional info:
#grep dt340 /proc/devices
250 dt340
# lsmod | grep dt340
dt340 21516 0
# tail /var/log/messages
Apr 23 11:59:26 ve kernel: [ 412.862139] dt340 0000:03:01.0: PCI INT A -> GSI 22 (level, low) -> IRQ 22
Apr 23 11:59:26 ve kernel: [ 412.862362] dt340: In function dt340_init_one:
Apr 23 11:59:26 ve kernel: [ 412.862363] Device DT340 Rev 0x0 detected at address 0xfebf0000
#lspci | grep 340
03:01.0 Multimedia controller: Data Translation DT340
ANSWER: A printk confirmed that the -ENODEV was thrown from inside open(). Following an oldstyle
while ((pdev = pci_find_device(PCI_VENDOR_ID_DTI, PCI_ANY_ID, pdev)))
(which is deprecated), if(!pdev) ends up true, and returns the -ENODEV.
I'm inching closer - I guess I have to work through and update the pci code to use more modern mechanisms...
If the device shows up in /proc/devices, and you're sure you've got the number right in mknod, then the driver itself is refusing the open. The driver can return any error code from open() - including "no such device", which it might if it discovered a problem initialising the hardware.
I'd guess it is a problem in the driver, check the open function.
It shows up in /proc/devices, so all the generic device stuff seems to be ok.
mknod doesn't care if there is an device corresponding to the given major/minor numbers. Are you sure insmod is installing your module? What does lsmod tell you?
I'm unfamiliar with having to add the ".ko" extension. Is that something specific to your device driver?
Check through lspci and make sure hardware is properly initialized. If your system supports hotplug, pci_find_device won't work. The problem with this is a refcnt. The best way to deal and learn is to dissect the API. BOL !!