Implementing a custom command in a basic shell(in C) - linux

I need to implement a custom command in a shell .The goal is to support a command program_name m that creates a child process to execute program_name, but aborts the process if it does not complete its operation in m seconds.
Actually I am checking the status of waitpid(child_pid,&exit_status,WUNTRACED) everytime ,but the code segment in the for loop is not working and is not aborting the process!!
Can anyone suggest me an appropriate routine from the library to deliver a SIGALRM signal after m seconds, and use a signal handler to perform appropriate actions?
Thanks in advance!!
int child_pid = fork();
if (child_pid < 0) {
perror("ERROR: could not fork process.\n");
}
if (child_pid == 0) {
char *args[4];
args[0] = path;
args[1] = "-c";
args[2] = command_line;
args[3] = (char *) 0;
//executing the command
int exec_return = execvp(path, args);
if (exec_return == -1) {
perror("error: command execution failed!\n");
} else {
exit(exec_return);
}
} else {
//assigning cur_fg_pid to the child
cur_fg_pid = child_pid + 1;
if (cur_fg_cmd == NULL) { cur_fg_cmd = (char *) malloc(sizeof(char)); }
strcpy(cur_fg_cmd, command_line);
int exit_status;
while (can_wait == 1 && waitpid(child_pid, &exit_status, 0) > 0) {}
cur_fg_pid = -1;
cur_fg_cmd = NULL;
if (can_wait == 1) latest_jobid = -1;
if(global_time_flag)
{
for (i = 0; i < stip_time; i++) {
if (waitpid(child_pid,&exit_status,WUNTRACED) > 0)
if (WIFSTOPPED(exit_status)) {
break;
} else {sleep(1);}
}
if(!WIFSTOPPED(exit_status ))
kill (child_pid, SIGUSR1);
}
}

Related

Heap buffer overflow error, Leetcode problem 941, Valid Mountain Array, using C

I am currently learning c and trying to do some problems on leetcode to better myself.
The problem: https://leetcode.com/problems/valid-mountain-array/
I am getting an error as such, error message apperently a read error.
However whenever i run my code on my pc i don't get any errors, even using valgrind.
Here is my code:
bool validMountainArray(int* arr, int arrSize)
{
bool is_m_array = false;
bool peek = false;
int peek_point = 0;
int end_of_slope = 0;
int k = 0;
if( arrSize >= 3)
{
while (arr[k] < arr[k+1] && arr[k] < arrSize)
{
k++;
}
peek = true;
peek_point = k;
}
if (peek == true)
{
while(arr[peek_point] > arr[peek_point+1] && arr[peek_point] < arrSize)
{
peek_point++;
end_of_slope = peek_point+1;
printf("end Of SLOPE %d, arrSize %d \n", end_of_slope, arrSize);
}
}
if (peek == true && end_of_slope == arrSize)
{
is_m_array = true;
}
return is_m_array;
}
I have tried several different inputs and they all seem to work just fine!
For example:
int main(int argc, char const *argv[])
{ int arr[9]= {1,2,3,4,5,4,3,2,1};
if (validMountainArray(arr, 9) == true)
{
printf("True");
}
else
{
printf("False");
}
return 0;
}
Will return True.
Anyone got any ide what i am missing here?

Problems with ptrace(PTRACE_ME,...) and subsequent wait

I am porting a debugger, 'pi' ('process inspector') to Linux and am
working on the code for fork/exec of a child to inspect it. I am
following standard procedure (I believe) but the wait is hanging.
'hang' is the procedure which does the work, the 'cmd' argument being
the name of the binary (a.out) to trace:
int Hostfunc::hang(char *cmd){
char *argv[10], *cp;
int i;
Localproc *p;
struct exec exec;
struct rlimit rlim;
i = strlen(cmd);
if (++i > sizeof(procbuffer)) {
i = sizeof(procbuffer) - 1;
procbuffer[i] = 0;
}
bcopy(cmd, procbuffer, i);
argv[0] = cp = procbuffer;
for(i = 1;;) {
while(*cp && *cp != ' ')
cp++;
if (!*cp) {
argv[i] = 0;
break;
} else {
*cp++ = 0;
while (*cp == ' ')
cp++;
if (*cp)
argv[i++] = cp;
}
}
hangpid = fork();
if (!hangpid){
int fd, nfiles = 20;
if(getrlimit(RLIMIT_NOFILE, &rlim))
nfiles = rlim.rlim_cur;
for( fd = 0; fd < nfiles; ++fd )
close(fd);
open("/dev/null", 2);
dup2(0, 1);
dup2(0, 2);
setpgid(0, 0);
ptrace(PTRACE_TRACEME, 0, 0, 0);
execvp(argv[0], argv);
exit(0);
}
if (hangpid < 0)
return 0;
p = new Localproc;
if (!p) {
kill(9, hangpid);
return 0;
}
p->sigmsk = sigmaskinit();
p->pid = hangpid;
if (!procwait(p, 0)) {
delete p;
return 0;
}
if (p->state.state == UNIX_BREAKED)
p->state.state = UNIX_HALTED;
p->opencnt = 0;
p->next = phead;
phead = p;
return hangpid;
}
I put the 'abort()' in to catch a non-zero return from ptrace,
but that is not happening. The call to 'raise' seems to be a
common practice but a cursory look at gdb's code reveals it is
not used there. In any case it makes no difference to the outcome.
`procwait' is as follows:
int Hostfunc::procwait(Localproc *p, int flag){
int tstat;
int cursig;
again:
if (p->pid != waitpid(p->pid, &tstat, (flag&WAIT_POLL)? WNOHANG: 0))
return 0;
if (flag & WAIT_DISCARD)
return 1;
if (WIFSTOPPED(tstat)) {
cursig = WSTOPSIG(tstat);
if (cursig == SIGSTOP)
p->state.state = UNIX_HALTED;
else if (cursig == SIGTRAP)
p->state.state = UNIX_BREAKED;
else {
if (p->state.state == UNIX_ACTIVE &&
!(p->sigmsk&bit(cursig))) {
ptrace(PTRACE_CONT, p->pid, 1, cursig, 0);
goto again;
}
else {
p->state.state = UNIX_PENDING;
p->state.code = cursig;
}
}
} else {
p->state.state = UNIX_ERRORED;
p->state.code = WEXITSTATUS(tstat) & 0xFFFF;
}
return 1;
}
The 'waitpid' in 'procwait' just hangs. If I run the program with
the above code, and run a 'ps', I can see that 'pi' has forked
but hasn't yet called exec, because the command line is still
'pi', and not the name of the binary I am forking. I discovered
that if I remove the 'raise', 'pi' still hangs but 'ps' now
shows that the forked program has the name of the binary being
examined, which suggests it has performed the exec.
So, as far as I can see, I am following documented procedures to
take control of a forked process but it isn't working.
Noel Hunt
I have found the problem (with my own code, as Nate pointed out), but the cause was obscure until I ran 'strace pi'. It was clear from that that there was a SIGCHLD handler, and it was executing a wait. The parent enters wait, SIGCHLD is delivered, the handler waits and thus reaping the status of the child, then wait is restarted in the parent and hangs because there is no longer any change of state. The SIGCHLD handler makes sense because the pi wants to be informed of state changes in the child. The first version of 'pi' I got working was a Solaris version, and it uses /proc for process control so there was no use of 'wait' to get child status, hence I didn't see this problem in the Solaris version.

Futex Error in C application that is using mutex and epoll

I am running epoll to process network connection. Everything is working perfectly I think.
Now i am trying to connect to the Postgresql Database from the child process. I have 4 child process.
Sometimes when i try to connect to the server. It hangs.
Sometimes i get this error
fserver: tpp.c:84: __pthread_tpp_change_priority: Assertion `new_prio
Would appreciate it if someone would be able to advice on my code. Thanks
If i remove the Postgresql Connection code , the problem disappears.
/******CHILD PROCESS **************/
void childProcess()
{
const char conninfo[] = "postgresql://postgres#localhost?port=5432&dbname=ram&password=xxx";
PGconn *conn = PQconnectdb(conninfo);
const ConnStatusType connStatusType = PQstatus(conn);
if (connStatusType == CONNECTION_BAD) {
printf("pg connection not OK");
if (conn) {
PQfinish(conn);
}
exit(1);
} else {
printf("pg connection OK");
}
int efd = epoll_create1(0);
if(efd == -1)
{
perror("Epoll Creation Failed\n");
}
nonblocksocket(&p2c_var);
struct epoll_event event0;
event0.data.fd = p2c_var;
event0.events = EPOLLIN | EPOLLET;
if(epoll_ctl(efd,EPOLL_CTL_ADD,p2c_var,&event0) == -1)
{
perror("First Failed to add file descriptor to epoll watch list\n");
}
nonblocksocket(&c2p_var);
struct epoll_event event1;
event1.data.fd = c2p_var;
event1.events = EPOLLOUT | EPOLLET;
if(epoll_ctl(efd,EPOLL_CTL_ADD,c2p_var,&event1) == -1)
{
perror("Second Failed to add file descriptor to epoll watch list\n");
}
struct epoll_event *ttlevents;
ttlevents = calloc(MAXEVENTS, sizeof(event0));
int head = 0,tail = 0;
pthread_mutex_t buflock;
pthread_mutex_t fdlock;
int bufhead=0,buftail=0;
struct fifoarr *fifoptr = (struct fifoarr *) calloc(QSIZE,sizeof(struct fifoarr));
int co = 0;
char st[1050];
memset(st,0,sizeof(st));
st[0] = 1;
while(1)
{
int eventcount = epoll_wait(efd,ttlevents,MAXEVENTS,-1);
for(int i =0;i<eventcount;i++)
{
if ((ttlevents[i].events & EPOLLERR) || (ttlevents[i].events & EPOLLHUP))
{
/* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */
fprintf (stderr, "epoll error\n");
close (ttlevents[i].data.fd);
continue;
}
if(ttlevents[i].events & EPOLLOUT)
{
if(ttlevents[i].data.fd == c2p_var)
{
pthread_mutex_lock(&buflock);
int bufval = popfd(&bufhead,&buftail);
if(bufval != -1)
{
write(c2p_var,fifoptr[bufval].buffer,sizeof(fifoptr[bufval].buffer));
}
pthread_mutex_unlock(&buflock);
}
}
if(ttlevents[i].events & EPOLLIN)
{
if(ttlevents[i].data.fd == p2c_var)
{
char buffer[1050];
while(1)
{
memset(buffer,0,sizeof(buffer));
int c = read(ttlevents[i].data.fd,buffer,sizeof(buffer));
if(c == -1)
{
if(errno == EAGAIN)
{
printf("Completed Reading From Parent Process\n");
break;
}
}
if(c == 0)
{
printf("Parent terminated Connection.\n");
break;
}
if(buffer[0] != 1)
{
pthread_mutex_lock(&buflock);
int bufval = pushfd(&bufhead);
if(bufval != -1)
{ memset(fifoptr[bufval].buffer,0,sizeof(fifoptr[bufval].buffer)); memcpy(fifoptr[bufval].buffer,buffer,sizeof(buffer));
// processRequest(fifoptr[bufval].buffer,conn);
write(c2p_var,&st,sizeof(st));
}
pthread_mutex_unlock(&buflock);
}//buffer[0]
}//While
}
}//if epollin
} //for
}//while(1)
PQfinish(conn);
}
The program tends to hang.
Well it is working now.
It seems that mutex is the cause of the problem.
Thanks for all that looked at my code.

Looping a fork()

This is a sample of my code for some piping I want to do. The problem is that pid2[0] does not supply me a child process. How do I fix it? pid2[1] and pid2[2] and so on do supply the parent with children.
int numCommands = numPipes + 1; /// not worrying about '>' and '<' right now
int *pipes = newint[numPipes*2]; /// two ends for each pipe
for(int i = 0; i < numPipes*2; i+=2) /// Offset by two since each pipe has two ends
pipe(pipes + i);
int *pid2 = new int [numCommands];
for(int i = 0; i < numCommands; i++)
{
pid2[i] = fork();
if(pid2[i] < 0)
{
std::cerr << "Failure to fork..." << std:endl;
return EXIT_FAILURE
}
if(pid2[i] == 0) /// Child process
{
if(i == 0) /// First Command
{
dup2(pipes[1], 1);
}
else if(i == numCommands -1) /// Last Command
{
dup2(pipes[2*(numCommands-1)-1], 0);
}
else /// Middle commands
{
dup2(pipes[2*(i-1)], 0);
dup2(pipes[(2*i)+1],1);
}
for(int j = 0; j < numPipes*2;j++)
close(pipes[j]);
execvp(pipeCommands[i][0], pipeCommands[i].data()); ///pipeCommands is a vector<vector<char*>>
perror("exec failed");
return EXIT_SUCCESS;
}
else /// The parent
{
for(int j = 0; j <numPipes*2;j++)
close(pipes[j]);
for(int k = 0; k < numCommands; k++)
waitpid(pid2[k],nullptr,0);
}
}
Your indexing into the pipes array is a little bit problematic. For sort file.txt | head | wc I'm assuming that numPipes is 2. Let's walk through your for loop for each value of i.
i==0
dup2(pipes[1], 1); // Send stdout to pipes[1]
i==1
dup2(pipes[2*(i-1)], 0); // dup2(pipes[0], 0), stdin from pipes[0]
dup2(pipes[(2*i)+1],1); // dup2(pipes[3], 1), stdout to pipes[3]
i == 2
dup2(pipes[2*(numCommands-1)-1], 0); //dup2(pipes[3], stdin from pipes[3]
In other words, any stdout from process 0 is going to a dead end. The second process will never read from its standard output. So the debug statement you put in there (cout == stdout, remember) will get lost as well.

libusb_bulk_transfer() read hangs after first successful libusb_bulk_transfer() write on USB mass storage device

I am trying to perform write/read libusb_bulk_transfer() on my USB mass storage device. But after the first successful libusb_bulk_transfer() write, my program just hangs and does not perform a libusb_bulk_transfer() read. I observe that my USB device gets detached. Why am I not able to perform a read?
Following is a snippet of my code:
e = libusb_get_configuration(handle, &config2);
if (e!=0)
{
printf("\n***Error in libusb_get_configuration\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
printf("\nConfigured value : %d", config2);
if (config2 != 1)
{
libusb_set_configuration(handle, 1);
if (e!=0)
{
printf("Error in libusb_set_configuration\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
else
printf("\nDevice is in configured state!");
}
if (libusb_kernel_driver_active(handle, 0) == 1)
{
printf("\nKernel Driver Active");
if (libusb_detach_kernel_driver(handle, 0) == 0)
printf("\nKernel Driver Detached!");
else
{
printf("\nCouldn't detach kernel driver!\n");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
}
e = libusb_claim_interface(handle, 0);
if (e < 0)
{
printf("\nCannot Claim Interface");
libusb_free_device_list(devs, 1);
libusb_close(handle);
return -1;
}
else
printf("\nClaimed Interface\n");
char *Report_to_write, *Report_to_read;
int transferred = 0;
int received = 0;
int nbytes = 8; // As protocol suggested it should be 8 bytes
Report_to_write = (char *)malloc(nbytes);
Report_to_read = (char *)malloc(nbytes);
Report_to_write[0] = 0x01; // cmd
Report_to_write[1] = Report_to_write[2] = Report_to_write[3] = 15; // HOUR
Report_to_write[4] = Report_to_write[5] = Report_to_write[6] = 30; // MIN
Report_to_write[7] = 255; // some checksum
memset(Report_to_read, '\0', 8);
e = libusb_bulk_transfer(handle, BULK_EP_OUT, Report_to_write, 8, &transferred, 0);
if (e == 0 && transferred == 8)
{
printf("\nWrite successful!");
printf("\nSent %d bytes with string: %s\n", transferred, Report_to_write);
}
else
printf("\nError in write! e = %d and transferred = %d\n", e, transferred);
e = libusb_bulk_transfer(handle, BULK_EP_IN, Report_to_read, 8, &received, 0); //64: Max Packet Length
if (e == 0)
{
printf("\nReceived: ");
printf("%c", Report_to_read[1]); //Will read a string
//sleep(1);
}
else
{
printf("\nError in read! e = %d and received = %d\n", e, received);
return -1;
}
e = libusb_release_interface(handle, 0);
libusb_free_device_list(devs, 1);
libusb_close(handle);
libusb_exit(NULL);
Naming and strings look very similar to the code in Stack Overflow question Read/write on a pen drive using libusb: libusb_bulk_transfer() (written by me).
Observing your code, I can only predict that you are not using the right end point addresses.

Resources