How to use chdir to change a directory? - c++

I am currently working on creating my own linux shell. I can "ls" in my directory and much more. However,
When I try and "cd" into a sub directory, it never actually changes. The code gets ran but does not actually change my directory.
On my linux filesystem I have the directory
/
home
testing
foo.txt
testingForShell
bar.txt
To get the current directory, I am using...
void execute(string command, char *
const * args, char * path) {
int pid = -5;
int child = -5;
int status;
pid = fork();
if (pid == 0) {
if (command.substr(command.length() - 2).compare("cd") == 0) {
const char * currentPath;
if ((currentPath = getenv("HOME")) == NULL) {
currentPath = getpwuid(getuid()) -> pw_dir;
}
cout << (string(currentPath) + "/" + string(args[1])).c_str() << endl;
int dir = chdir((string(currentPath) + "/" + string(args[1])).c_str());
} else {
char * pathArgs = strtok(path, ":");
while (pathArgs != NULL) {
try {
execv((string(pathArgs) + "/" + command).c_str(), args);
} catch (...) {
}
pathArgs = strtok(NULL, ":");
}
}
exit(0);
} else {
waitpid(-1, & status, 0);
}
}
The first if inside the child process is if they are going to "cd" into a directory. The else is for other commands such as "ls".
The cout prints out /home/testing/testingForShell but when I call "ls" again, it never went inside the directory to show bar.txt. Let me know if I have provided enough information. I am very confident I am using chdir wrong, but that might not be the case. NOTE: I am trying to change the directory in the script running, not the actual linux terminal that I started my script from.

Changing working directory in a forked process will work fine... in that forked process.
But it doesn't do anything to the parent. So the next command that is executed is in the same working directory as before.

Related

How to convert the system call to fork in C++ linux

This is the code for playing sound file in C++ linux code
string str1 = "aplay ";
str1 = str1 + " out.wav" + " & ";
const char *command = str1.c_str();
system(command);
** Entire code is available here : Playing sound C++ linux aplay : device or resource busy
I just want to know how to play this in a fork() as I read that system call is too taxing on cpu, which ofcourse is in my case.
Please help
fork will make a copy of your process, so you can easily write:
// fork the current process: beyond this point, you will have 2 process
int ret = fork();
if (ret == 0) {
// in child: execute the long command
system("aplay out.wav");
// exit the child process
exit(0);
}
// child process will not go here
if (ret < 0) {
perror("fork");
}
After, you should know that system will do for you fork + exec + wait. Since you don't want your parent process to wait the child, you can write:
// fork the current process: beyond this point, you will have 2 process
int ret = fork();
if (ret == 0) {
// in child: execute the long command
char program[] = "/usr/bin/aplay";
char *args[] = {"/usr/bin/aplay", "out.wav" };
ret = execv(program, args);
// this point will be reach only if `exec` fails
// so if we reach this point, we've got an error.
perror("execv");
exit(0);
}
// child process will not go here
if (ret < 0) {
perror("fork");
}

readdir on AWS EFS doesn't return all files in directory

After having written many files to a series of folders on EFS (10k or so). Readdir stops returning all of the files in each directory.
I have a C++ application that in one part of its process it generates a lot of files and each file is given a symlink. After that I need to get a list of the file in a folder to then select a subset to rename. When I run the function that gets the list of files, it does not return all the files that are actually there. This code runs fine on my local machine, but on an AWS server with a mounted EFS drive, it stops working after a while.
In order to troubleshoot this issue, I have made my code only write one file at a time. I have also setup my code to use getFiles() to give me a count of how many files there are in a folder after writing each batch of files (around 17 files). When the number of files reaches ~950 files, getFiles() starts listing ~910 files and no longer increments. When its writing files, the files are varied but fairly small (2 bytes - 300K) and its writing about 200 files a second. Each file also has a symlink created to it.
When reading and writing files I am using posix open(), write(), read() and close(). I have verified that I do in fact close all files after reading or writing.
I am trying to figure out:
1. Why is readdir not working? Or why is it not listing all the files?
2. What is different about EFS that could be causing issues?
These are the functions I am using to get the list of files in a folder:
DIR * FileUtil::getDirStream(std::string path) {
bool success = false;
if (!folderExists(path)){
return NULL;
}
DIR * dir = opendir(path.c_str());
success = dir != NULL;
int count = 0;
while(!success){
int fileRetryDelay = BlazingConfig::getInstance()->getFileRetryDelay();
const int sleep_milliseconds = (count+1)*fileRetryDelay;
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_milliseconds));
std::cout<<"Was unable to get Dir stream for "<<path<<std::endl;
dir = opendir(path.c_str());
success = dir != NULL;
count++;
if(count > 6){
break;
}
}
if(success == -1){
std::cout<<"Can't get Dir stream for "<<path<<". Error was: "<<errno<<std::endl;
}
return dir;
}
int FileUtil::getDirEntry(DIR * dirp, struct dirent * & prevDirEntry, struct dirent * & dirEntry){
bool success = false;
if (dirp == NULL){
return -1;
}
int returnCode = readdir_r(dirp, prevDirEntry, &dirEntry);
success = (dirEntry == NULL && returnCode == 0) || dirEntry != NULL;
int count = 0;
while(!success){
int fileRetryDelay = BlazingConfig::getInstance()->getFileRetryDelay();
const int sleep_milliseconds = (count+1)*fileRetryDelay;
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_milliseconds));
std::cout<<"Was unable to get dirent with readdir"<<std::endl;
returnCode = readdir_r(dirp, prevDirEntry, &dirEntry);
success = (dirEntry == NULL && returnCode == 0) || dirEntry != NULL;
count++;
if(count > 6){
break;
}
}
if(success == -1){
std::cout<<"Can't get dirent with readdir. Error was: "<<errno<<std::endl;
}
return returnCode;
}
std::vector<std::string> FileUtil::getFiles(std::string baseFolder){
DIR *dir = getDirStream(baseFolder);
std::vector <std::string> subFolders;
if (dir != NULL) {
struct dirent *prevDirEntry = NULL;
struct dirent *dirEntry = NULL;
int len_entry = offsetof(struct dirent, d_name) + fpathconf(dirfd(dir), _PC_NAME_MAX) + 1;
prevDirEntry = (struct dirent *)malloc(len_entry);
int returnCode = getDirEntry(dir, prevDirEntry, dirEntry);
while (dirEntry != NULL) {
if( dirEntry->d_type == DT_REG || dirEntry->d_type == DT_LNK){
std::string name(dirEntry->d_name);
subFolders.push_back(name);
}
returnCode = getDirEntry(dir, prevDirEntry, dirEntry);
}
free(prevDirEntry);
closedir (dir);
} else {
std::cout<<"Could not open directory err num is"<<errno<<std::endl;
/* could not open directory */
perror ("");
}
return subFolders;
}
The functions were written this way to try to be as robust as possible, since there can be many threads performing file operations, I wanted to be able to have the code retry in case of any failures. Unfortunately when getFiles() returns the wrong result, it does not give me any indication of failure.
Note: when I use readdir as opposed to readdir_r I still have the same issue.

PathFileExists returns false when executing application through RemoteApp

My executable built in C++/WinAPI will check for a file placed in the same folder and I use PathFileExists for that. When I run it on a normal computer it finds the file but when I publish the executable on RemoteApp and I run it from Web Access the file is not found. What would I be missing?
// This is the file I want to find (located in the same directory as the EXE)
wstring myfile = L"myfile.conf";
BOOL abspath = FALSE;
// Trying to get the absolute path first
DWORD nBufferLength = MAX_PATH;
wchar_t szCurrentDirectory[MAX_PATH + 1];
if (GetCurrentDirectory(nBufferLength, szCurrentDirectory) == 0) {
szCurrentDirectory[MAX_PATH + 1] = '\0';
} else {
abspath = true;
}
if (abspath) {
// Create the absolute path to the file
myfile = L'\\' + myfile;
myfile = szCurrentDirectory + myfile ;
MessageBox(hWnd, ConvertToUNC(myfile).c_str(), L"Absolute Path", MB_ICONINFORMATION);
} else {
// Get the UNC path
myfile = ConvertToUNC(myfile);
MessageBox(hWnd, myfile.c_str(), L"UNC Path", MB_ICONINFORMATION);
}
// Try to find file
int retval = PathFileExists(myfile.c_str());
if (retval == 1) {
// Do something
} else {
// File not found
}
The ConvertToUNC function is copied from here.
What I see is that, although the executable lies somewhere else, the absolute path is considered to be C:\Windows. I really don't know what is causing this. The server is Windows 2012 R2 and, like I said, applications are run through RemoteApp Web Access. The returned UNC path is just the name of the file (no volume or folder)

Unsuccesfull management of specific processes in my C++ console application

In this thread I solved a part of my cases and thanks to NathanOliver I've got to the following code so far:
int main(){
//...
bool proc1 = false, proc2 = false, proc3 = false, proc4 = false,
while(true) {
if(!proc1 && ProcessRunning("process1.exe")){
fun1("fun1.bat");
proc1 = true;
}
if(!proc2 && ProcessRunning("process2.exe")){
fun1("fun2.bat");
proc2 = true;
}
if(!proc3 && ProcessRunning("process3.exe")){
fun1("fun3.bat");
proc3 = true;
}
if(!proc4 && ProcessRunning("process4.exe")){
fun1("fun4.bat");
proc4 = true;
}
}
return 0;
}
What I still can't get through is the case where:
double click on app1 -> process1 starts.
while process1 is running I double click on app2 so that process2 should have the same behaviour as I mentioned in my first thread:
if it finds process2 (the second if(){}), it creates that .bat file and
it executes it (kill process2(it might existed before i opened it), start > it again, delete the .bat file generated by fun2(const char name[]){}).
Summary of previous post:
int fun1(const char name[]){
ofstream file;
file.open(name, ios::out);
//start of what I write in .bat
file << "#echo off";
file << "cd to specific path";
file << "taskkill /im process.exe* /f";
file << "start process.exe";
file << "del \"%~f0\"";
file.close();
return system(name);
}
Exactly the same for the rest functions.
I believe you run the .bat file as sync program, therefore until the bat won't finish and return exit code (which you may check as return value of system function) your main program won't continue to run. You may use async process using fork on linux based systems and CreateProcess on windows OS.
How about this? (C++11 Standard)
bool proc[] = {false, false, false, false};
while(true)
{
for(int i=0 ; i<4 ; i++)
{
const std::string exeName = "process" + std::to_string(i) + ".exe";
const std::string funName = "fun" + std::to_string(i) + ".bat";
if(!proc[i] && ProcessRunning(exeName.c_str()))
{
fun1(funName.c_str());
proc[i] = true;
}
}
Should make things a bit more flexible, but getting to your problem. If-condition compares the first expression proc and then ProcessRunning(...). Both must be true in order to enter the control block.
But your file explaining fun1() seems to have an issue at least in comments. You mention for example to //taskkill process.exe but it has to be process#.
I can help you more on that if you provide the full fun1 implementation or at least the most relevant parts. Your cycle though should work. The problem has to be in fun1(...)
P.D.: I also would rename fun1(...) to something that makes more sense.

How to get pid of process executed with system() command in c++

When we use system() command, program wait until it complete but I am executing a process using system() and using load balance server due to which program comes to next line just after executing system command. Please note that that process may not be complete.
system("./my_script");
// after this I want to see whether it is complete or not using its pid.
// But how do i Know PID?
IsScriptExecutionComplete();
Simple answer: you can't.
The purpose of system() is to block when command is being executed.
But you can 'cheat' like this:
pid_t system2(const char * command, int * infp, int * outfp)
{
int p_stdin[2];
int p_stdout[2];
pid_t pid;
if (pipe(p_stdin) == -1)
return -1;
if (pipe(p_stdout) == -1) {
close(p_stdin[0]);
close(p_stdin[1]);
return -1;
}
pid = fork();
if (pid < 0) {
close(p_stdin[0]);
close(p_stdin[1]);
close(p_stdout[0]);
close(p_stdout[1]);
return pid;
} else if (pid == 0) {
close(p_stdin[1]);
dup2(p_stdin[0], 0);
close(p_stdout[0]);
dup2(p_stdout[1], 1);
dup2(::open("/dev/null", O_RDONLY), 2);
/// Close all other descriptors for the safety sake.
for (int i = 3; i < 4096; ++i)
::close(i);
setsid();
execl("/bin/sh", "sh", "-c", command, NULL);
_exit(1);
}
close(p_stdin[0]);
close(p_stdout[1]);
if (infp == NULL) {
close(p_stdin[1]);
} else {
*infp = p_stdin[1];
}
if (outfp == NULL) {
close(p_stdout[0]);
} else {
*outfp = p_stdout[0];
}
return pid;
}
Here you can have not only PID of the process, but also it's STDIN and STDOUT. Have fun!
Not an expert on this myself, but if you look at the man page for system:
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed
You can go into the background within the command/script you're executing (and return immediately), but I don't think there's a specific provision in system for that case.
Ideas I can think of are:
Your command might return the pid through the return code.
Your code might want to look up the name of the command in the active processes (e.g. /proc APIs in unix-like environments).
You might want to launch the command yourself (instead of through a SHELL) using fork/exec
As the other answers said, std::system blocks until complete anyway. However, if you want to run the child process async and you are ok with boost you can use boost.process (ref):
#include <boost/process.hpp>
namespace bp = boost::process;
bp::child c(bp::search_path("echo"), "hello world");
std::cout << c.id() << std::endl;
// ... do something with ID ...
c.wait();
You can check exit status of your command by following code :
int ret = system("./my_script");
if (WIFEXITED(ret) && !WEXITSTATUS(ret))
{
printf("Completed successfully\n"); ///successful
}
else
{
printf("execution failed\n"); //error
}