output not displaying after piping with fork and exec - c++11

I am trying to create a function which runs one command and then pipes the output to a second command and runs that. I'm running the function in an infinite loop. The problem is, the function works the first time, but doesn't show anything after that.
For example, when I run ls | wc -l, the first time it shows the correct results, but when I run it after that I get no output.
Here is my function (parsing is handled in another function):
void system_pipe(std::string command1, std::string command2)
{
int status;
int fd[2];
int fd2[2];
pipe(fd);
int pid = fork();
// Child process.
if (pid == 0)
{
std::shared_ptr<char> temp = string_to_char(command1);
char *name[] = {"/bin/bash", "-c", temp.get(), NULL};
close(fd[0]);
dup2(fd[1], 1);
execvp(name[0], name);
exit(EXIT_FAILURE);
}
// Parent process.
else
{
std::shared_ptr<char> temp = string_to_char(command2);
char *name[] = {"/bin/bash", "-c", temp.get(), NULL};
close(fd[1]);
dup2(fd[0], 0);
waitpid(pid, &status, 0);
//my_system(command2);
// Fork and exec a new process here.
int pid2 = fork();
if (pid2 == 0)
{
execvp(name[0], name);
exit(EXIT_FAILURE);
}
else
{
waitpid(pid2, NULL, 0);
}
}
if (status)
std::cout << "Bad" << std::endl;
}
I call the function like this:
while(true)
{
string line;
getline(cin, line);
pair<string, string> commands = parse(line);
system_pipe(commands.first, commands.second);
}
Why is the function only working correctly on the first loop? What is changing after that?

else
{
std::shared_ptr<char> temp = string_to_char(command2);
char *name[] = {"/bin/bash", "-c", temp.get(), NULL};
close(fd[1]);
dup2(fd[0], 0);
waitpid(pid, &status, 0);
//my_system(command2);
That was not your intention, I believe. dup2 had to be called in child.
int pid2 = fork();
if (pid2 == 0)
{
dup2(fd[0], 0); // here.
execvp(name[0], name);
exit(EXIT_FAILURE);
}
The second problem is that you leave your pipe files open.
This is not a good coding sample, but it's only to illustrate how it should work.
// ( g++ -std=c++11 )
// type `ls | grep file.cxx`
#include <iostream>
#include <string>
#include <cstring>
#include <array>
#include <memory>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void replace_with ( std::string command )
{
char exec_name [] = "bash" , arg [] = "-c" ;
char * line [] = { exec_name , arg , &command[ 0 ] , nullptr } ;
execvp( exec_name , line ) ;
}
void pipeline ( const std::string& command0 , const std::string& command1 )
{
std::array< int , 2 > pipe_fd ; enum { READ_END , WRITE_END } ;
if ( pipe( pipe_fd.data() ) ) throw std::runtime_error( "can't create a pipe" ) ;
int id = fork() ;
if ( id < 0 ) { for ( auto each : pipe_fd ) close( each ) ;
throw std::runtime_error( "can't create a child" ) ; }
if ( ! id ) /* child */
{
close( pipe_fd[ READ_END ] ) ;
dup2( pipe_fd[ WRITE_END ] , STDOUT_FILENO ) ;
close( pipe_fd[ WRITE_END ] ) ; //
replace_with( command0 ) ;
}
else /* parent */
{
close( pipe_fd[ WRITE_END ] ) ;
waitpid( id , nullptr , 0 ) ;
int id_second = fork () ;
if ( id_second > 0 ) waitpid( id_second , nullptr , 0 ) ;
else if ( ! id_second ) /* child */
{
dup2( pipe_fd[ READ_END ] , STDIN_FILENO ) ;
close( pipe_fd[ READ_END ] ) ; //
replace_with( command1 ) ;
}
close( pipe_fd[ READ_END ] ) ;
}
}
int main () try
{
while ( true )
{
std::string command0 , command1 ;
getline( std::cin , command0 , '|' ) ;
getline( std::cin , command1 ) ;
pipeline( command0 , command1 ) ;
}
} catch ( const std::runtime_error& e )
{ std::cerr << e.what() ; return - 1 ; }

Related

How find the disk sector size of a drive that's on a UNC-path

I've got the following code to get the drive sector size of a local or mapped drive:
#include <Windows.h>
#include <stdexcept>
#include <sstream>
#include <string>
#include "xhandle.h"
#include "DiskSectorSize.h"
DiskSectorSize getDiskSectorSize( char const *filename )
{
using namespace std;
DWORD dwFfnLength;
if( (dwFfnLength = GetFullPathNameA( filename, 0, nullptr, nullptr )) == 0 )
throw system_error( error_code( (int)GetLastError(), system_category() ),
(stringstream() << "can't get full path for path \"" << filename << "\"").str().c_str() );
string fullFileName( (size_t)dwFfnLength, 0 );
if( GetFullPathNameA( filename, dwFfnLength, &fullFileName[0], nullptr ) == 0 )
throw system_error( error_code( (int)GetLastError(), system_category() ),
(stringstream() << "can't get full path for path" << filename).str().c_str() );
if( dwFfnLength < 2 || toupper( fullFileName[0] ) < 'A' || toupper( fullFileName[0] ) > 'Z' || fullFileName[1] != ':' )
throw exception( "no drive letter in absolute path" );
string logicalDrive = "\\\\.\\ ";
logicalDrive.replace( logicalDrive.begin() + 4, logicalDrive.begin() + 6, fullFileName.begin(), fullFileName.begin() + 2 );
XHANDLE xhDevice( CreateFileA( logicalDrive.c_str(), 0, 0, NULL, OPEN_EXISTING, 0, NULL ), true,
"can't create device handle for disk" );
DWORD dwOutSize;
STORAGE_PROPERTY_QUERY spq;
memset( &spq, 0, sizeof spq);
spq.PropertyId = StorageAccessAlignmentProperty;
spq.QueryType = PropertyStandardQuery;
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR saad;
memset( &saad, 0, sizeof saad );
if( !DeviceIoControl( xhDevice, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof spq, &saad, sizeof saad, &dwOutSize, NULL ) ||
dwOutSize != sizeof saad )
throw system_error( error_code( (int)GetLastError(), system_category() ),
(stringstream() << "can't detemine disk sector size for device" << fullFileName).str().c_str() );
DiskSectorSize dss;
dss.dwPhysical = saad.BytesPerPhysicalSector;
dss.dwLogical = saad.BytesPerLogicalSector;
return dss;
}
But I can't get the disk sector size of a UNC-file with at. When I wrote the above code I also found a way to do that. But today I can't remember it exactly.

show location of biggest memory leak on Windows

My program has big leaks. I am using the debug heap by putting this in my stdafx.h:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
Then I'm capturing all the leaks in a text file by putting this code just before exit:
HANDLE hLogFile;
hLogFile = CreateFile( "T:\\MyProject\\heap.txt", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, hLogFile);
_CrtDumpMemoryLeaks();
exit( EXIT_SUCCESS );
However even then the data is leak by leak, which is far too low-level information.
Stepping into _CrtDumpMemoryLeaks(), the code is actually easy to follow. I wrote my own function that summarizes the data, reporting bytes leaked for each line of code and sorting by leak size.
However it requires a static variable inside dbgheap.c in order to work. I've tried to make a version of dbgheap.c that doesn't have these as static symbols and tried to make a mini-DLL out of it (but it complains about a missing symbol I can't find anywhere in the MSFT code, _heap_regions). Instead what I've settled on is putting this code right before the code above calling _CrtDumpMemoryLeaks():
// Put a breakpoint here; step INTO the malloc, then in variable watch
// window evaluate: _CrtDumpMemoryLeakSummary( _pFirstBlock );
void* pvAccess = malloc(1);
And in turn this is the code for the _CrtDumpMemoryLeakSummary function:
#define _CRTBLD
#include "C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\src\dbgint.h"
typedef struct {
const char* pszFileName;
int iLine;
int iTotal;
} Location_T;
#define MAX_SUMMARY 5000
static Location_T aloc[ MAX_SUMMARY ];
static int CompareFn( const void* pv1, const void* pv2 ) {
Location_T* ploc1 = (Location_T*) pv1;
Location_T* ploc2 = (Location_T*) pv2;
if ( ploc1->iTotal > ploc2->iTotal )
return -1;
if ( ploc1->iTotal < ploc2->iTotal )
return 1;
return 0;
}
void _CrtDumpMemoryLeakSummary( _CrtMemBlockHeader* pHead )
{
int iLocUsed = 0, iUnbucketed = 0, i;
for ( /*pHead = _pFirstBlock */;
pHead != NULL && /* pHead != _pLastBlock && */ iLocUsed < MAX_SUMMARY;
pHead = pHead->pBlockHeaderNext ) {
const char* pszFileName = pHead->szFileName ? pHead->szFileName : "<UNKNOWN>";
// Linear search is theoretically horribly slow but saves trouble of
// avoiding heap use while measuring heap use.
int i;
for ( i = 0; i < iLocUsed; i++ ) {
// To speed search, compare line number (fast) before strcmp() (slow).
// If szFileName were guaranteed to be __LINE__ then we could take advantage
// of __LINE__ always having the same address for any given file, and just
// compare pointers rather than using strcmp(). However, szFileName could
// be something else.
if ( pHead->nLine == aloc[i].iLine &&
strcmp( pszFileName, aloc[i].pszFileName ) == 0 ) {
aloc[i].iTotal += pHead->nDataSize;
break;
}
}
if ( i == iLocUsed ) {
aloc[i].pszFileName = pszFileName;
aloc[i].iLine = pHead->nLine;
aloc[i].iTotal = pHead->nDataSize;
iLocUsed++;
}
}
if ( iLocUsed == MAX_SUMMARY )
_RPT0( _CRT_WARN, "\n\n\nARNING: RAN OUT OF BUCKETS! DATA INCOMPLETE!!!\n\n\n" );
qsort( aloc, iLocUsed, sizeof( Location_T ), CompareFn );
_RPT0(_CRT_WARN, "SUMMARY OF LEAKS\n" );
_RPT0(_CRT_WARN, "\n" );
_RPT0(_CRT_WARN, "bytes leaked code location\n" );
_RPT0(_CRT_WARN, "------------ -------------\n" );
for ( i = 0; i < iLocUsed; i++ )
_RPT3(_CRT_WARN, "%12d %s:%d\n", aloc[i].iTotal, aloc[i].pszFileName, aloc[i].iLine );
}
It produces output like this:
SUMMARY OF LEAKS
bytes leaked code location
------------ -------------
912997 <UNKNOWN>:0
377800 ..\MyProject\foo.h:205
358400 ..\MyProject\A.cpp:959
333672 ..\MyProject\B.cpp:359
8192 f:\dd\vctools\crt_bld\self_x86\crt\src\_getbuf.c:58
6144 ..\MyProject\Interpreter.cpp:196
4608 ..\MyProject\Interpreter.cpp:254
3634 f:\dd\vctools\crt_bld\self_x86\crt\src\stdenvp.c:126
2960 ..\MyProject\C.cpp:947
2089 ..\MyProject\D.cpp:1031
2048 f:\dd\vctools\crt_bld\self_x86\crt\src\ioinit.c:136
2048 f:\dd\vctools\crt_bld\self_x86\crt\src\_file.c:133

Building simple unix shell problems

I am new with unix and I've got an assignemnt on college to build a simple shell in c with built in cd and kill command..
This is my code which is not working..tbh I dont understand it the best so Im not suprised it is not working.. can you help me with it? Also have no idea how I would implement kill command. thank you!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '\0')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
You were on the right track. There were a few subtle issues where you were not accounting for the trailing '\n' that would remain in line as the last character following whatever was entered at the prompt. Including " \n" in the delimiters used to tokenize the input with strtok will remove it, allowing valid strcmp comparisons with the final token (e.g. that is why quit and exit would not quit the application).
Other than than, there were several additional things you could do a little different/better, you could handle directories entered as e.g. '~/somedir', and similar additional checks that could be employed. I have notated most below as comments to the code.
Look over the changes below and let me know if you have any questions. There are always additional checks that can be added, etc.., but on balance your approach to the problem was pretty good. (note: some of the changes made were non-substantive, e.g. "shell> " as the prompt, instead of "> ". Just handle any of those as you wish.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
Sample Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit

How to create | in one's own shell?

I'm actually doing my own shell.
I have done the following special characters:
int commande(int fin, int fout, char * com, char * param, int * bg){
// execute a command
(ex. ls –l)
int symbole;
char *mot;
pid_t pid;
symbole = parsing();
switch(symbole){
case 0: // NL
case 1: // ;
case 2: // &
case 3: // <
case 4: // >
case 5: // | (Here I have some issues when I try to redirect the output of a command).
(correspond à ctrl+D)
case 10:// Mot
default:
}
return;
}
But I have some issues to do the redirection of an output when it is piped " |", when I have two instructions that follow themselves. Indeed I have tried the following operations which have all worked:
>myShell ps > fich
>myShell ls -l | wc -l
But not this one:
>myShell ls -l | wc -l >file
here are the two cases specifically developped. I think that the issue is in the case 5 and not in the case 4 because the first command I tried worked (which I shew you above).
case 4: // SYMBOLE : >
if(output==0){
output=1;
execute=1;
for (l=0;l<10;l++){
eltsoutput[l]=eltsCommande[l];
}
}
break;
case 5: // SYMBOLE : |
//if(tube==0){
/*for (l=0;l<10;l++){
eltstube[l]=eltsCommande[l];
}*/
p2=fork();
if(p2==0){
if(tube==0){
freopen( "fichtmp", "w", stdout );
execvp(eltsCommande[0], eltsCommande);
}
return(0);
}
else{ if(background==0){ // SANS MOD BG ATTENDRE FIN FILS
waitpid(p2, NULL, 0);
}
tube=1;
execute=1;
}
break;
Can you help me finding a way to execute two commands at the same time with | and that allow their result to go to a file?
In my shell, the case one work in the case of a redirection with an instruction ";":
}else if(output==1){
close(1);
int filew = creat(eltsCommande[0], 0644);
execvp(eltsoutput[0], eltsoutput);
Maybe I should use this code to make it work?
Looking at the NetBSD /bin/sh source code, I see the following pipe implementation:
static int
sh_pipe(int fds[2])
{
int nfd;
if (pipe(fds))
return -1;
if (fds[0] < 3) {
nfd = fcntl(fds[0], F_DUPFD, 3);
if (nfd != -1) {
close(fds[0]);
fds[0] = nfd;
}
}
if (fds[1] < 3) {
nfd = fcntl(fds[1], F_DUPFD, 3);
if (nfd != -1) {
close(fds[1]);
fds[1] = nfd;
}
}
return 0;
}
This function is called by evalpipe with 2 file descriptors:
STATIC void
evalpipe(union node *n)
{
struct job *jp;
struct nodelist *lp;
int pipelen;
int prevfd;
int pip[2];
TRACE(("evalpipe(0x%lx) called\n", (long)n));
pipelen = 0;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
pipelen++;
INTOFF;
jp = makejob(n, pipelen);
prevfd = -1;
for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
prehash(lp->n);
pip[1] = -1;
if (lp->next) {
if (sh_pipe(pip) < 0) {
if (prevfd >= 0)
close(prevfd);
error("Pipe call failed");
}
}
if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
INTON;
if (prevfd > 0) {
close(0);
copyfd(prevfd, 0, 1);
close(prevfd);
}
if (pip[1] >= 0) {
close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1, 1);
close(pip[1]);
}
}
evaltree(lp->n, EV_EXIT);
}
if (prevfd >= 0)
close(prevfd);
prevfd = pip[0];
close(pip[1]);
}
if (n->npipe.backgnd == 0) {
exitstatus = waitforjob(jp);
TRACE(("evalpipe: job done exit status %d\n", exitstatus));
}
INTON;
}
evalpipe is called in a switch statement in evaltree as follows:
case NPIPE:
evalpipe(n);
do_etest = !(flags & EV_TESTED);
break;
... which is called by the infinite loop in evalloop, and percolates up the tree till it gets to the eval function. I hope this helps.

ATA command device IDENTIFY

I am trying to identify a device using ATA_PASS_THROUGH_EX.
When I see the output buffer, it has all invalid data. Can someone help me what I am doing wrong?
#include <Windows.h>
#include <ntddscsi.h>
#include <iostream>
void main() {
WCHAR *fileName = (WCHAR * ) "\\.\PhysicalDrive0";
HANDLE handle = CreateFile(
fileName,
GENERIC_READ | GENERIC_WRITE, //IOCTL_ATA_PASS_THROUGH requires read-write
FILE_SHARE_READ,
NULL, //no security attributes
OPEN_EXISTING,
0, //flags and attributes
NULL //no template file
);
ATA_PASS_THROUGH_EX inputBuffer;
inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
inputBuffer.DataTransferLength = 0;
inputBuffer.DataBufferOffset = 0;
IDEREGS *ir = (IDEREGS *) inputBuffer.CurrentTaskFile;
ir->bCommandReg = 0xEC; //identify device
ir->bSectorCountReg = 1;
unsigned int inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);
UINT8 outputBuffer[512];
UINT32 outputBufferSize = 512;
LPDWORD bytesReturned = 0;
DeviceIoControl( handle, IOCTL_ATA_PASS_THROUGH_DIRECT, &inputBuffer, inputBufferSize, &outputBuffer, outputBufferSize, bytesReturned, NULL);
DWORD error = GetLastError();
std::cout << outputBuffer << std::endl;
system("pause");
}
update:
When I check the error value, it is 5, which means it is an access violation. I am running in admin mode. Am I doing something wrong?
-Nick
I've done this using code that looks like this:
int foo()
{
int iRet( 0 );
// Open handle to disk.
HANDLE hDevice( ::CreateFileW( L"\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ) );
if( hDevice == INVALID_HANDLE_VALUE )
{
std::wcout << L"CreateFileW( " << sPath << L" ) failed. LastError: " << GetLastError() << std::endl;
return -1;
}
//
// Use IOCTL_ATA_PASS_THROUGH
//
std::vector< UCHAR > vBuffer( sizeof( ATA_PASS_THROUGH_EX ) + sizeof( IDENTIFY_DEVICE_DATA ), 0 );
PATA_PASS_THROUGH_EX pATARequest( reinterpret_cast< PATA_PASS_THROUGH_EX >( &vBuffer[0] ) );
pATARequest->AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED;
pATARequest->Length = sizeof( ATA_PASS_THROUGH_EX );
pATARequest->DataBufferOffset = sizeof( ATA_PASS_THROUGH_EX );
pATARequest->DataTransferLength = sizeof( IDENTIFY_DEVICE_DATA );
pATARequest->TimeOutValue = 2;
pATARequest->CurrentTaskFile[6] = ID_CMD;
ULONG ulBytesRead;
if( DeviceIoControl( hDevice, IOCTL_ATA_PASS_THROUGH,
&vBuffer[0], ULONG( vBuffer.size() ),
&vBuffer[0], ULONG( vBuffer.size() ),
&ulBytesRead, NULL ) == FALSE )
{
std::cout << "DeviceIoControl(IOCTL_ATA_PASS_THROUGH) failed. LastError: " << GetLastError() << std::endl;
iRet = -1;
}
else
{
// Fetch identity blob from output buffer.
PIDENTIFY_DEVICE_DATA pIdentityBlob( reinterpret_cast< PIDENTIFY_DEVICE_DATA >( &vBuffer[ sizeof( ATA_PASS_THROUGH_EX ) ] ) );
}
CloseHandle( hDevice );
return iRet;
}
Note that this must be run from an administrator account or elevated context.

Resources