I'm trying to check if a file on a jffs2 fs exist from a kernel space. I have a Barrier Breaker OpenWrt with a 3.10.14 Linux kernel. (There's an MTD subsystem in use, so I have pseudo block devices for partitions on a NAND flash (/dev/mtdblock1, ...12).)
(I'm implementing some upgrading logic which requires keeping some state between reboots, to store this state, I use the file.)
To check a file existence I just try to open the file (without an O_CREAT flag) and make a decision based on a result of opening. I use the next article about opening a file from within kernel: Read/write files within a Linux kernel module.
I'm able to check a file existence using this approach, but this file is placed not on a rootfs partition, so I have to mount that partition before I can open the file on it.
I'm able to mount the partition, open file (to check it existence) and close it, if it was opened, but failed to un-mount it: I got an error -16: EBUSY which, as I guess, means that someone else keep using this block device/mount point. So a question who can keep a reference on it?
I think it's a bad idea, but just to test, I tried to un-mount forcibly with an MNT_FORCE, but, as this article https://linux.die.net/man/2/umount states that this option only for NFS fs, nothing changed.
Here's a code:
/* lool at https://stackoverflow.com/questions/1184274/read-write-files-within-a-linux-kernel-module */
static struct file *file_open( const char *path, int flags, int rights )
{
struct file *filp = NULL;
mm_segment_t oldfs;
int err = 0;
oldfs = get_fs();
set_fs( get_ds() );
filp = filp_open( path, flags, rights );
set_fs( oldfs );
if( IS_ERR( filp ) )
{
err = PTR_ERR( filp );
return NULL;
}
return filp;
}
bool need_to_switch_to_me_upgrade_mode( void )
{
struct file* me_upgrade_finished_file;
dev_t me_upgrade_dev;
char full_name[256] = { 0 };
bool result;
int err;
const char* me_upgrade_dir = "/me_upgrade";
const char* me_upgrade_dev_name = "/dev/me_upgrade";
const char* me_upgrade_finished_flag = "/etc/me_upgrade_finished";
// /dev/mtdblock6
const char* me_upgrade_finished_flag_partition = "/dev/mtdblock" str( RECOVERY_ROOTFS_DATA_MTD_PART_NUM );
err = sys_mkdir( (const char __user __force *) me_upgrade_dir, 0700 );
if( err < 0 )
panic( "fail to mkdir %s\n", me_upgrade_dir );
me_upgrade_dev = name_to_dev_t( me_upgrade_finished_flag_partition );
err = create_dev( me_upgrade_dev_name, me_upgrade_dev );
if( err < 0 )
panic( "fail to create_dev %s\n", me_upgrade_dev_name );
err = sys_mount( me_upgrade_dev_name, me_upgrade_dir, "jffs2", MS_SILENT, NULL );
if( err < 0 )
panic( "fail to mount %s on to %s, err: %d\n", me_upgrade_dev_name, me_upgrade_dir, err );
strlcat( full_name, me_upgrade_dir, sizeof( full_name ) );
strlcat( full_name, me_upgrade_finished_flag, sizeof( full_name ) );
me_upgrade_finished_file = file_open( full_name, O_RDONLY, 0 );
if( !me_upgrade_finished_file )
{
printk( "fail to open a %s file\n", full_name );
result = true;
}
else
{
printk( "success to open a file\n" );
result = false;
}
if( me_upgrade_finished_file )
{
err = filp_close( me_upgrade_finished_file, NULL );
printk( "filp_close returned: %d\n", err );
}
err = sys_umount( me_upgrade_dir, MNT_DETACH );
printk( "sys_umount returned: %d\n", err );
sys_unlink( me_upgrade_dev_name ); // destroy_dev( me_upgrade_dev_name );
sys_rmdir( me_upgrade_dir );
return result;
}
This code is called from a kernel_init_freeable function (init/main.c) after we have MTD subsystem initialized (after do_basic_setup() and before a rootfs gets mounted).
So the questions are:
who can keep using a block device/mount point after I closed a file?
is any other ways to check if file exist from within kernel?
I have a second option, just to place my state in a partition without any fs, and check it by performing a raw access to the flash memory, but this approach will require significant changes to user code I have now, so I'm trying to avoid it...
P.S. I tried to change a call to file_open/filp_close by sys_open/sys_close (with the same arguments), but nothing changed...
Related
I try using CreateCopy(), it seem in thrown me an exception when i run the program
Unhandled exception at 0x000007FEDF2C9120 (gdal202.dll) in GdalTest.exe: 0xC0000005: Access violation reading location 0x0000000000000058.
It will display this output on the console:
I try debug on the exception occurs, on the call stack it will go to the new tab then display no symbol loaded
I hope someone can explain to me what file not be loaded and if the console can view raster map it is will throw an error or exception ?
Below is my code if someone want to copy and make reference it just i have issues on "Using CreateCopy()" part.
Thank you and best regards,
// GdalTest.cpp : Defines the entry point for the console application.
//
#include "cpl_conv.h" // for CPLMalloc()
#include "stdafx.h"
#include "gdal.h"
#include <stdlib.h>
#include <stdio.h>
#include "iostream"
#include "cpl_string.h"
#include "gdal_priv.h"
class GDALMajorObject;
class GDALDataset;
class GDALRasterBand;
class GDALDriver;
class GDALRasterAttributeTable;
class GDALProxyDataset;
class GDALProxyRasterBand;
class GDALAsyncReader;
int main(int argc,char* argv)
{
///*/*/*/*/*/*/*/*/*/*Getting Dataset Information*/*/*/*/*/*/*/*/*/*/
GDALDataset *poDataset;
//GDALDatasetH *poDatasetH;
const char* Raster = new char[256];
double adfGeoTransform[6];
GDALAllRegister();
Raster = "C:\\Users\\User\\Desktop\\DSI REFERENCE\\Map Data\\Raster\\4257.tif";
poDataset = (GDALDataset *) GDALOpen(Raster, GA_ReadOnly )CPL_WARN_UNUSED_RESULT;
//poDataset = (GDALDataset *) GDALOpen(Raster, GA_ReadOnly );
if( poDataset == NULL )
{
printf("Not found");
}
else
{
printf( "Driver: %s/%s\n",
poDataset->GetDriver()->GetDescription(),
poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) );
printf( "Size is %dx%dx%d\n",
poDataset->GetRasterXSize(), poDataset->GetRasterYSize(),
poDataset->GetRasterCount() );
if( poDataset->GetProjectionRef() != NULL )
printf( "Projection is `%s'\n", poDataset->GetProjectionRef() );
if( poDataset->GetGeoTransform( adfGeoTransform ) == CE_None )
{
printf( "Origin = (%.6f,%.6f)\n",
adfGeoTransform[0], adfGeoTransform[3] );
printf( "Pixel Size = (%.6f,%.6f)\n",
adfGeoTransform[1], adfGeoTransform[5] );
}
}
///*/*/*/*/*/*/*/*/*/* Fetching a Raster Band*/*/*/*/*/*/*/*/*/*/
GDALRasterBand *poBand;
int nBlockXSize, nBlockYSize;
int bGotMin, bGotMax;
double adfMinMax[2];
poBand = poDataset->GetRasterBand( 1 );
poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
printf( "Block=%dx%d Type=%s, ColorInterp=%s\n", nBlockXSize, nBlockYSize,GDALGetDataTypeName(poBand->GetRasterDataType()),
GDALGetColorInterpretationName( poBand->GetColorInterpretation()) );
adfMinMax[0] = poBand->GetMinimum( &bGotMin );
adfMinMax[1] = poBand->GetMaximum( &bGotMax );
if( ! (bGotMin && bGotMax) )
GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
printf( "Min=%.3fd, Max=%.3f\n", adfMinMax[0], adfMinMax[1] );
if( poBand->GetOverviewCount() > 0 )
printf( "Band has %d overviews.\n", poBand->GetOverviewCount() );
if( poBand->GetColorTable() != NULL )
printf( "Band has a color table with %d entries.\n",
poBand->GetColorTable()->GetColorEntryCount() );
// make it 256 bytes for a string length of 255 plus null (\0) terminator
///*/*/*/*/*/*/*/*/*/*/*Reading Raster Data*/*/*/*/*/*/*/*/*/*/*/
float *pafScanline;
int nXSize = poBand->GetXSize();
pafScanline = (float *) CPLMalloc(sizeof(float)*nXSize);
poBand->RasterIO( GF_Read, 0, 0, nXSize, 1,pafScanline, nXSize, 1, GDT_Float32,0, 0 );
///*/*/*/*/*/*/*/*/*/*/*Techniques for Creating Files (determine whether it supports Create() and/or CreateCopy().) */*/*/*/*/*/*/*/*/*/*/
const char *pszFormat = "GTiff";
GDALDriver *poDriver;
char **papszMetadata;
poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
if( poDriver == NULL )
exit( 1 );
papszMetadata = poDriver->GetMetadata();
if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ) )
printf( "Driver %s supports Create() method.\n", pszFormat );
if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATECOPY, FALSE ) )
printf( "Driver %s supports CreateCopy() method.\n", pszFormat );
///*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*Using CreateCopy()*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
const char*pszDstFilename= new char[256];
GDALDataset *poSrcDS =(GDALDataset *) GDALOpen( pszDstFilename, GA_ReadOnly );
GDALDataset *poDstDS;
poDstDS = poDriver->CreateCopy( pszDstFilename, poSrcDS, FALSE,NULL, NULL, NULL );
/* Once we're done, close properly the dataset */
if( poDstDS != NULL )
GDALClose( (GDALDatasetH) poDstDS );
GDALClose( (GDALDatasetH) poSrcDS );
std::cin.get();
//delete[] Raster;// release the memory VERY IMPORTANT
}
You haven't set the variable pszDstFilename to anything meaningful. You allocated it, but it just contains random junk. You need to put a valid existing dataset into it for anything useful to happen in the call to GDALOpen(). The documentation states:
Once the drivers are registered, the application should call the free standing GDALOpen() function to open a dataset, passing the name of the dataset and the access desired (GA_ReadOnly or GA_Update).
I have manages to use ShellExecute in VC++ in order to launch a document.
Now I wish to run a command-line tool that receives some arguments, and to run in the background (as hidden, not minimized) and let it block my program flow, so that i'll be able to wait for it to finish.
How to i alter the command-line of:
ShellExecute(NULL,"open",FULL_PATH_TO_CMD_LINE_TOOL,ARGUMENTS,NULL,SW_HIDE);
The problem is, I have tool that converts html to pdf, and I wish that once the tool finished, aka pdf is ready, to have another ShellExecute to view it.
There is a CodeProject article that shows how, by using ShellExecuteEx instead of ShellExecute:
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = "c:\\MyProgram.exe";
ShExecInfo.lpParameters = "";
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
CloseHandle(ShExecInfo.hProcess);
The crucial point is the flag SEE_MASK_NOCLOSEPROCESS, which, as MSDN says
Use to indicate that the hProcess member receives the process handle. This handle is typically used to allow an application to find out when a process created with ShellExecuteEx terminates
Also, note that:
The calling application is responsible for closing the handle when it is no longer needed.
You can also use CreateProcess instead of ShellExecute/ShellExecuteEx. This function includes a cmd.exe wrapper option, returning the exit code, and returning stdout. (The includes may not be perfect).
Notes: In my use, I knew that there had to be stdout results, but the PeekedNamePipe function wouldn't always return the bytes count on the first try, hence the loop there. Perhaps, someone can figure this out and post a revision? Also, maybe an alternate version should be produced which returns stderr separately?
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <Shellapi.h>
/*
Note:
The exitCode for a "Cmd Process" is not the exitCode
for a sub process launched from it! That can be retrieved
via the errorlevel variable in the command line like so:
set errorlevel=&[launch command]&echo.&echo exitCode=%errorlevel%&echo.
The stdOut vector will then contain the exitCode on a seperate line
*/
BOOL executeCommandLine( const CStringW &command,
DWORD &exitCode,
const BOOL asCmdProcess=FALSE,
std::vector<CStringW> *stdOutLines=NULL )
{
// Init return values
BOOL bSuccess = FALSE;
exitCode = 0;
if( stdOutLines ) stdOutLines->clear();
// Optionally prepend cmd.exe to command line to execute
CStringW cmdLine( (asCmdProcess ? L"cmd.exe /C " : L"" ) +
command );
// Create a pipe for the redirection of the STDOUT
// of a child process.
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
bSuccess = CreatePipe( &g_hChildStd_OUT_Rd,
&g_hChildStd_OUT_Wr, &saAttr, 0);
if( !bSuccess ) return bSuccess;
bSuccess = SetHandleInformation( g_hChildStd_OUT_Rd,
HANDLE_FLAG_INHERIT, 0 );
if( !bSuccess ) return bSuccess;
// Setup the child process to use the STDOUT redirection
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Execute a synchronous child process & get exit code
bSuccess = CreateProcess( NULL,
cmdLine.GetBuffer(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo ); // receives PROCESS_INFORMATION
if( !bSuccess ) return bSuccess;
WaitForSingleObject( piProcInfo.hProcess, (DWORD)(-1L) );
GetExitCodeProcess( piProcInfo.hProcess, &exitCode );
CloseHandle( piProcInfo.hProcess );
CloseHandle( piProcInfo.hThread );
// Return if the caller is not requesting the stdout results
if( !stdOutLines ) return TRUE;
// Read the data written to the pipe
DWORD bytesInPipe = 0;
while( bytesInPipe==0 ){
bSuccess = PeekNamedPipe( g_hChildStd_OUT_Rd, NULL, 0, NULL,
&bytesInPipe, NULL );
if( !bSuccess ) return bSuccess;
}
if( bytesInPipe == 0 ) return TRUE;
DWORD dwRead;
CHAR *pipeContents = new CHAR[ bytesInPipe ];
bSuccess = ReadFile( g_hChildStd_OUT_Rd, pipeContents,
bytesInPipe, &dwRead, NULL);
if( !bSuccess || dwRead == 0 ) return FALSE;
// Split the data into lines and add them to the return vector
std::stringstream stream( pipeContents );
std::string str;
while( getline( stream, str ) )
stdOutLines->push_back( CStringW( str.c_str() ) );
return TRUE;
}
Using ShellExecuteEx sometimes doesn't work if COM is used, so the following remarks must be considered.
Because ShellExecuteEx can delegate execution to Shell extensions
(data sources, context menu handlers, verb implementations) that are
activated using Component Object Model (COM), COM should be
initialized before ShellExecuteEx is called. Some Shell extensions
require the COM single-threaded apartment (STA) type. In that case,
COM should be initialized as shown here:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)
There are instances where ShellExecuteEx does not use one of these
types of Shell extension and those instances would not require COM to
be initialized at all. Nonetheless, it is good practice to always
initalize COM before using this function.
More from MSDN here
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecuteexa
As I understand it, to reserve a chunk of virtual memory in linux, you call mmap with MAP_ANONYMOUS and MAP_PRIVATE, and the equivalent system call on windows is VirtualAlloc.
However, linux provides mremap to resize a memory mapping, which the man page says
changes the mapping between virtual addresses and memory pages
I cannot find an equivalent system call for windows. It seems that to reallocate memory, it is necessary to use HeapAlloc instead of VirtualAlloc, and then use HeapReAlloc. Regarding HeapReAlloc, msdn says
The process of preserving the memory content involves a memory copy operation that is potentially very time-consuming.
So is there no way of remapping pieces of virtual memory in Windows? If not, why not?
Fine-grained control of virtual memory on Windows may be achieved through the AWE-family of functions in the Win32 API.
Initial allocation is done with AllocateUserPhysicalPages, which, as the name alludes to, allocates actual physical pages for you. You may then proceed to map these physical pages to virtual pages using MapUserPhysicalPages into a virtual address space range that you have previously reserved using VirtualAlloc. Note that you may remap an already mapped physical page to a different virtual page.
This does come with a different set of semantics as you are dealing with both physical and virtual memory at the same time. Among a few of the drawbacks that may be worth mentioning are that you need to ensure that there is no aliasing present; and that you are effectively restricted to using the native page size, i.e. you will not be able to use large pages.
This is a working solution using Address Windowing Extensions (AWE).
The idea is to temporarily map the starting physical pages to the end of the virtual memory. In order to do this, you have to virtually allocate twice the size of the cyclic array.
It is not as convenient as Linux mremap, but it works.
Regarding the MSDN documentation (https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc2), you could also use "placeholders" with VirtualAlloc2, but it is only available on Windows 10 and later.
This solution is based on the MSDN example (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx). Please remember to get the "lock page in memory" privilege for your account in Windows before running it.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define MEMORY_REQUESTED 1024*1024 // request a megabyte
BOOL
LoggedSetLockPagesPrivilege ( HANDLE hProcess,
BOOL bEnable);
BOOL
CyclicMapUserPhysicalPages( void* VirtualAddress,
void* VirtualHeadAddress,
ULONG_PTR NumberOfPages,
ULONG_PTR* PageArray,
DWORD dwPageSize);
void _cdecl main()
{
BOOL bResult; // generic Boolean value
ULONG_PTR NumberOfPages; // number of pages to request
ULONG_PTR NumberOfPagesInitial; // initial number of pages requested
ULONG_PTR *aPFNs; // page info; holds opaque data
PVOID lpMemReserved; // AWE window
SYSTEM_INFO sSysInfo; // useful system information
int PFNArraySize; // memory to request for PFN array
GetSystemInfo(&sSysInfo); // fill the system information structure
_tprintf(_T("This computer has page size %d.\n"), sSysInfo.dwPageSize);
// Calculate the number of pages of memory to request.
NumberOfPages = MEMORY_REQUESTED/sSysInfo.dwPageSize;
_tprintf (_T("Requesting %d pages of memory.\n"), NumberOfPages);
// Calculate the size of the user PFN array.
PFNArraySize = NumberOfPages * sizeof (ULONG_PTR);
_tprintf (_T("Requesting a PFN array of %d bytes.\n"), PFNArraySize);
aPFNs = (ULONG_PTR *) HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
if (aPFNs == NULL)
{
_tprintf (_T("Failed to allocate on heap.\n"));
return;
}
// Enable the privilege.
if( ! LoggedSetLockPagesPrivilege( GetCurrentProcess(), TRUE ) )
{
return;
}
// Allocate the physical memory.
NumberOfPagesInitial = NumberOfPages;
bResult = AllocateUserPhysicalPages( GetCurrentProcess(),
&NumberOfPages,
aPFNs );
if( bResult != TRUE )
{
_tprintf(_T("Cannot allocate physical pages (%u)\n"), GetLastError() );
return;
}
if( NumberOfPagesInitial != NumberOfPages )
{
_tprintf(_T("Allocated only %p pages.\n"), NumberOfPages );
return;
}
// Reserve the virtual memory.
lpMemReserved = VirtualAlloc( NULL,
MEMORY_REQUESTED*2, // NB: Twice the size
MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE );
if( lpMemReserved == NULL )
{
_tprintf(_T("Cannot reserve memory.\n"));
return;
}
// Cyclic Map the physical memory into the window.
void* Head = ((char*)lpMemReserved) + MEMORY_REQUESTED - 6; // Arbitrary Head Address (must be between >= lpMemReserved and <lpMemReserved+MEMORY_REQUESTED)
bResult = CyclicMapUserPhysicalPages( lpMemReserved,
Head,
NumberOfPages,
aPFNs,
sSysInfo.dwPageSize );
if( bResult != TRUE )
{
_tprintf(_T("CyclicMapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
sprintf((char*)Head, "Hello World");
/// unmap Cyclic
bResult = CyclicMapUserPhysicalPages( lpMemReserved,
Head,
NumberOfPages,
NULL,
sSysInfo.dwPageSize );
if( bResult != TRUE )
{
_tprintf(_T("CyclicMapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
// Map the physical memory into the window.
bResult = MapUserPhysicalPages( lpMemReserved,
NumberOfPages,
aPFNs );
if( bResult != TRUE )
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
if (strcmp((char const*)lpMemReserved, "World"))
{
_tprintf(_T("Mem Content Check failed\n") );
return;
}
// unmap
bResult = MapUserPhysicalPages( lpMemReserved,
NumberOfPages,
NULL );
if( bResult != TRUE )
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
// Free the physical pages.
bResult = FreeUserPhysicalPages( GetCurrentProcess(),
&NumberOfPages,
aPFNs );
if( bResult != TRUE )
{
_tprintf(_T("Cannot free physical pages, error %u.\n"), GetLastError());
return;
}
// Free virtual memory.
bResult = VirtualFree( lpMemReserved,
0,
MEM_RELEASE );
// Release the aPFNs array.
bResult = HeapFree(GetProcessHeap(), 0, aPFNs);
if( bResult != TRUE )
{
_tprintf(_T("Call to HeapFree has failed (%u)\n"), GetLastError() );
}
}
/*****************************************************************
LoggedSetLockPagesPrivilege: a function to obtain or
release the privilege of locking physical pages.
Inputs:
HANDLE hProcess: Handle for the process for which the
privilege is needed
BOOL bEnable: Enable (TRUE) or disable?
Return value: TRUE indicates success, FALSE failure.
*****************************************************************/
BOOL
LoggedSetLockPagesPrivilege ( HANDLE hProcess,
BOOL bEnable)
{
struct {
DWORD Count;
LUID_AND_ATTRIBUTES Privilege [1];
} Info;
HANDLE Token;
BOOL Result;
// Open the token.
Result = OpenProcessToken ( hProcess,
TOKEN_ADJUST_PRIVILEGES,
& Token);
if( Result != TRUE )
{
_tprintf( _T("Cannot open process token.\n") );
return FALSE;
}
// Enable or disable?
Info.Count = 1;
if( bEnable )
{
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
Info.Privilege[0].Attributes = 0;
}
// Get the LUID.
Result = LookupPrivilegeValue ( NULL,
SE_LOCK_MEMORY_NAME,
&(Info.Privilege[0].Luid));
if( Result != TRUE )
{
_tprintf( _T("Cannot get privilege for %s.\n"), SE_LOCK_MEMORY_NAME );
return FALSE;
}
// Adjust the privilege.
Result = AdjustTokenPrivileges ( Token, FALSE,
(PTOKEN_PRIVILEGES) &Info,
0, NULL, NULL);
// Check the result.
if( Result != TRUE )
{
_tprintf (_T("Cannot adjust token privileges (%u)\n"), GetLastError() );
return FALSE;
}
else
{
if( GetLastError() != ERROR_SUCCESS )
{
_tprintf (_T("Cannot enable the SE_LOCK_MEMORY_NAME privilege; "));
_tprintf (_T("please check the local policy.\n"));
return FALSE;
}
}
CloseHandle( Token );
return TRUE;
}
/*
--->(tail) (head) ----- ~~~~>
v v
+-------------------------------|-------------------------------+
| virtual memory |
+-------------------------------|-------------------------------+
<--- Memory Requested Size ---->
*/
BOOL CyclicMapUserPhysicalPages(void* VirtualAddress, void* VirtualHeadAddress, ULONG_PTR NumberOfPages, ULONG_PTR* PageArray, DWORD dwPageSize){
ULONG_PTR iStartPage = (ULONG_PTR(VirtualHeadAddress)-ULONG_PTR(VirtualAddress))/dwPageSize;
void* pEnd = ((BYTE*)VirtualAddress)+dwPageSize*iStartPage;
void* pStart = ((BYTE*)VirtualAddress)+dwPageSize*NumberOfPages;
BOOL bResult = MapUserPhysicalPages( pEnd, NumberOfPages-iStartPage, PageArray ? (PageArray+iStartPage) : NULL );
if( !bResult )
return FALSE;
if (iStartPage)
{
bResult = MapUserPhysicalPages( pStart, iStartPage, PageArray );
if( !bResult ){
if (PageArray)
MapUserPhysicalPages( pEnd, NumberOfPages-iStartPage, NULL );
return FALSE;
}
}
return TRUE;
}
You can do it with Address Windowing Extensions (AWE). For example, you can reserve two regions of virtual memory and then map them to the same physical region one after another. Or you can reserve single virtual region but map different segments of it.
It is not as convenient as Linux mremap, but it works.
Check out Address Windowing Extensions (AWE) please:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx
My working code for your reference based on the MSDN example. Please remember to get the "lock page in memory" privilege for your account in Windows before running it.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define MEMORY_REQUESTED 1024*1024 // request a megabyte
BOOL
LoggedSetLockPagesPrivilege(HANDLE hProcess,
BOOL bEnable);
void _cdecl main()
{
BOOL bResult; // generic Boolean value
ULONG_PTR NumberOfPages; // number of pages to request
ULONG_PTR NumberOfPagesInitial; // initial number of pages requested
ULONG_PTR *aPFNs; // page info; holds opaque data
PVOID lpMemReserved; // AWE window
PVOID lpMemReserved2; // AWE window
SYSTEM_INFO sSysInfo; // useful system information
int PFNArraySize; // memory to request for PFN array
GetSystemInfo(&sSysInfo); // fill the system information structure
_tprintf(_T("This computer has page size %d.\n"), sSysInfo.dwPageSize);
// Calculate the number of pages of memory to request.
NumberOfPages = MEMORY_REQUESTED / sSysInfo.dwPageSize;
_tprintf(_T("Requesting %d pages of memory.\n"), NumberOfPages);
// Calculate the size of the user PFN array.
PFNArraySize = NumberOfPages * sizeof(ULONG_PTR);
_tprintf(_T("Requesting a PFN array of %d bytes.\n"), PFNArraySize);
aPFNs = (ULONG_PTR *)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
if (aPFNs == NULL)
{
_tprintf(_T("Failed to allocate on heap.\n"));
return;
}
// Enable the privilege.
if (!LoggedSetLockPagesPrivilege(GetCurrentProcess(), TRUE))
{
return;
}
// Allocate the physical memory.
NumberOfPagesInitial = NumberOfPages;
bResult = AllocateUserPhysicalPages(GetCurrentProcess(),
&NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Cannot allocate physical pages (%u)\n"), GetLastError());
return;
}
if (NumberOfPagesInitial != NumberOfPages)
{
_tprintf(_T("Allocated only %p pages.\n"), (void*)NumberOfPages);
return;
}
// Reserve the virtual memory.
lpMemReserved = VirtualAlloc(NULL,
MEMORY_REQUESTED,
MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE);
if (lpMemReserved == NULL)
{
_tprintf(_T("Cannot reserve memory.\n"));
return;
}
lpMemReserved2 = VirtualAlloc(NULL,
MEMORY_REQUESTED,
MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE);
if (lpMemReserved2 == NULL)
{
_tprintf(_T("Cannot reserve memory.\n"));
return;
}
// Map the physical memory into the window.
bResult = MapUserPhysicalPages(lpMemReserved,
NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError());
return;
}
else {
int* pa = (int*)lpMemReserved;
pa[1] = pa[100] = 0xF0F0;
_tprintf(_T("MapUserPhysicalPages successfully at %p\n"), lpMemReserved);
}
// unmap
bResult = MapUserPhysicalPages(lpMemReserved,
NumberOfPages,
NULL);
if (bResult != TRUE)
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError());
return;
}
//remap
bResult = MapUserPhysicalPages(lpMemReserved2,
NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Re-MapUserPhysicalPages failed (%u)\n"), GetLastError());
return;
}
else {
int* pa = (int*)lpMemReserved2;
if(pa[1] != pa[100] || pa[100] != 0xF0F0)
_tprintf(_T("Re-MapUserPhysicalPages failed (%u)\n"), GetLastError());
_tprintf(_T("Re-MapUserPhysicalPages successfully at %p\n"), lpMemReserved2);
}
// Free the physical pages.
bResult = FreeUserPhysicalPages(GetCurrentProcess(),
&NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Cannot free physical pages, error %u.\n"), GetLastError());
return;
}
// Free virtual memory.
bResult = VirtualFree(lpMemReserved,
0,
MEM_RELEASE);
// Release the aPFNs array.
bResult = HeapFree(GetProcessHeap(), 0, aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Call to HeapFree has failed (%u)\n"), GetLastError());
}
_tprintf(_T("Successfully finished\n"));
}
/*****************************************************************
LoggedSetLockPagesPrivilege: a function to obtain or
release the privilege of locking physical pages.
Inputs:
HANDLE hProcess: Handle for the process for which the
privilege is needed
BOOL bEnable: Enable (TRUE) or disable?
Return value: TRUE indicates success, FALSE failure.
*****************************************************************/
BOOL
LoggedSetLockPagesPrivilege(HANDLE hProcess,
BOOL bEnable)
{
struct {
DWORD Count;
LUID_AND_ATTRIBUTES Privilege[1];
} Info;
HANDLE Token;
BOOL Result;
// Open the token.
Result = OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES,
&Token);
if (Result != TRUE)
{
_tprintf(_T("Cannot open process token.\n"));
return FALSE;
}
// Enable or disable?
Info.Count = 1;
if (bEnable)
{
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
Info.Privilege[0].Attributes = 0;
}
// Get the LUID.
Result = LookupPrivilegeValue(NULL,
SE_LOCK_MEMORY_NAME,
&(Info.Privilege[0].Luid));
if (Result != TRUE)
{
_tprintf(_T("Cannot get privilege for %s.\n"), SE_LOCK_MEMORY_NAME);
return FALSE;
}
// Adjust the privilege.
Result = AdjustTokenPrivileges(Token, FALSE,
(PTOKEN_PRIVILEGES)&Info,
0, NULL, NULL);
// Check the result.
if (Result != TRUE)
{
_tprintf(_T("Cannot adjust token privileges (%u)\n"), GetLastError());
return FALSE;
}
else
{
if (GetLastError() != ERROR_SUCCESS)
{
_tprintf(_T("Cannot enable the SE_LOCK_MEMORY_NAME privilege; "));
_tprintf(_T("please check the local policy.\n"));
return FALSE;
}
}
CloseHandle(Token);
return TRUE;
}
I am creating a pty using openpty in C, and sharing it between master/parent and slave/child. The child could fork/exec and pass on the file descriptor to other programs. I want to inject commands to the child, but if I pass them immediately they get lost. How can I tell from the parent process that someone is blocking on input from stdin? I happen to be working on SUSE 10, but I would prefer a distro independent solution.
Edit : The answer to this question is still interesting to me, but may not be relevant to the problem. I'll get to that later.
A simplified version of the code would be to use the script source code (some of the headers may need to be fixed), and add the lines
char* command = "echo 'Hello World!'\r\n", written = 0;
(void)write(master, command, strlen(command));
(void)write(STDOUT_FILENO, "Sent command\r\n", 14);
before the big
for (;;) {
in main.
I had been executing a csh from script, but I then noticed that the script command was dumping some garbage (as viewed in vi)
^[[>0;115;0c
onto the parent's stdin. If I instead exec a bash shell, nothing gets dumped out and the program injects the command just fine.
I'm still curious as to the answer to the question being asked, but it is clearly no longer relevant to my problem, as there is something else going on. If anyone does know how to see if a pty is being read feel free to answer.
As far as I know, file descriptors will not survive a trip to another process. You can share them between threads, though.
As for knowing when there is something to read, I'd try using select with the appropriate file descriptor in the read set.
I have noticed same problem about losting stuff when I write to master fd.
Problem can be avoided by using the slave fd for writing. And the master fd for stdin of child.
This way:
int main(void)
{
int master_fd = -1;
int slave_fd = -1;
if( openpty( &master_fd, &slave_fd, NULL, NULL, NULL ) != -1 )
{
const pid_t child_pid = fork();
if( child_pid != -1 )
{
if( child_pid )
{
const char command[] = "command\n";
close( master_fd );
write( slave_fd, command, strlen(command) );
close( slave_fd );
}
else
{
close( slave_fd );
dup2( master_fd, STDIN_FILENO );
execlp( "/bin/cat", "cat", (char*)0 );
}
}
}
return 0;
}
You may even add delays to child process and it still works.
So parent process can exit before the child process do anything:
~ # temp_test
~ # command
cat: read error: Input/output error
~ #
EDIT:
Little bit different example, because error print out of cat causes confusing:
if( child_pid )
{
const char command[] = "command\n";
close( master_fd );
write( slave_fd, command, sizeof(command) );
close( slave_fd );
}
else
{
char buffer[100];
ssize_t i;
ssize_t len;
close( slave_fd );
do
{
len = read( master_fd, buffer, sizeof(buffer) );
for( i = 0; i < len; i++ )
printf("%c", buffer[i] );
} while( len > 0 );
}
And result:
~ # temp_test
command
~ #
i am creating a bluetooth based server program in Bluez which basically handles connections from multiple devices. I have constructed two threads; one to scan the remote devices and another to connect with the devices that are broadcasting the service. Again, a separate thread is extracted from a thread pool for each of the newly connected devices which will then communicate with the server over a RFCOMM channel.
After establishing connection with a remote device, the server will send commands to the remote bluetooth device. Once the remote device a reply, the server reads that reply and stores it.
Now, the problem is whenever I get a reply back from the device the program crashes stating a "segmentation fault". Can anyone tell me a possible cause for this. The part of the code that does this is given here.
void startCommunication( int newSocket )
{
char buf[MODZ_MAX_DATA_SIZE] = "\0";
char previousData[ MODZ_MAX_DATA_SIZE ] = "\0";
time_t recvTime, prevRecvTime;
char dataToBeSent[ 4*MODZ_MAX_DATA_SIZE ] = "\0";
char *result;
if( sendDataToClient( newSocket, CMD_SEND) == EXT_ERROR ) //send acknowledgement first
printf("Couldn;t send ack\n");
else { printf("Date send woot! woot! %s\n", CMD_SEND); }
memset( buf, '0', sizeof(buf) );
while( 1 ){
recvTime = time( ( time_t * )0 );
if( readDataFromClient( newSocket, buf ) == EXT_ERROR ){
printf( "Read Error\n" );
break;
}
printf( "Data received = %s\n", buf );
strcpy( previousData, buf );
// store the data in a file and send to web
// check if the web has any data to send and if there is then send
result = "here we update the challenge";
strcpy( dataToBeSent, result );
free( result );
result = NULL;
//strcpy( buf, "We will soon update the database" );
if( sendDataToClient( newSocket, dataToBeSent ) == EXT_ERROR ){
break;
}
}
close( newSocket );
if( result != NULL ){
free( result );
}
printf( "\n****************Device disconnected***************\n" );
}
One obvious problem:
result = "here we update the challenge";
strcpy( dataToBeSent, result );
free( result );
You are freeing a pointer that was not allocated with malloc. That could well cause a segmentation fault.
In the future, try to use gdb to figure out exactly where your program crashes.