close() system call not removes descriptor from /proc/pid/fdinfo - linux-kernel

Im using fanotify to track disk changes.
fanotify associates file descriptor to my process, which I need to close once Im done dealing with the event.
However, even though the close(fd) is successful, It seems that the file descriptor remains open.
Im using the man fanotify example
The close(..) returns with no errors, but looking at /proc/<pid>/fdinfo tells a different story.
Is there a way to overcome this?
Without clearing the descriptors associated with a process, a read(..) call may encounter read: Too many open files
The error Im receiving is:
EMFILE The per-process limit on the number of open files has been reached. See the description of RLIMIT_NOFILE in getrlimit(2).
I expected to test it with this sample code, but here it works OK:
#include <iostream>
#include <cstdio>
#include <string>
#include <unistd.h>
int main ()
{
close(2);
std::string line; std::getline(std::cin, line);
return 0;
}

Related

redirected stdin ends prematurely Lua for Windows

I'm using Lua in a cmd window under Windows.
I use "cat" (from UnxUtils) to feed a file to a Lua script. The script uses "io.read(1)" to read one byte at a time.
local b, n ;
n = -1 ;
b = true ;
while b do
n = n + 1 ;
b = io.read(1) ;
end ;
print( n, "bytes read" ) ;
When I feed the script a 333K .EXE file, it claims "24025 bytes read".
Feed the same .EXE to "wc" (another UnxUtils), and wc correctly says 333008.
> cat "Firefox Installer.exe" | lua count.lua
24025 bytes read
cat: write error: Invalid argument
> cat "Firefox Installer.exe" | wc
1408 8674 333008
Since I get the expected answer when I "cat | wc", I don't think there's anything wrong with the "cat" program, or with Windows' implementation of redirection.
I am not looking for advice on how to make the Lua script more efficient. I do not need advice on how to make the script read directly from a file (that works as expected). I am looking for a clue as to where to look for the reason I can't use Lua to write a filter (and be able to trust the results).
I have looked at the input file to see if a Ctrl-Z or Ctrl-D was the reason for the early shut-off -- they occur very early in the file.
I tried reading after "io.read()" returned "false": the script admitted to seeing more bytes, but still no more than 45K of the 333K input file.
Copied from my comments:
Likely to be a Windows issue (see e.g. this answer). Windows treats binary and text "streams" / files differently. I would assume that your program's stdin is a text stream by default; it isn't possible to change the mode of stdin to binary later on using plain Lua, you'll need a library for that. Something like lfs = require("lfs"); lfs.setmode(io.stdin, "binary") might work (using the LuaFileSystem library).
You could also try to fix your script invocation to set the correct mode using a script which changes stdin to binary mode before invoking your Lua script:
./stdbin.c:
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
int main(int argc, char** argv) {
if (argc < 1) {
printf("Arguments: <program> {args}\n");
return 1;
}
// See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?redirectedfrom=MSDN&view=msvc-170
if (_setmode(_fileno(stdin), _O_BINARY) == -1)
perror("_setmode failed");
execvp("lua", ++argv);
// execvp only returns if there is an error
perror("execvp failed");
return 1;
}
Note: Untested. Usage: ./stdbin lua count.lua.
(This is an addition to LMD's answer)
In LuaJIT no external libraries and executables are needed:
local ffi = require"ffi"
ffi.cdef"int _setmode(int,int)"
ffi.C._setmode(0, 0x8000)
-- Now io.read() will return binary data

Prevent visual C++ from closing automatically

I have a new project where I created a HelloWorld.cpp Source file.
But when I am running it in Start without dedugging mode (CTRL+ F5), it opens the console and closes automatically.
#include <iostream>
#include<stdlib.h>
#ifdef _WIN32
#define WINPAUSE system("pause")
#endif
using namespace std;
void main()
{
cout << "Hello, World!" ;
}
Mr. Patel, did you try using the second solution on that linked question and then tried to use the run without debugging option? The Visual Studio will only keep the command prompt open if you set the subsystem option in the linker to console. If it is not set, the window will close as soon as the program finishes running.
At any rate, note that this will only work if you run your program from inside Visual Studio, running your .exe directly will still have it close as soon as possible. If you want your program to wait on the user, you would need to do it yourself (at least as far as I know). A very simple solution would be to write your main function like this:
int main (int argc, char* argv[]) {
...//Your code goes here.
std::cout << "Enter any character to end the program.\n";
char end;
std::cin >> end;
return(0);
}
Note that to use the cin and cout streams, you should include the iostream header in your code.

libssh/libssh.h not found on Windows 10 using gcc

I'm trying to use libssh on Windows 10 with gcc. The work is being done from the command line.
I don't know how to make libssh/ part of the search path.
The #include was libssh/libssh.h, but that failed. (The brackets were left out of this sentence.)
#include <libssh.h>
#include <stdlib.h>
int main()
{
ssh_session my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
...
ssh_free(my_ssh_session);
}
When I modify the include statement to be just libssh.h and use the following on the command line:
gcc -IC:\libssh\include\libssh ssh.c -oout.exe
That works to get past the libssh.h file not found.
But, the other files that are called, such as libssh/legacy.h are not found.
How do I get the libssh to be part of the search path?
I added c:\libssh\include\libssh to the environment path. That didn't work.
You need to let #include <libssh/libssh.h>
because libssh.h call a header legacy.h which is also located in the libssh folder so if you put directly the header libssh.h it won't be able to locate legacy.h
#include <libssh/libssh.h>
#include <stdlib.h>
int main()
{
ssh_session my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
// remove the dots it'll create an error
ssh_free(my_ssh_session);
}
to have libssh a part of the path you should do
gcc -I/path/to/libssh/include/directory -L/path/to/libssh/lib/directory -lssh ssh.c oout.exe
I also got stuck into that, now I face another issue, the one to link the libssh.dll or ssh.dll inside the compiled code to use it as stand-alone.

Check if Windows file is redirected to itself

I'm trying to figure out how I can test if a file is being redirected to itself, e.g. .\command.exe file1 > file1
In the *nix world, I'd just use something like this:
// Language agnostic...
if (file_dev == out_dev && file_ino == out_ino) {
printf("%s\n", "same file!");
}
But in Windows, if I try to do this:
// This (language) is Go...
// create fileStat...
// now stat stdout
outStat, err := os.Stdout.Stat()
// error check
if os.SameFile(fileStat, outStat) {
fmt.Println("same file!")
}
...I get the IncorrectFunction error.
I read this (How to check if stdout has been redirected to NUL on Windows (a.k.a. /dev/null on Linux)?) question, and from what I gather you can't stat stdout?
This is a mostly language agnostic question -- I can translate whatever to Go (the language I'm using). I'm mostly concerned about how, using Windows' ABI (API?), I would find where stdout is being redirected to.
This answer is Windows-specific but as you've tagged windows I figure that's ok.
I can't help with Go, but in C/C++ you can do something like this:
#include <tchar.h>
#include <Windows.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t chPath[MAX_PATH];
if (GetFinalPathNameByHandle(GetStdHandle(STD_OUTPUT_HANDLE), chPath, MAX_PATH, 0))
std::wcout << L"stdout = " << chPath << std::endl;
else
std::cout << "stdout not redirected" << std::endl;
return 0;
}
GetFinalPathNameByHandle will fail if stdout is a console handle, but if it's been redirected to a file it will return the file path.
You can call HANDLE GetStdHandle( DWORD stdHandle ) with STD_INPUT_HANDLE and STD_OUTPUT_HANDLE to open the file handle.
Then call DWORD GetFileType( HANDLE hFile ) to check if the returned type is FILE_TYPE_DISK
Finally, call
DWORD WINAPI GetFinalPathNameByHandle( _In_ HANDLE hFile, _Out_ LPTSTR lpszFilePath, _In_ DWORD cchFilePath, _In_ DWORD dwFlags );
to obtain the file pathname and compare the names for equivalency.
Well, first up, I don't think your method in UNIX-land is actually going to protect you.
By the time your code gets to checking devices and inodes, the shell has already truncated the file. It is responsible for processing the output redirections and it does this before your program even starts, so that you're given a fresh file for your output.
I suspect you'd have the same problem in Windows in that cmd.exe will truncate your file before your script even started running.
Having said that, I believe at some point you're going to have to trust that the user knows what they're doing :-)
The other alternative is, of course, not to do output redirection but instead to require the input and output files as arguments:
cmd.exe myscipt myscript
That way, you could detect if the user was going to write to the input file (using canonicalised file names or inodes) and prevent it.
Although that still won't prevent the user from doing something silly like:
cmd.exe myscipt >myscript
blowing away your script before you get a chance to notify them they should have provided two arguments rather than one.
I think the bottom line is, if the user does output redirection, there's no way for your program to catch it before it's too late.

How to get a std::iostream from a file by opening it with share locking on Windows?

I am looking for a simple solution to open a file, probably using CreateFile and being sure that nobody can read/write to it and still being able to obtain a std::iostream object, which is needed later.
I think you can do the following:
#include <iostream>
#include <fstream>
fstream my_stream;
my_stream.open("my.file", std::ios_base::in | std::ios_base::out, _SH_DENYRW);
my_stream << "test";

Resources