Unix: using the fork, exec and wait system call for command interpreter - unix

I was able to refine the program further, but still need a little help in terms of storing the now separate words into an array. My current code only takes in the first word/command only. Here's my new code:
#include <unistd.h>
#include <string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
int main(){
int pid,status,rs;
char comm[100];
cout<<"Enter command:\n ";
cin.getline(comm,100);
char *token=strtok(comm," ");
pid=fork();
if(pid==-1)
{
perror("fork");
exit(pid);
}
if(pid==0)
{
while(token!=NULL){
char *argv[]={token,0};
rs=execvp(argv[0],argv);
token = strtok(NULL, " ");
}
if(rs==-1)
{
perror("execvp");
exit(rs);
}
}
else
{
cout<<"Done waiting for: "<<wait(&status)<<endl;
}
}
The outcome of the code should be something like this:
% ./z123456
Enter command: mkdir one
Enter command: touch one/file one/other one/more
Enter command: ls -l one
total 0
-rw-r--r-- 1 student student 0 Apr 3 13:03 file
-rw-r--r-- 1 student student 0 Apr 3 13:03 more
-rw-r--r-- 1 student student 0 Apr 3 13:03 other
Enter command: gobly gook
gobly: No such file or directory
Enter command: cd one
cd: No such file or directory
Enter command: exit
%

Related

Using PBS batch scripting, is there a way to view the contents of PBS_NODEFILE?

I read in the qsub man page that PBS_NODEFILE is created once mpirun, mpiexec, aprun, whatever, begins to execute. Is there a way to view its contents? I tried the following:
C code catfile.c:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char command[256];
MPI_Init(&argc, &argv);
sprintf(command, "%s %s\n", "cat", argv[1]);
printf("%s\n", command);
system(command);
MPI_Finalize();
}
In my batch script, I run with
cc -o catfile catfile.c
aprun -n 1 ./catfile $PBS_NODEFILE
Output is
cat /var/spool/PBS/aux/1894.pbs01
cat: /var/spool/PBS/aux/1894.pbs01: No such file or directory
That's all I've got. Is there another way? Thanks.

set-UID privieged programs

I have 2 question:
Consider the situation where Alice runs a owned Set-UID program
by Bob. The program wants to read the file contained in / etc / data, readable by
Alice, but by no one else. Can this program access the file?
Consider the situation where a process wants to access a file for reading;
the effective user ID of the process is 3000 and the real user ID is 4000. If the file is readable
for user ID 4000, but not for user ID 3000, this process can access the
file?
These are really the same question, and the answer in both cases is no, unless the program uses setresuid to change its effective UID to its real UID, or it uses setfsuid (Linux-specific) to change its filesystem UID to its real UID. But the program would have to be designed for this scenario; an ordinary program that never manipulates its UID/GID and just accesses files will fail the permission check.
Here is a concrete example of how to answer your part 1 question in code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static void flipuids(void) {
uid_t r = getuid();
uid_t e = geteuid();
if (setreuid(e, r)) {
perror("failed to flip");
exit(1);
}
}
int main(int argc, char *argv[]) {
printf("euid=%d uid=%d\n", geteuid(), getuid());
flipuids();
printf("euid=%d uid=%d\n", geteuid(), getuid());
FILE *file = fopen("/tmp/alices", "r");
if (file == NULL) {
perror("no reads");
exit(1);
}
flipuids();
printf("euid=%d uid=%d\n", geteuid(), getuid());
fclose(file);
}
If you chmod +s ./uidaccess to make sure that the program has these permissions:
$ ls -l ./uidaccess
-rwsr-sr-x 1 bob bob 17008 Apr 18 09:34 uidaccess
Once the program is run by alice, it is an example of a process operating as described in your part 2 question.

Can I link two separate executables with MPI_open_port and share port information in a text file?

I'm trying to create a shared MPI COMM between two executables which are both started independently, e.g.
mpiexec -n 1 ./exe1
mpiexec -n 1 ./exe2
I use MPI_Open_port to generate port details and write these to a file in exe1 and then read with exe2. This is followed by MPI_Comm_connect/MPI_Comm_accept and then send/recv communication (minimal example below).
My question is: can we write port information to file in this way, or is the MPI_Publish_name/MPI_Lookup_name required for MPI to work as in this, this and this? As supercomputers usually share a file system, this file based approach seems simpler and maybe avoids establishing a server.
It seems this should work according to the MPI_Open_Port documentation in the MPI 3.1 standard,
port_name is essentially a network address. It is unique within the communication universe to which it belongs (determined by the implementation), and may be used by any client within that communication universe. For instance, if it is an internet (host:port) address, it will be unique on the internet. If it is a low level switch address on an IBM SP, it will be unique to that SP
In addition, according to documentation on the MPI forum:
The following should be compatible with MPI: The server prints out an address to the terminal, the user gives this address to the client program.
MPI does not require a nameserver
A port_name is a system-supplied string that encodes a low-level network address at which a server can be contacted.
By itself, the port_name mechanism is completely portable ...
Writing the port information to file does work as expected, i.e creates a shared communicator and exchanges information using MPICH (3.2) but hangs at the MPI_Comm_connect/MPI_Comm_accept line when using OpenMPI versions 2.0.1 and 4.0.1 (on my local workstation running Ubuntu 12.04 but eventually needs to work on a tier 1 supercomputer). I have raised as an issue here but welcome a solution or workaround in the meantime.
Further Information
If I use the MPMD mode with OpenMPI,
mpiexec -n 1 ./exe1 : -n 1 ./exe2
this works correctly, so must be an issue with allowing the jobs to share ompi_global_scope as in this question. I've also tried adding,
MPI_Info info;
MPI_Info_create(&info);
MPI_Info_set(info, "ompi_global_scope", "true");
with info passed to all commands, with no success. I'm not running a server/client model as both codes run simultaneously so sharing a URL/PID from one is not ideal, although I cannot get this to work even using the suggested approach, which for OpenMPI 2.0.1,
mpirun -n 1 --report-pid + ./OpenMPI_2.0.1 0
1234
mpirun -n 1 --ompi-server pid:1234 ./OpenMPI_2.0.1 1
gives,
ORTE_ERROR_LOG: Bad parameter in file base/rml_base_contact.c at line 161
This failure appears to be an internal failure;
here's some additional information (which may only be relevant to an
Open MPI developer):
pmix server init failed
--> Returned value Bad parameter (-5) instead of ORTE_SUCCESS
and with OpenMPI 4.0.1,
mpirun -n 1 --report-pid + ./OpenMPI_4.0.1 0
1234
mpirun -n 1 --ompi-server pid:1234 ./OpenMPI_4.0.1 1
gives,
ORTE_ERROR_LOG: Bad parameter in file base/rml_base_contact.c at line 50
...
A publish/lookup server was provided, but we were unable to connect
to it - please check the connection info and ensure the server
is alive:
Using 4.0.1 means the error should not be related to this bug in OpenMPI.
Minimal code
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
using namespace std;
int main( int argc, char *argv[] )
{
int num_errors = 0;
int rank, size;
char port1[MPI_MAX_PORT_NAME];
char port2[MPI_MAX_PORT_NAME];
MPI_Status status;
MPI_Comm comm1, comm2;
int data = 0;
char *ptr;
int runno = strtol(argv[1], &ptr, 10);
for (int i = 0; i < argc; ++i)
printf("inputs %d %d %s \n", i,runno, argv[i]);
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (runno == 0)
{
printf("0: opening ports.\n");fflush(stdout);
MPI_Open_port(MPI_INFO_NULL, port1);
printf("opened port1: <%s>\n", port1);
//Write port file
ofstream myfile;
myfile.open("port");
if( !myfile )
cout << "Opening file failed" << endl;
myfile << port1 << endl;
if( !myfile )
cout << "Write failed" << endl;
myfile.close();
printf("Port %s written to file \n", port1); fflush(stdout);
printf("Attempt to accept port1.\n");fflush(stdout);
//Establish connection and send data
MPI_Comm_accept(port1, MPI_INFO_NULL, 0, MPI_COMM_WORLD, &comm1);
printf("sending 5 \n");fflush(stdout);
data = 5;
MPI_Send(&data, 1, MPI_INT, 0, 0, comm1);
MPI_Close_port(port1);
}
else if (runno == 1)
{
//Read port file
size_t chars_read = 0;
ifstream myfile;
//Wait until file exists and is avaialble
myfile.open("port");
while(!myfile){
myfile.open("port");
cout << "Opening file failed" << myfile << endl;
usleep(30000);
}
while( myfile && chars_read < 255 ) {
myfile >> port1[ chars_read ];
if( myfile )
++chars_read;
if( port1[ chars_read - 1 ] == '\n' )
break;
}
printf("Reading port %s from file \n", port1); fflush(stdout);
remove( "port" );
//Establish connection and recieve data
MPI_Comm_connect(port1, MPI_INFO_NULL, 0, MPI_COMM_WORLD, &comm1);
MPI_Recv(&data, 1, MPI_INT, 0, 0, comm1, &status);
printf("Received %d 1\n", data); fflush(stdout);
}
//Barrier on intercomm before disconnecting
MPI_Barrier(comm1);
MPI_Comm_disconnect(&comm1);
MPI_Finalize();
return 0;
}
The 0 and 1 simply specify if this code writes a port file or reads it in the example above. This is then run with,
mpiexec -n 1 ./a.out 0
mpiexec -n 1 ./a.out 1

What's the d_ino in dirent of the root directory and its parent directory?

I am doing an Unix programming exercise to find out the i-node number of a directory and its parent directory, I know that command "ls -ldi" satisfies my requirement but as I said I am doing Unix programming exercise and just want to further understand it so I write the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int
main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if(argc != 2)
fprintf(stderr, "usage: ex1 directory_name");
if((dp = opendir(argv[1])) == NULL)
fprintf(stderr, "can't open %s", argv[1]);
while((dirp = readdir(dp)) != NULL)
if(strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
printf("inode number of %s is %llu\n", dirp->d_name, dirp->d_ino);
closedir(dp);
exit(0);
}
I just check all the entries of a given path and compare if the name is dot or dot-dot, if it is, then print out its d_ino.
Here is what I am confused by:
if I run "./a.out .", this acts as what "ls -ldi .", meaning they both give the i-node number of the current directory and its parent directory, but if I run "./a.out /" expecting to find out the i-node number of the root directory and its parent directory, then my program print the i-node number 2 for "." and 1 for ".." but command "ls -ldi /." and "ls -ldi /.." both print 2.
So I am wondering why this occurs.
Thanks!

Why does reading from STDOUT work?

I encountered a curious case, where reading from STDOUT works, when running a program in terminal. The question is, why and how? Let's start with code:
#include <QCoreApplication>
#include <QSocketNotifier>
#include <QDebug>
#include <QByteArray>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
const int fd_arg = (a.arguments().length()>=2) ? a.arguments().at(1).toInt() : 0;
qDebug() << "reading from fd" << fd_arg;
QSocketNotifier n(fd_arg, QSocketNotifier::Read);
QObject::connect(&n, &QSocketNotifier::activated, [](int fd) {
char buf[1024];
auto len = ::read(fd, buf, sizeof buf);
if (len < 0) { qDebug() << "fd" << fd << "read error:" << errno; qApp->quit(); }
else if (len == 0) { qDebug() << "fd" << fd << "done"; qApp->quit(); }
else {
QByteArray data(buf, len);
qDebug() << "fd" << fd << "data" << data.length() << data.trimmed();
}
});
return a.exec();
}
Here's qmake .pro file for convenience, if someone wants to test above code:
QT += core
QT -= gui
CONFIG += c++11
TARGET = stdoutreadtest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
And here's output of 4 executions:
$ ./stdoutreadtest 0 # input from keyboard, ^D ends, works as expected
reading from fd 0
typtyptyp
fd 0 data 10 "typtyptyp"
fd 0 done
$ echo pipe | ./stdoutreadtest 0 # input from pipe, works as expected
reading from fd 0
fd 0 data 5 "pipe"
fd 0 done
$ ./stdoutreadtest 1 # input from keyboard, ^D ends, works!?
reading from fd 1
typtyp
fd 1 data 7 "typtyp"
fd 1 done
$ echo pipe | ./stdoutreadtest 1 # input from pipe, still reads keyboard!?
reading from fd 1
typtyp
fd 1 data 7 "typtyp"
fd 1 done
So, the question is, what is going on, why do the last two runs above actually read what is typed on terminal?
I also tried looking at QSocketNotifier sources here leading to here, but didn't really gain any insight.
There is no different between fd 0,1,2, all of the three fds is pointing to terminal if not redirected, they are strictly IDENTICAL!
Programs usually use 0 for input, 1 for output, 2 for error, but all of them can be different ways.
Eg, for less, ordinary usage:
prog | less
Now input of less is redirected to the prog, and less can not read any user input from stdin, so how does less get user input like scroll up/down or page up/down ?
Sure less can read user input from stdout, which is exactly what less does.
So you can use these fds wisely when you know how bash handle these fds.

Resources