I have a big trouble while writing some data to files using MPI on a cluster with PBS. Here is the example of simple problem-emulating programm.
#include <mpi.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <unistd.h>
int main(int argc, char* argv[]){
int rank;
int size;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
// Define hostname
char hostname[128];
gethostname(hostname, 128);
// check and create dump directory
struct stat buf;
int rc;
char *dir="Res";
rc = stat( dir, &buf );
if( rc ) // no dir, create
{ if( rank == 0 )
{
rc = mkdir( dir, 0771);
if( rc )
{std::ostringstream oss;
oss << "Can't create dump directory \""
<< dir
<< "\"";
}
}
else {
sleep (2);
}
}
else if( !S_ISDIR( buf.st_mode ) )
{std::ostringstream oss;
oss << "Path \""
<< dir
<< "\" is not directory for dump";
}
MPI_Barrier(MPI_COMM_WORLD);
// Every process defines name of file for output (res_0, res_1, res_2.....)
std::ostringstream filename;
filename << dir << "/res_"<< rank;
// Open file
std::ofstream file(filename.str().c_str());
// Output to file . Output seems like "I am 0 from 24. hostname"
file << "I am " << rank << " from " << size << ". " << hostname << std::endl;
file.close();
MPI_Finalize();
return 0;
}
I compile it with openmpi_intel-1.4.2, using comand
mpicxx -Wall test.cc -o test
Then I queue this program with script:
#!/bin/bash
#PBS -N test
#PBS -l select=8:ncpus=6:mpiprocs=6
#PBS -l walltime=00:01:30
#PBS -m n
#PBS -e stderr.txt
#PBS -o stdout.txt
cd $PBS_O_WORKDIR
echo "I run on node: `uname -n`"
echo "My working directory is: $PBS_O_WORKDIR"
echo "Assigned to me nodes are:"
cat $PBS_NODEFILE
mpirun -hostfile $PBS_NODEFILE ./test
I expected this result:
1. New directory "Res" to be created
2. 8*6 different files (res_0, res_1, res_2, ...) to be written to the Res dir
But only res_* file from the first node are written (res_{0..5}) while the rest are not.
What is the problem?
Thank you!
OK, let's assume you run on a file system coherently mounted across all your compute nodes. This is the case, right?
So then the main issue I see with your code snippet is that all processes do state the directory at the same time and then try to create it if it doesn't exist. I'm not sure what truly happens but I'm sure this isn't the smartest idea ever.
Since in essence what you want is a serial sanity check of the directory and/or it's creation if needed, why not just letting MPI process of rank 0 doing it?
That would give you something like this:
if ( rank == 0 ) { // Only master manages the directory creation
int rc = stat( dir, &buf );
... // sanity check goes here and directory creation as well
// calling MPI_Abort() in case of failure seems also a good idea
}
// all other processes wait here
MPI_Barrier( MPI_COMM_WORLD );
// now we know the directory exists and is accessible
// let's do our stuff
Could this work for you?
Related
How can I change my current working directory in C++ in a platform-agnostic way?
I found the direct.h header file, which is Windows compatible, and the unistd.h, which is UNIX/POSIX compatible.
The chdir function works on both POSIX (manpage) and Windows (called _chdir there but an alias chdir exists).
Both implementations return zero on success and -1 on error. As you can see in the manpage, more distinguished errno values are possible in the POSIX variant, but that shouldn't really make a difference for most use cases.
Now, with C++17 is possible to use std::filesystem::current_path:
#include <filesystem>
int main() {
auto path = std::filesystem::current_path(); //getting path
std::filesystem::current_path(path); //setting path
}
For C++, boost::filesystem::current_path (setter and getter prototypes).
A file system library based on Boost.Filesystem will be added to the standard.
This cross-platform sample code for changing the working directory using POSIX chdir and MS _chdir as recommend in this answer. Likewise for determining the current working directory, the analogous getcwd and _getcwd are used.
These platform differences are hidden behind the macros cd and cwd.
As per the documentation, chdir's signature is int chdir(const char *path) where path is absolute or relative. chdir will return 0 on success. getcwd is slightly more complicated because it needs (in one variant) a buffer to store the fetched path in as seen in char *getcwd(char *buf, size_t size). It returns NULL on failure and a pointer to the same passed buffer on success. The code sample makes use of this returned char pointer directly.
The sample is based on #MarcD's but corrects a memory leak. Additionally, I strove for concision, no dependencies, and only basic failure/error checking as well as ensuring it works on multiple (common) platforms.
I tested it on OSX 10.11.6, Centos7, and Win10. For OSX & Centos, I used g++ changedir.cpp -o changedir to build and ran as ./changedir <path>.
On Win10, I built with cl.exe changedir.cpp /EHsc /nologo.
MVP solution
$ cat changedir.cpp
#ifdef _WIN32
#include <direct.h>
// MSDN recommends against using getcwd & chdir names
#define cwd _getcwd
#define cd _chdir
#else
#include "unistd.h"
#define cwd getcwd
#define cd chdir
#endif
#include <iostream>
char buf[4096]; // never know how much is needed
int main(int argc , char** argv) {
if (argc > 1) {
std::cout << "CWD: " << cwd(buf, sizeof buf) << std::endl;
// Change working directory and test for success
if (0 == cd(argv[1])) {
std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl;
}
} else {
std::cout << "No directory provided" << std::endl;
}
return 0;
}
OSX Listing:
$ g++ changedir.c -o changedir
$ ./changedir testing
CWD: /Users/Phil
CWD changed to: /Users/Phil/testing
Centos Listing:
$ g++ changedir.c -o changedir
$ ./changedir
No directory provided
$ ./changedir does_not_exist
CWD: /home/phil
$ ./changedir Music
CWD: /home/phil
CWD changed to: /home/phil/Music
$ ./changedir /
CWD: /home/phil
CWD changed to: /
Win10 Listing
cl.exe changedir.cpp /EHsc /nologo
changedir.cpp
c:\Users\Phil> changedir.exe test
CWD: c:\Users\Phil
CWD changed to: c:\Users\Phil\test
Note: OSX uses clang and Centos gnu gcc behind g++.
Does chdir() do what you want? It works under both POSIX and Windows.
You want chdir(2). If you are trying to have your program change the working directory of your shell - you can't. There are plenty of answers on SO already addressing that problem.
Did you mean C or C++? They are completely different languages.
In C, the standard that defines the language doesn't cover directories. Many platforms that support directories have a chdir function that takes a char* or const char* argument, but even where it exists the header where it's declared is not standard. There may also be subtleties as to what the argument means (e.g. Windows has per-drive directories).
In C++, googling leads to chdir and _chdir, and suggests that Boost doesn't have an interface to chdir. But I won't comment any further since I don't know C++.
Nice cross-platform way to change current directory in C++ was suggested long time ago by #pepper_chico. This solution uses boost::filesystem::current_path().
To get the current working directory use:
namespace fs = boost::filesystem;
fs::path cur_working_dir(fs::current_path());
To set the current working directory use:
namespace fs = boost::filesystem;
fs::current_path(fs::system_complete( fs::path( "new_working_directory_path" ) ));
Bellow is the self-contained helper functions:
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <string>
namespace fs = boost::filesystem;
fs::path get_cwd_pth()
{
return fs::current_path();
}
std::string get_cwd()
{
return get_cwd_pth().c_str();
}
void set_cwd(const fs::path& new_wd)
{
fs::current_path(fs::system_complete( new_wd));
}
void set_cwd(const std::string& new_wd)
{
set_cwd( fs::path( new_wd));
}
Here is my complete code-example on how to set/get current working directory:
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <iostream>
namespace fs = boost::filesystem;
int main( int argc, char* argv[] )
{
fs::path full_path;
if ( argc > 1 )
{
full_path = fs::system_complete( fs::path( argv[1] ) );
}
else
{
std::cout << "Usage: tcd [path]" << std::endl;
}
if ( !fs::exists( full_path ) )
{
std::cout << "Not found: " << full_path.c_str() << std::endl;
return 1;
}
if ( !fs::is_directory( full_path ))
{
std::cout << "Provided path is not a directory: " << full_path.c_str() << std::endl;
return 1;
}
std::cout << "Old current working directory: " << boost::filesystem::current_path().c_str() << std::endl;
fs::current_path(full_path);
std::cout << "New current working directory: " << boost::filesystem::current_path().c_str() << std::endl;
return 0;
}
If boost installed on your system you can use the following command to compile this sample:
g++ -o tcd app.cpp -lboost_filesystem -lboost_system
Can't believe no one has claimed the bounty on this one yet!!!
Here is a cross platform implementation that gets and changes the current working directory using C++. All it takes is a little macro magic, to read the value of argv[0], and to define a few small functions.
Here is the code to change directories to the location of the executable file that is running currently. It can easily be adapted to change the current working directory to any directory you want.
Code :
#ifdef _WIN32
#include "direct.h"
#define PATH_SEP '\\'
#define GETCWD _getcwd
#define CHDIR _chdir
#else
#include "unistd.h"
#define PATH_SEP '/'
#define GETCWD getcwd
#define CHDIR chdir
#endif
#include <cstring>
#include <string>
#include <iostream>
using std::cout;
using std::endl;
using std::string;
string GetExecutableDirectory(const char* argv0) {
string path = argv0;
int path_directory_index = path.find_last_of(PATH_SEP);
return path.substr(0 , path_directory_index + 1);
}
bool ChangeDirectory(const char* dir) {return CHDIR(dir) == 0;}
string GetCurrentWorkingDirectory() {
const int BUFSIZE = 4096;
char buf[BUFSIZE];
memset(buf , 0 , BUFSIZE);
GETCWD(buf , BUFSIZE - 1);
return buf;
}
int main(int argc , char** argv) {
cout << endl << "Current working directory was : " << GetCurrentWorkingDirectory() << endl;
cout << "Changing directory..." << endl;
string exedir = GetExecutableDirectory(argv[0]);
ChangeDirectory(exedir.c_str());
cout << "Current working directory is now : " << GetCurrentWorkingDirectory() << endl;
return 0;
}
Output :
c:\Windows>c:\ctwoplus\progcode\test\CWD\cwd.exe
Current working directory was : c:\Windows
Changing directory...
Current working directory is now : c:\ctwoplus\progcode\test\CWD
c:\Windows>
I have this short program:
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
int main (int argc, char * argv[]) {
std::string homedir = std::getenv("HOME");
std::string filename = argc > 1 ? argv[1] : (homedir + "/" + "file");
std::cout << homedir << std::endl;
std::cout << filename << std::endl;
std::fstream file;
file.open(filename, std::ios::out);
file << "Yo yo waddup" << std::endl;
file.close();
return 0;
}
When I supply no arguments, it opens a file in the users home directory. That of course makes sense. But when I run it from a different directory like this:
$ ./folder/hometest examplefile
The program creates "examplefile" in my current directory instead of the directory where the program is.
Why exactly is this happening?
Why exactly is this happening?
The program is behaving just as expected.
The file is opened relative to the current work directory, not where the executable is located.
If it didn't work that way,
All your programs will have to work with absolute paths, or
The location of the program will be flooded with files. First, that might not be possible because of permissions issue. Second, in a multi-user system, users will end up trying to create the same file names/directories.
Neither of the above is desirable.
I'm an inexperienced Linux programmer and am trying to learn to use readlink() based on this question and answer.
My call to readlink() returns -1 and sets errno to 2 (ENOENT).
The code:
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
int main(int argc, char* argv[])
{
char szTmp[100];
snprintf(szTmp, 100, "proc/%d/exe", getpid());
std::cout << "szTmp is " << szTmp << std::endl;
char executingFolder[500];
errno = 0;
int bytes = std::min(readlink(szTmp, executingFolder, 500), (ssize_t)499);
if (bytes > 0)
{
executingFolder[bytes] = '\0';
}
std::cout << "bytes is " << bytes << std::endl;
std::cout << "errno is " << errno;
if (ENOENT == errno)
{
std::cout << " ENOENT";
}
std::cout << std::endl;
std::cout << "Executing folder is \"" << executingFolder << "\"" << std::endl;
return 0;
}
The output:
(An example from one iteration since pid changes)
szTmp is proc/22272/exe
bytes is -1
errno is 2 ENOENT
Executing folder is ""
Things I have tried:
After compilation: sudo ./a.out (thinking that directory access was restricted because of lack of permission). Result: unchanged behavior from ./a.out
SIGINT the program during execution, and verified that /proc/<pid>/exe exists. Result: it consistently exists for each run of the program.
Verified that the value of the target link is well within 499 chars.
Can someone please help identify the problem? Having read the readlink man page and online descriptions, and the noted StackOverflow article, I am still unclear what is wrong.
Thank you.
proc/1234/exe is a relative path.
I think you want /proc/%d/exe, which is an absolute path, and correctly refers to the /proc directory.
Secondly, because readlink() will truncate the result in case the buffer is too small, you should consider the case where the return value is == bufsiz to be an error, as truncation may have happened. You can't know.
Also, "Executing folder" is not what /proc/<pid>/exe gives you. /proc/<pid>/exe is a symlink to the currently running executable (file), not a directory.
proc/22272/exe is a relative path name. It resolves to the file exe, in the directory 22272, in the directory proc, in your current directory. Unless your current directory is /, that's unlikely to exist.
You want an absolute path name, starting with /, in this case /proc/22272/exe.
Change this:
snprintf(szTmp, 100, "proc/%d/exe", getpid());
to this:
snprintf(szTmp, 100, "/proc/%d/exe", getpid());
But before you fix your program, you might try this:
( cd / ; ~/a.out )
(assuming a.out is in your home directory).
Hey everyone. I need to write a POSIX program to search through an entire file system for a specified file starting at the top directory. I've got some code which isn't done at all, but when I run it, and check to see if a particular file is a directory, it's saying this file which is not at all a directory is a directory and is trying to move into it, causing an error. I'm not sure how I can tell it that this type of file isn't a directory.
Here's my code. I know it's not perfect and I could probably do some things differently in the way of getting the directory names and passing them into the function. Either way, I'm pretty sure I have to do this recursively.
The file in question is /dev/dri/card0 and I'm running this from a Debian virtual machine.
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <locale.h>
#include <langinfo.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
void SearchDirectory(string file_Name, string directory){
string new_Directory = directory;
DIR *dirp;
dirp = opendir(directory.c_str());
struct dirent *dptr;
struct stat statStruct;
while(dptr = readdir(dirp)){
stat(dptr->d_name, &statStruct);
if( S_ISDIR(statStruct.st_mode) ){
string check = dptr->d_name;
if ( check.compare(".") == 0 || check.compare("..") == 0 ){
continue;
}
else{
cout << dptr->d_name << " is is a directory" << endl;
new_Directory.append("/");
new_Directory.append(dptr->d_name);
SearchDirectory(file_Name, new_Directory);
}
}
else if( S_ISREG(statStruct.st_mode)){
string check = dptr->d_name;
if( check.compare(file_Name) == 0){
cout << "Found " << file_Name << " in " << directory << "/" << endl;
}
}
}
}
int main(int argc, char *argv[]){
if(argc < 2 || argc > 2){
cerr << "This program will find the specified file." << endl;
cerr << "Usage: mysearch <filename>" << endl;
return 1;
}
string file_Name = argv[1];
SearchDirectory(file_Name, "/");
return 0;
}
POSIX.2 requires a working "find" command.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>", argv[0]);
}
execlp("find", "find", "/", "-name", argv[1], "-print", (char *)NULL);
exit(EXIT_FAILURE);
}
->d_name returns just the name of the file, not the path to the file. You need to stat (not yet constructed) new_Directory instead of dptr->d_name.
You also have a problem if a directory contains more than one subdirectories. Your construction of new_Directory is incorrect for each subdirectory after the first.
You never closedir your directory handle, so you run out of resources. You should also consider loading the entire directory into an array before recursing to avoid running out of handles.
void SearchDirectory(string directory, string target_File_Name){
DIR *dirp = opendir(directory.c_str());
if (!dirp) {
perror(("opendir " + directory).c_str());
return;
}
struct dirent *dptr;
while(dptr = readdir(dirp)){
string file_Name = dptr->d_name;
string file_Path = directory + "/" + file_Name;
struct stat statStruct;
stat(file_Path.c_str(), &statStruct);
if( S_ISDIR(statStruct.st_mode) ){
if ( file_Name.compare(".") == 0 || file_Name.compare("..") == 0 ){
continue;
}
SearchDirectory(file_Path, target_File_Name);
}
else if( S_ISREG(statStruct.st_mode)){
if( file_Name.compare(target_File_Name) == 0){
cout << file_Path << endl;
}
}
}
closedir(dirp);
}
Update: Added second problem.
Update: Added third problem.
Update: Added code.
Not for the benefit of the OP, who writes "The point is to come up with a way to do it myself," but rather for the benefit of posterity, here is a way to use Boost.Filesystem:
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
// sample usage: find_file("/home", ".profile");
void find_file( const fs::path& dirPath, const std::string& fileName) {
fs::recursive_directory_iterator end;
for(fs::recursive_directory_iterator it(dirPath); it != end; ++it) {
if(it->leaf() == fileName)
std::cout << it->path() << "\n";
if(fs::is_symlink(it->symlink_status()))
it.no_push();
}
}
Use fork, execv and the Unix implemented /usr/bin/find process and redirect its output for your result area?
I'm not sure if it's POSIX or not but the nftw library function is widely available on UNIX (HP-UX, AIX, Linux).
Your problem is "search a tree for a match"
BFS and DFS are the canonical basic algorithms. Give them a start node and go.
You will get into trouble if you follow symlinks; so test for them and don't follow them.
You should be able to map each point in the *FS algorithms to a directory operation.
Since C++ is an option, why not use something like Boost.Filesystem? The Boost.Filesystem two-minute tutorial gives an example of how to implement your search using directory iterators.
While I try the following:
system( "ifconfig -a | grep inet | "
"sed 's/\\([ ]*[^ ]*\\)\\([ ]*[^ ]*\\).*$/\\1 \\2/' "
" > address.txt" ) ;
I am getting the output in a file. How can I assign the out put to a variable.
EDIT: the best way to do this as recommended in #Paul R's comment, is to use _popen and read in the command output from stdin. There is sample code at that MSDN page.
ORIGINAL EFFORT:
One option would be to create a temp file using tmpnam_s, write your output there instead of hard-coding the filename, and then read it back from the file into a std::string,deleting the temp file once you are done. Based on the MSDN sample code:
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
int main( void )
{
char name1[L_tmpnam_s];
errno_t err;
err = tmpnam_s( name1, L_tmpnam_s );
if (err)
{
printf("Error occurred creating unique filename.\n");
exit(1);
}
stringstream command;
command << "ifconfig -a | grep inet | " <<
"sed 's/\\([ ]*[^ ]*\\)\\([ ]*[^ ]*\\).*$/\\1 \\2/' " <<
" > " << (const char*)name1;
system(command.str().c_str());
{
ifstream resultFile((const char*)name1);
string resultStr;
resultFile >> resultStr;
cout << resultStr;
}
::remove(name1);
}
This code uses the CRT more than I would usually, but you seem to have a methodology you wish to use that relies on this.