I 'm writing a little program that implements pipes like they work in the shell.
ie:
ls -hal | sort | grep p | wc
it works fine, with the minor issue that on one line, when CMD_NO=n, the comparison i biggerthan CMD_NO does not work, but i!=(CMD_NO-1) does. I'm trying to figure out why in this particular case (the line is ocmmented as TROUBLED LINE in the code) these statements are not equivalent. Many thanks.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define READ_END 0
#define WRITE_END 1
#define CMDS_NO 5
int main (int argc, char **argv)
{
pid_t pid;
int new_fds[2];
int old_fds[2];
char *array[CMDS_NO];
char *param[CMDS_NO];
array[0]="ls";
array[1]="sort";
array[2]="grep";
array[3]="grep";
array[4]="wc";
param[0]="-hal";
param[1]=NULL;
param[2]="p";
param[3]="out";
param[4]=NULL;
for (int i=0; i<CMDS_NO; i++) {
if (i<CMDS_NO) //if there is a next command
pipe(new_fds);
pid=fork();
if (pid==0) { //if child
if (i!=0) { //if there is ap revoius commmand
dup2(old_fds[0], 0);
close(old_fds[0]);
close(old_fds[1]);
}
if (i!=(CMDS_NO-1)) { //TROUBLED LINE i<CMDS_NO does not work,
//if there is a next command
close(new_fds[0]);
dup2(new_fds[1],1);
close(new_fds[1]);
}
execlp(array[i], array[i], param[i], NULL);
} else {
if (i!=0) { //if there is a previous command
close(old_fds[0]);
close(old_fds[1]);
}
if (i<CMDS_NO) { //if there is a next command
old_fds[0] = new_fds[0];
old_fds[1] = new_fds[1];
}
}
}
if (CMDS_NO>1) {
close(old_fds[0]);
close(old_fds[1]);
}
while (1) { //wait for child processes to end
wait(NULL);
if(errno== ECHILD) {
printf("all children ended\n");
break;
}
}
return 0;
}
The condition i<CMDS_NO will always be true because i runs from 0 to CMDS_NO-1. I think you meant to write your condition as i<CMDS_NO-1. Of course, i!=CMDS_NO-1 is equally valid.
Note that this affects several other places where you have if (i<CMDS_NO); these should also read if (i<CMDS_NO-1).
That's normal.
for (int i=0; i<CMDS_NO; i++) {
This means "loop as long as i is less than CMDS_NO". As soon as i == CMDS_NO the loop will stop; so, inside the loop, the highest i will ever reach is CMDS_NO - 1.
PS: CMDS_NO is a really poor variable name, call it MAX_COMMANDS for example
Related
I've written the following program, that simulates the work of semaphore. There are three functions: lock, unlock, lockpath.
lock = opens the file; checks if the file already exists, and if it does, puts the current process to sleep. If the file didn't exist, it is created and TRUE is returned.
unlock = deletes the file
lockpath = returns the path name corresponding to the file that might be created.
Here's the source code:
#include <unistd.h>
//exit();
#include <stdlib.h>
//errno
#include <errno.h>
//creat(..)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//strcat, strcpy
#include <string.h>
//For err_sys
#include <stdio.h>
#define LOCKDIR "/tmp/"
#define MAXTRY 3
#define WAITTIME 5
enum BOOLEAN{TRUE, FALSE};
void err_sys(const char* x) {
perror(x);
exit(1);
}
static char* lockpath(char* name) {
static char path[20];
strcpy(path, LOCKDIR);
return (strcat(path, name));
}
int lock(char* name) {
char *path;
int fd, incerc;
extern int errno;
path = lockpath(name);
int try = 0;
while ((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0
&& errno == EEXIST) {
if (++try >= MAXTRY)
return FALSE;
sleep(WAITTIME);
}
if (fd < 0 || close(fd) < 0)
err_sys("lock");
return TRUE;
}
void unlock(char* name) {
if (unlink(lockpath(name)) < 0)
err_sys("unlock");
}
int main(void) {
pid_t child_process;
child_process = fork();
char* sem_file_name = "test_semaf";
if (child_process != 0)
{
printf("\nParent process ID: %d", getpid());
}
else
{
printf("\nChild process ID: %d", getpid());
}
if (lock(sem_file_name))
{
printf("\nProcess with ID: %d", getpid());
printf("\nonly, has access to %s", strcat(LOCKDIR, sem_file_name)); //****
unlock(sem_file_name);
} else {
printf("\nProcess with ID: %d", getpid());
printf("\nwas unable to get access to %s", strcat(LOCKDIR, sem_file_name));
}
return 0;
}
The line at which the program stops is marked with: ****
The error is:
Program received signal SIGSEGV, Segmentation fault.
__strcat_ssse3 () at ../sysdeps/x86_64/multiarch/strcat-ssse3.S:571
571 ../sysdeps/x86_64/multiarch/strcat-ssse3.S: No such file or directory.
The problem is that I get Segmentation Fault, and can't find where's the problem. To me, everything's fine. A process is supposed to create file X. Then, if another process tries to create it's own file X, it is not allowed; the process is put to sleep. This second process is allowed to make MAXTRY attempts. If it does not succeed after MAXTRY attempts, the lock() function returns FALSE. Finally, when a process, that has successfully created his own X file, doesn't need it now, the file X is deleted.
Can you, please, tell what do you think is the problem with this program? Thank you in advance.
EDIT :
Here's the link to the page that explains why lockpath() function isn't correct.
Is returning a pointer to a static local variable safe?
This is the cause of your crashes:
strcat(LOCKDIR, sem_file_name)
Here you try to append to a literal string constant.
You should use the lockpath function here as well.
The problem seems to be in your misunderstanding of strcat() function. The function appends string in second parameter to the string in first parameter - but you need to ensure there is enough space for the data. Read the man page.
That means that
char * dest = "whatever";
strcat(dest, anything_else);
is always wrong. What you want is
char dest[SIZE] = "whatever";
strcat(dest, anything_else);
where SIZE is big enough for the buffer to be able to contain the whole concatenated string.
Also, your lockpath() function is broken. See this answer to learn why. You need to create the dest buffer outside the lockpath() function and pass it to it as a parameter.
I need some help with a simple shell for class, and I'm worried I don't quite understand how the execvp() function works.
The shell does not do much, does not support piping, redirection, scripting or anything fancy like that. It only reads a command, reads in the options (with the command as option[0]), and forks.
It worked a few times, then started giving me errors about not being able to find commands. Other similar questions posted here had to do with piping or redirection.
Please forgive the noobcode, it's not pretty, but I hope it's legible:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#define OPT_AMT 10
const size_t SIZE = 256;
int i = 0;
int o = 0;
int main(void) {
// initializing data
int exit = 0;
char cwd[SIZE];
char cmd[SIZE];
char input[SIZE * OPT_AMT];
char *opt[OPT_AMT];
getcwd(cwd, SIZE);
// main loop
while (exit == 0) {
// reset everything
o = 1;
i = 0;
cmd[0] = "\0";
while (i < OPT_AMT) {
opt[i++] = "\0";
}
// get input
printf("%s $ ", cwd);
scanf("%s", cmd);
gets(input);
opt[0] = cmd;
char *t = strtok(input, " ");
while (t != NULL) {
opt[o++] = t;
t = strtok(NULL, " ");
}
// if exit, exit
if (strcmp(cmd, "exit") == 0) {
exit = 1;
}
// else fork and execute
else {
pid_t pID = fork();
if (pID == 0) { // child process
execvp(cmd, opt);
} else if (pID < 0) { // failed to fork
printf("\nFailed to fork\n");
} else { // parent process
wait(0);
}
}
}
// cleanup
printf("\nFinished! Exiting...\n");
return 0;
}
Anything blatantly wrong? I most recently added the exit condition and the resetting the options array.
Also, this is my first question, so remind me of any rules I may have broken.
For starters, this
cmd[0] = "\0";
ought to be
cmd[0] = '\0';
Listen to your compiler's warnings.
To enable them use the options -Wall -Wextra -pedantic (for gcc).
Also you might better want to initalise opt's elements to point to "nothing", that is NULL but to the literal "\0":
while (i < OPT_AMT) {
opt[i++] = NULL;
}
as execvp() requires opt to be a NULL-terminated array of C-"strings" (thanks Paul for mentioning/wording the relevant background).
Also^2: Do not use gets(), as it's evil and not even part of the C Standard anymore. Instead of
gets(input);
use
fgets(input, sizeof input, stdin);
gets() easyly let's the user overflow the (input) buffer passed. (Mentioning this came to my mind without Paul, btw ... ;-))
I have a little problem here. I know Linux limits the number of threads of an user can actually run.
I'm using pthread_create and an array of pthread_t limited with 50 ( pthread_t tid[50]; ). I have a for cycle that each time that limit reaches 50 every thread on pthread_t array is killed.
How? I tested almost everything. with pthread_kill(tid[w],SIGKILL); w is a simple cycle control variable goes from 0 to 50. I already tested pthread_cancel(tid[w]); and the problem keeps.
So what is the problem?
Everytime I reach 380 thread number I can't create more. But I'm killing with cancel or kill. So what is happening?
The objective of the program is a network scanner. To be faster I need like 500 threads with like 2 seconds of timeout to test IP's and ports.
Anyone knows how to "go arround" this problem?
I thought that I could kill the thread it would solve the problem but I was wrong :(
Without use ulimit or in /proc/sys/kernel/threads_max changing values, I looked at pthread_attr_setstacksize but I'm a bit confused :P
any ideas?
EDIT
The code as requested :P
I'm going to put ALL code here:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#ifndef SOL_TCP
#define SOL_TCP 6
#endif
#ifndef TCP_USER_TIMEOUT
#define TCP_USER_TIMEOUT 18 //retry
#endif
#define MAX_TH 250
struct ar_stc{
char* ip;
int port;
};
char* ret[2];
int porar[2];
pthread_t tid[MAX_TH];
void create_port_scan_th(char* host,int p,int j);
//cares about args.
//this is not helpful for the threads post on stackoverflow. skip this function
char** arguments_handle(int argc,char **arg)
{
char p[]="-p";
char h[]="-h";
size_t _p,_h;
_p=(size_t)strlen(p);
_h=(size_t)strlen(h);
if(argc!=5)
{
printf("Usage:./file -p PORT-RANGE -h HOST.IP\n");
exit(1);
}
if(strncmp(arg[1],p,_p)==0 || strncmp(arg[1],h,_h)==0 && strncmp(arg[3],p,_p)==0 || strncmp(arg[3],h,_h)==0)
{
if(strncmp(arg[1],p,_p)==0)
{
strncpy(ret[0],arg[2],strlen(arg[2]));
}
else
{
strncpy(ret[1],arg[2],strlen(arg[2]));
}
if(strncmp(arg[3],h,_h)==0)
{
strncpy(ret[1],arg[4],strlen(arg[4]));
}
else
{
strncpy(ret[0],arg[4],strlen(arg[4]));
}
}
return ret;
}
int* take_ports(char *arg)
{
char* ports[2];
ports[0] = malloc(5);
ports[1] = malloc(5);
memset(ports[0],0,5);
memset(ports[1],0,5);
char tmp[5];
int len = strlen(arg);
int i,j=0,x=0;
char min_p[5],max_p[5];
for(i=0;i<len;i++)
{
if(arg[i]=='-')
{
min_p[x]='\0';
j=1;
x=0;
continue;
}
else
{
if(j==0)
min_p[x]=arg[i];
else
max_p[x]=arg[i];
}
x++;
}
max_p[x]='\0';
porar[1]=atoi(max_p);
porar[0]=atoi(min_p);
free(ports[0]);
free(ports[1]);
return porar;
}
void *check_port(void* ar_p)
{
struct ar_stc *ar =ar_p;
char* ip = ar->ip;
int port = ar->port;
int s,conexao;
int timeout = 1000; //1 second timeout
s=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in dst;
setsockopt(s,SOL_TCP,TCP_USER_TIMEOUT,(char*)&timeout,sizeof(timeout)); //NOT WORKING :(
if(s<0)
{
printf("\nCouldnt create socket\nPremissions maybe?\n");
exit(1);
}
dst.sin_family = AF_INET;
dst.sin_port = htons(port);
dst.sin_addr.s_addr = inet_addr(ip);
bzero(&(dst.sin_zero),8);
//printf("\nChecking: %d...",port);
conexao = connect(s,(struct sockaddr*)&dst,sizeof(dst));
if(conexao <0)
{
printf("TCP/%d:CLOSED!\n",port); //just to make sure the thread is running
close(s);
return;
}
else
{
printf("TCP/%d:OPEN!\n",port);
close(s);
return;
}
}
int main(int argc, char **argv)
{
int open_ports[65535];
int open_ports_count=0;
int min_p,max_p;
int* p;
ret[0] = malloc(20);
ret[1] = malloc(20);
memset(ret[0],0,20);
memset(ret[1],0,20);
char** ipnport;
ipnport = arguments_handle(argc,argv);
printf("The IP is :%s and the range is %s\n",ipnport[1],ipnport[0]);
p=take_ports(ipnport[0]);
min_p=p[0];
max_p=p[1];
printf("Min port:%d e max port:%d\n",min_p,max_p);
int i;
int thread_count=-1;
for(i=min_p;i<=max_p;i++)
{
thread_count++;
create_port_scan_th(ipnport[1],i,thread_count);
if(thread_count>=MAX_TH)
{
sleep(1);
thread_count=0;
int w;
for(w=0;w<=MAX_TH;w++)
{
pthread_kill(tid[w],SIGKILL);
}
}
}
free(ret[0]);
free(ret[1]);
return 0x0;
}
void create_port_scan_th(char* host,int p,int j)
{
int error;
struct ar_stc *ar;
ar = malloc(sizeof(*ar));
ar->ip=host;
ar->port=p;
error = pthread_create(&(tid[j]),NULL,&check_port,(void*)ar);
if(error!=0)
printf("\nError creating thread:%s\n",strerror(error));
}
But I'm killing with cancel or kill.
First of all, pthread_kill does not kill or end a thread.
(see more at pthread_kill doesnt kill thread C linux or When to use pthread_cancel and not pthread_kill).
If you send SIGKILL to a thread, the entire process will end.
To end a thread, you need to
Make the thread end.
by returning from the thread function, or
calling pthread_exit or
pthread_cancel the thread
Dispose the resources tied to the thread by:
Call pthread_join() on the thread or
make the thread a detached thread.
If you opt for the last point by making the thread detached - which will automatically release the thread when it ends , you can call pthread_detach(pthread_Self()) at the start of your thread function.
Or supply a pthread_attr_t when you call pthread_create(), where you set the thread to a detached state.
As for the total number of threads you can use, linux have a limit on the total number of threads/processes any user can have running.
You can view this with the command ulimit -u
I have a question I am writing a code that find the perfect number by brute forcing the algorithm which is required by my assignment. I want to see how far the ranges goes in 15 seconds. I tried using a while loop and an alarm but it seems to not work at all. How would I go from there?
Thanks
Heres my code:
#define _POSIX_SOURCE
#define _BSD_SOURCE
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
volatile int stop=0;
void sigalrm_handler( int sig ){
stop = 1;
}
int main(int argc, char **argv){
struct sigaction sact;
int num_sent = 0;
sigemptyset(&sact.sa_mask);
sact.sa_flags = 0;
sact.sa_handler = sigalrm_handler;
sigaction(SIGALRM, &sact, NULL);
alarm(15); /* Request SIGALRM in 60 seconds */
while (!stop) {
for (;;){
for (;;){
}
}
}
printf("%d \n", num_sent);
exit(0);
}
Even if the alarm gets triggered and set stop to a non-zero value you won't notice since your for loop doesn't return to the outer while. You need to apply the condition to all loops that should be stopped:
while (!stop) {
for (;!stop;){
for (;!stop;){
}
}
}
An alternative to alarm is simply checking whether you crossed a certain timepoint:
time_t end = time(0) + 15;
while (end < time(0)) {
for (;end < time(0);){
for (;end < time(0);){
}
}
}
Basically I have created a shell using standard POSIX commands, I want to be able to Implement Piping as well. Right now it handles commands correctly, and can do background processing with &. But I need to be able to pipe using | and >> as well.
For example something like this:
cat file1 file2 >> file3
cat file1 file2 | more
more file1 | grep stuff
Here is the code I have currently. I also want to AVOID "SYSTEM" calls. I know U need to use dup2, but the way I did my code is a bit odd, so im hoping if someone can tell me if it is feasible to implement pipes in this code? thanks! I know dup2 is used, but also im def. confused at how to implement >> as WELL as |
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
void Execute(char* command[],bool BG)
{
//Int Status is Used Purely for the waitpid, fork() is set up like normal.
int status;
pid_t pid = fork();
switch(pid)
{
case 0:
execvp(command[0], command);
if(execvp(command[0], command) == -1)
{
cout << "Command Not Found" << endl;
exit(0);
}
default:
if(BG == 0)
{
waitpid(pid, &status, 0);
//Debug cout << "DEBUG:Child Finished" << endl;
}
}
}
bool ParseArg(char* prompt, char* command[], char Readin[],bool BG)
{
fprintf(stderr, "myshell>");
cin.getline(Readin,50);
prompt = strtok(Readin, " ");
int i = 0;
while(prompt != NULL)
{
command[i] = prompt;
if(strcmp(command[i], "&") == 0){
//Debug cout << "& found";
command[i] = NULL;
return true;
}
//Debug cout << command[i] << " ";
i++;
prompt = strtok(NULL, " ");
}
return false;
}
void Clean(char* command[])
{
//Clean Array
for(int a=0; a < 50; a++)
{
command[a] = NULL;
}
}
int main()
{
char* prompt;
char* command[50];
char Readin[50];
bool BG = false;
while(command[0] != NULL)
{
Clean(command);
BG = ParseArg(prompt, command, Readin, BG);
if(strcmp(command[0], "exit") == 0 || strcmp(command[0], "quit") == 0 )
{
break;
}
else
{
Execute(command,BG);
}
}
return 1;
}
Pipes and redirections are different, actually. To implement a redirection (such as >>) you have to use dup2 indeed. First, open the desired file with appropriate flags (for >> they'll be O_WRONLY|O_CREAT|O_APPEND). Second, using dup2, make stdout (file descriptor 1) a copy of this newly opened fd. Finally, close newly opened fd.
To create a pipe, you'll need a pipe syscall. Read its manpage, it contains example code. Then you'll also need dup2 to make file descriptors returned by pipe be stdin for one process and stdout for another, respectively.
You should be able to implement pipes and output redirection with your shell, but there are a few things I noticed:
Your code for reading input, parsing, and output are mixed together, you may want to separate this functionality.
strtok won't work very well as a parser for shell commands. It will work for very simple commands, but you may want to look into creating or finding a better parser. A command like echo "hello world" will be problematic with your current parsing method.
You may want to create a simple structure for holding your parsed commands.
Here is some pseudocode to get you started:
#define MAX_LINE 10000
#define MAX_COMMANDS 100
#define MAX_ARGS 100
// Struct to contain parsed input
struct command
{
// Change these with IO redirection
FILE *input; // Should default to STDIN
FILE *output; // Should default to STDOUT
int num_commands;
int num_args[MAX_COMMANDS]; // Number of args for each command
char* command_list[MAX_COMMANDS]; // Contains the programs to be run
char* args_list[MAX_COMMANDS][MAX_ARGS]; // The args for each command
boolean background_task;
boolean append;
}
int main()
{
char input[MAX_LINE];
while (1)
{
struct command cmd;
print_prompt();
read_input(input);
parse_input(input, &cmd);
execute(&cmd);
}
}
Good luck with this project!