C Unix Xcode bug again - c

I am doing a university project, we have to use the Unix system call.
Right now, I'm really struggling to understand if, in my project, there really is a mistake. This is because, while in terminal it compiles and it starts and finishes without error, on xcode I get several errors.
In particular, I get errors when using semaphores.
I'll try to explain what errors, I receive, but since I'm not native English speakers forgive me in advance if I make some mistakes.
First, the program creates a number of child processes with a fork (). It does depending on how many clientei.txt located (i = iterator).
Immediately I block parent with a semaphore, I run the child up to a certain point, then I block it with a semaphore and I restart the parent.
At this point, the parent should read a message sent by his son, call a function to print the content inside a log.txt and restart the son.
Then the child does other things (including erase the message) and it block.
The parent restart, and everything is repeated for subsequent children.
While in terminal synchronization is perfect (everything happens at the right time without error) this both Linux and Mac, about XCode I had several errors:
semop: Resource temporarily unavailable (if I created more than 5 txt)
semop: File too large (if I created more than 2)
with 2 instead gave me two errors:
semop 1: Interrupted system call (this stops after running both processes)
semop 3: Identifier removed (with this in restarting the second process)
is not so much time that I do C then I do not know what to do. I would like first of all to know if I have to worry (so there is an error), or I have to be quiet because it is a bug in xcode.
If there was a mistake I kindly ask you not to ask me to change the code a lot.
This is mainly because they are close to expiring and I can not afford to do it all again.
I also ask you, if you can, to be as clear as possible. I understand enough English, but not as a mother-tongue, I can not always follow the responses here on StackOverflow.
The code is here:
https://www.dropbox.com/s/2utsb6r5d7kzzqj/xcode%2Bterminal.zip?dl=0
this zip contain a small part of the project that has this problem.
the terminal version works. there is a makefile in this version to simplify the compilation.
xcode version does not work. It contains the Debug folder. Indeed xcode, txt files, it does not read from the root folder where the codes are contained in the folder where it creates the compiled. There is a readme in each case with the procedure in detail.
I tried to minimize, I commented all in English.
I removed the code that was not needed, but I added the file with all the include and functions that use.
here the code:
main.c
key_t key, key_2;
int semid, semid_2;
union semun arg;
union semun arg_2;
struct sembuf sb_2 = {0, -1, 0};
char* nome_file;
nome_file = (char*) malloc(sizeof(char*));
int numero_clienti;
//semaphore for all the child
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
//cretion of first SEMAPHORE
{
//key creation
if ((key = ftok("cliente0.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid = semget(key, numero_clienti, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of all child semaphore
for (i_c = 0; i_c < numero_clienti; i_c++) {
arg.val = 0;
if (semctl(semid, i_c, SETVAL, arg) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
}
//cretion of second SEMAPHORE
{
//key creation
if ((key_2 = ftok("cliente1.txt", 'J')) == -1)
{
perror("ftok");
exit(EXIT_FAILURE);
}
//creation of the semaphore
if ((semid_2 = semget(key_2, 1, 0666 | IPC_CREAT | IPC_EXCL)) == -1)
{
perror("semget");
exit(EXIT_FAILURE);
}
//set value of parent semaphore
arg_2.val = 0;
if (semctl(semid_2, 0, SETVAL, arg_2) == -1)
{
perror("semctl");
exit(EXIT_FAILURE);
}
}
while(fd > 0 && pid > 0){
j++;
close(fd);
pid = fork();
if(pid != 0)
{
i++;
sprintf(nome_file, "./cliente%d.txt", i);
fd = open(nome_file, O_RDONLY);
}
switch(pid)
{
//error case
case -1:
{
perror("Error during fork.");
exit(EXIT_FAILURE);
break;
}
//child case
case 0:
{
puts("Child: I'm a child");
messaggio(numero_clienti, j);
puts("Child: I have to do something");
//Start parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
//, stop itself
sb[j].sem_op = -1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
printf("Child: I have to do something else %d\n", getpid());
_exit(EXIT_SUCCESS);
break;
}
//parent case
default:
{
puts("Parent: I'm a parent");
//Stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop padre");
exit(1);
}
puts("Parent: now I can send the message, my child is blocked");
//restart child
sb[j].sem_op = 1;
if (semop(semid, &sb[j], 1) == -1)
{
perror("semop");
exit(1);
}
//stop itself
sb_2.sem_op = -1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("Parent: end of while");
break;
}
}
}
puts("Parent: I can restart all my child");
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_op = 1;
if (semop(semid, &sb[i_c], 1) == -1)
{
perror("semop");
exit(1);
}
}
puts("I wait the end of my child...");
while (wait(NULL) != -1);
puts("All child end");
//remove semaphore I create
if (semctl(semid, 0, IPC_RMID, arg) == -1)
{
perror("semctl");
exit(1);
}
if (semctl(semid_2, 0, IPC_RMID, arg_2) == -1)
{
perror("semctl");
exit(1);
}
puts("FINE");
return 0;
}
cliente.c
#include "cliente.h"
/**
inside this function child do some thing.
1. at this point it give control to parent after it create a message
2. at this point it remove the message
*/
void messaggio(int numero_clienti, int num_j){
key_t key, key_2;
int semid, semid_2;
struct sembuf sb[numero_clienti];
int i_c;
for (i_c = 0; i_c < numero_clienti; i_c++) {
sb[i_c].sem_num = i_c;
sb[i_c].sem_op = -1;
sb[i_c].sem_flg = 0;
}
struct sembuf sb_2 = {0, -1, 0};
if ((key = ftok("cliente0.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid = semget(key, 1, 0)) == -1) {
perror("semget");
exit(1);
}
if ((key_2 = ftok("cliente1.txt", 'J')) == -1) {
perror("ftok");
exit(1);
}
if ((semid_2 = semget(key_2, 1, 0)) == -1) {
perror("semget");
exit(1);
}
//creation of a message
//1. Restart parent
sb_2.sem_op = 1;
if (semop(semid_2, &sb_2, 1) == -1)
{
perror("semop");
exit(1);
}
puts("cambio sem");
//stop itself
sb[num_j].sem_op = -1;
if (semop(semid, &sb[num_j], 1) == -1)
{
perror("semop");
exit(1);
}
//here it can move again
puts("remove message");
puts("Figlio: sono tornato attivo, mio padre aspetta");
}

1st you do
nome_file = (char*) malloc(sizeof(char*));
which allocates 4 or 8 bytes (depending on the platform you compile on: 32 or 64bit).
Then you do
sprintf(nome_file, "./cliente%d.txt", i);
The latter writes to invalid memory, as "./cliente%d.txt" is 14+1 characters long plus the potenial number of digits from i if i>9 or and addtional sign if i<0.
To fix this allocate what is needed:
nome_file = malloc(13 + 10 + 1 + 1); /* 13 for the filename,
10 for the digits,
1 for a potential sign,
1 the C-"strings" 0-terminator. */
This is a really ugly bug, which is expected to be the main issue in your code.
Also in the sources (you linked) in function read_line() you allocate memory, which you do not properly initialise, but later depend on its content.
main.c:20
char* myb2 = (char*) malloc(sizeof(char*));
malloc() does not initialise the memory it allocates, so either do:
char * myb2 = calloc(1, sizeof(char*));
of add and addtional call to
memset(mb2, 0, sizeof(char*));
after the call to malloc().
This bug is nasty either.
Also^2 you should build using gcc's options -std=c99 -D_XOPEN_SOURCE.
That is because:
You are using C constructs available from C99 on only. Typically VLAs, so tell the compiler to treat the code as being C99 code by explcitly stating -std=c99
To #define _XOPEN_SOURCE is issued by gcc, for some header you include in your project.
Also^3 you seem to be not necessarily count the correct number of client(file)s, at least not if your files a distributed as per the archive you linked:
main.c:82
system("ls cliente* | wc -l");
Change this to be:
system("ls cliente*.txt | wc -l");
If the bug described above should return more files then there actually are the following code fails as well from a certain value of i on:
main.c:176
fd = open(nome_file, O_RDONLY);
The result of the above operation is NOT tested. The possible invalid fd is used and the infamous undefined behaviour is taking over. Everything can happen.
As a final note: It's mostly never a bug in the tools we are using.

Related

Making multiple pipes

I am trying to create a process where several other processes talk to this main one, and I am using pipes to accomplish this. I can get two pipes to work with my current method but as soon as I introduce a 3rd pipe, the program starts to malfunction which I think is due to the reading from individual pipes being blocking functions. Altogether, I am going to need to have 5 receiving pipes and 2 of those receiving pipes will need a sending pipe with them to echo back info. Altogether, this needs a total of 7 pipes. I am very new to Linux and programming in general; I am sorry if this doesn't make sense.
mkfifo(ECHO_COMMAND_PIPE, 0666);
mkfifo(READ_COMMAND_PIPE, 0666);
mkfifo(READ_MATH_PIPE, 0666);
if ((echo_command_pipe = open(ECHO_COMMAND_PIPE, O_WRONLY))==-1){
fprintf(stderr, "echo_command_pipe creation failed");
}
else if ((read_command_pipe = open(READ_COMMAND_PIPE, O_RDONLY))==-1){
fprintf(stderr, "read_command_pipe creation failed");
}
else if ((math_pipe = open(READ_MATH_PIPE, O_RDONLY))==-1){
fprintf(stderr, "math_pipe creation failed");
return 1;
}
int error_cnt;
while(1){
fflush(stdout);
fflush(stdin);
int command_read = read(read_command_pipe, command_buffer, sizeof(command_buffer)-1);
int math_read = read(math_pipe, math_buffer, sizeof(math_buffer)-1);
command_buffer[command_read] = '\0';
math_buffer[math_read] = '\0';
fprintf(stdout, "%s", math_buffer);
if (strlen(command_buffer) < 1){
write(echo_command_pipe, err_buffer, strlen(err_buffer));
error_cnt = error_cnt + 1;
}
else {
write(echo_command_pipe, command_buffer,strlen(command_buffer));
error_cnt = 0;
}
if (error_cnt > 7) break;
}
close(echo_command_pipe);
close(read_command_pipe);
close(math_pipe);
unlink(ECHO_COMMAND_PIPE);
unlink(READ_COMMAND_PIPE);
unlink(READ_MATH_PIPE);
return 0;
}

Creating my first Unix Server/Client but getting a "shmget: Invalid argument" error and possibly more. [C]

I am doing a Unix, C assignment. I am creating a Server and a Client which will interact with each other. I am not very experienced with TCP/IP programming so I apologize for being slow in advance.
First, I am trying to create a basic layout of my set up. I compile the Client and Server using a Makefile and it works perfectly. However, when I execute the Server, I get this error:
shmget: Invalid argument
I think it is a problem with IPC resources. I am supposed to remove the IPC resources using atexit() but I don't think I am doing it right.
Here is the code for server.c if it helps:
#include "server.h"
int shmid, semid;
struct Shared *shm;
int main() {
key_t shmkey = 0x6060, semkey = 0x6061;
char *s, c;
unsigned short zeros[2] = {0, 0};
int srvrFd, clntFd, clntAdrLen, i; //socket
struct sockaddr_in srvrAddr, clntAddr;
char buf[256];
if(atexit(server_exit) != 0) {
perror("failed to attach atexit()");
_exit(EXIT_FAILURE);
}
/* Create an array of 2 semaphores with key. */
semid = semget(semkey, 2, 0666 | IPC_CREAT);
if (semid < 0) {
perror("semget");
exit(0);
}
/* Set the values of semaphores */
argument.array = zeros;
if (semctl(semid, 0, SETALL, argument) < 0) {
printf("Cannot init semaphore 0.\n");
}
/* Create the segment. */
if ((shmid=shmget(shmkey, sizeof(struct Shared), IPC_CREAT|0666))<0) {
perror("shmget");
exit(1);
}
/* Attach the segment to our data space. */
if ((shm=shmat(shmid, NULL, 0))==(struct Shared *)-1) {
perror("shmat");
exit(1);
}
/* Put some things into the shared memory. */
s = shm->text;
for (c = 'a'; c<= 'z'; c++) {
*s++ = c;
}
*s = '\0';
shm->number = 123;
//socket
srvrFd = socket(AF_INET, SOCK_STREAM, 0);
if(srvrFd < 0) {
perror("socket");
exit(1);
}
srvrAddr.sin_addr.s_addr = htonl(INADDR_ANY);
srvrAddr.sin_port = htons(6060);
if(bind(srvrFd, (struct sockaddr *)&srvrAddr, sizeof(srvrAddr)) < 0) {
perror("bind");
exit(1);
}
listen(srvrFd, 5);
while(1) {
clntAdrLen = sizeof(clntAddr);
clntFd = accept(srvrFd, (struct sockaddr*)&clntAddr, NULL);
if (fork() == 0) { //we're in the child
i = recv(clntFd, buf, sizeof buf, 0);
send(clntFd, buf, i, 0);
close(clntFd);
exit(0);
} else { //we're in the parent
close(clntFd);
}
}
}
void server_exit(void)
{
if(shm != NULL) {
shmdt(shm);
}
if(semid != -1) {
semctl(semid, 0, IPC_RMID);
}
if(shmid != -1) {
shmctl(shmid, IPC_RMID, 0);
}
}
Thanks for reading.
Edit: Definition of structure..
struct Shared {
char text[27];
int number;
} ;
http://linux.die.net/man/2/shmget
Looks like either the segment exists and it's smaller than what you asked for, or you're trying to create a new one, but it's smaller than the system min size (SHMMIN) or greater than max (SHMMAX)
EDIT: Turns out this was it -- it already existed and was smaller than what you were asking for. You must have created it as a size 27, 28, 29, 30, or 31, since it works for 27 but not 32. If you run the unix command line program ipcs, it will show you all your existing shared memory segments:
key shmid owner perms bytes nattch status
0x00000001 0 ec2-user 666 32 0
Then ipcrm -M <key> will delete it.
From what I'm seeing, you likely don't want to use SYS-V shared memory. Use POSIX if you can. Here is a reference for the POSIX Shared Memory interface:
http://man7.org/linux/man-pages/man7/shm_overview.7.html
also check out:
http://www.cs.cf.ac.uk/Dave/C/node27.html
for a guide to both, but I'd prefer POSIX if it's available (and it will be unless you're on a really old system like DEC Alpha)

Child process hangs when using shared memory?

I am experiencing some pretty weird output from some c code. Granted I am a newbie to c and Linux development, as my background is centered around .NET and C#.
In any case, I was supposed to write a FAT12 implementation and a command shell in c. My shell hangs whenever a child process tries to access shared memory. As a matter of fact nothing happens at all which is really weird. Can anyone help me debug the code?
Thanks,
This is the main loop that runs the shell:
while(strcmp(input, "EXIT") != 0 )
{
scanf("%s", input);
input = String_ToFixedArray(input);
array = StringArray_Create(input, " "); //split the input string into array.
if( array->Items == NULL || array->Size == 0 )
{
input = "CONTINUE";
continue;
}
if( strcmp(String_ToUpper(array->Items[0]), "PBS") == 0)
{
pid_t processId;
if((processId = fork()) < 0 )
{
printf("%s", "Error executing command.");
}
//child process. Nothing happens???????
if( processId == 0 )
{
ExecutePBS();
}
}
else if( strcmp(String_ToUpper(array->Items[0]), "PFE") == 0 )
{
printf("Execute Print Fat Entries (PFE) Command\n");
}
else if( strcmp(String_ToUpper(array->Items[0]), "EXIT") == 0 )
{
printf("Exiting..");
break;
}
else
{
input = "CONTINUE";
}
}
This is a "driver" function that will print the contents of the boot sector (PBS). The problem is that whenever this function executes, nothing happens!
void ExecutePBS(void)
{
int shm_file_id;
char* shm_file;
char* shm_file_ptr;
struct shmid_ds shm_file_buffer;
if( (shm_file_id = shmget(SHM_FILE_NAME_KEY,SHM_FILE_NAME_SIZE, 0666)) < 0)
{
perror("Error locating shared memory segment.");
exit(1);
}
if((shm_file = shmat(shm_file_id, NULL, 0)) == (char *) -1)
{
perror("Error attaching shared memory segment to process' scope.");
exit(1);
}
if(shmctl(shm_file_id, IPC_STAT, &shm_file_buffer) == -1 )
{
perror("Error while attempting to control the shared memory segment used to store the floppy file name for IPC.");
exit(1);
}
sprintf(shm_file_ptr, "%s", shm_file);
if( shmdt(shm_file) == -1)
{
perror("Error releasing shared memory.");
exit(1);
}
FILE* floppyImage = fopen(shm_file_ptr, "r+");
if (floppyImage == NULL)
{
printf("Could not open the floppy drive or image.\n");
exit(1);
}
BootSector* bootSector = BootSector_ReadBootSector(floppyImage);
BootSector_ToString(bootSector);
return;
}
not really a big forker... but my understanding was that it returned = 0 for the child process != 0 for the parent... so you should have two lots of logic, one for each case... as it stands, after the client has called the method, it's going to start going round the while loop as well, is that correct? also.. what do you mean by 'nothing' happens... have you tried putting printfs to increase visibility?

Multi Piping bash-style in C

I know there are many threads that talk about this problem but I don't really understand the way it can be done.
I'm trying to make a shell that can execute a linux command sucha as ps | grep | less
I've donne the parsing by puting every command and its args in a simply linked list.
Here's my implementation that doesn't work. Hope that's clear enough.
if ((son = fork()) < 0)
return printerr_sys("Unable to fork", 0);
if (son == 0)
{
if (first > 1 && data->format[first - 1] &&
is_directing_elt(data->format[first - 1]) == DIRECT_TPIPE)
dup2(tube_p[0], STDIN_FILENO);
first = make_argv(data, first, &argv);
if (next)
{
dup2(tube_v[1], STDOUT_FILENO);
close(tube_v[0]);
}
if (execvp(argv[0], argv) < 0)
return printerr_cmd(argv[0], 1);
}
else
{
if (next)
{
close(tube_v[1]);
cmdline_executer(data, next, tube_v);
}
waitpid(son, &(data->lastcmd), WUNTRACED);
data->lastcmd = WEXITSTATUS(data->lastcmd);
}
return TRUE;
My questions are:
What would be the correct implementation?
Is it possible to do it with recursion?
Do I need to fork from right to left or left to right (logically it give the same result)?
Here's a part of a UNIX Shell I had to implement in C for Operating System subject in my Computer Science career.
/* Executes the command 'buffer' assuming that doesn't contain redirections */
void execute_only_pipes(char* buffer)
{
char *temp = NULL, *pipeCommands[MAX_PIPES], *cmdArgs[MAX_ARGUMENTS];
int newPipe[2], oldPipe[2], pipesCount, aCount, i, status;
pid_t pid;
pipesCount = -1; /* This variable will contain how many pipes the command contains */
/* Counting the number of pipes and splitting them into pipeCommands */
do
{
temp = strsep(&buffer, "|");
if(temp != NULL)
{
if(strlen(temp) > 0)
{
pipeCommands[++pipesCount] = temp;
}
}
} while(temp);
cmdArgs[++pipesCount] = NULL;
for(i = 0; i < pipesCount; i++) /* For each command */
{
aCount = -1;
/* Parsing command & arguments */
do
{
temp = strsep(&pipeCommands[i], " ");
if(temp != NULL)
{
if(strlen(temp) > 0)
{
/* If a parameter is ~, then replace it by /home/user */
if (!strcmp(temp, "~"))
strcpy(temp, home);
cmdArgs[++aCount] = temp;
}
}
} while(temp);
cmdArgs[++aCount] = NULL;
/* If there still are commands to be executed */
if(i < pipesCount-1)
{
pipe(newPipe); /* just create a pipe */
}
pid = fork();
if(pid == 0) /* Child */
{
/* If there is a previous command */
if(i > 0)
{
close(oldPipe[1]);
dup2(oldPipe[0], 0);
close(oldPipe[0]);
}
/* If there still are commands to be executed */
if(i < pipesCount-1)
{
close(newPipe[0]);
dup2(newPipe[1], 1);
close(newPipe[1]);
}
/* Execute it */
int res = execvp(cmdArgs[0], cmdArgs);
if (res == -1)
{
printf("Error. Command not found: %s\n", cmdArgs[0]);
}
exit(1);
}
else /* Father */
{
/* If there is a previous command */
if(i > 0)
{
close(oldPipe[0]);
close(oldPipe[1]);
}
/* do we have a next command? */
if(i < pipesCount-1)
{
oldPipe[0] = newPipe[0];
oldPipe[1] = newPipe[1];
}
/* wait for last command process? */
if(i == pipesCount-1)
{
waitpid(pid, &status, 0);
}
}
}
}
It might be a little buggy (I'm not checking if fork() < 0, etc) but the main idea is correct.
> Is it possible to do it with recursion?
Most of the time I try to avoid recursion, if I can write a similar understandable code without using it.
Processes run independently, so you need to set up the pipe for at least the first pair of commands before you fork, but you're doing that in the child (son == 0). You could code a recursive solution that, as long as there are at least two commands left, creates a pipe, then forks, then runs the first command.

Locking semaphores in C problem sys/sem

EDIT: This peace of code is pretty fine (so take it as example of semaphores ;). Bug in my program was in another place - found by my friend.
I have problem with my functions. Sometimes two processes enter into critical section. I can't find problem in this after I spent 10 hours by debugging. On what I should aim? Is there any possibility to have bud in this piece of code?
// lock semaphore
static int P(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = 0;
if (semop(sem_id, &sem_b, 1) == -1) {
// error
return(0);
}
return(1);
}
// unlock semaphore
static int V(int sem_id)
{
struct sembuf sem_b[1];
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = 0;
if (semop(sem_id, &sem_b, 1) == -1) {
// error
return(0);
}
return(1);
}
static int set_semval(int sem_id) {
// set to 1 (opened semaphore)
if (semctl(sem_id, 0, SETVAL, 1) == -1) {
// error
return(0);
}
return(1);
}
static int get_val(int sem_id)
{
union semun sem_union;
//sem_union.val = 0; ?
return semctl(sem_id, 0, GETVAL, sem_union);
}
The action loop:
// semaphores init
int mutex;
if ((mutex=semget(key+2, 1, 0666))>=0) {
// semaphore exists
fprintf(stderr,"semaphore exists for key %d\n", key+2);
}
if ((mutex=semget(key+2, 1, 0666 | IPC_CREAT)) == -1) {
exit(EXIT_FAILURE);
}
if (!set_semval(mutex)) {
exit(EXIT_FAILURE);
}
fork() // some times with good conditionals
// in some children
while(1) {
P(mutex);
assert(get_val(mutex)==0); // always ok
action(); // sometimes made by two processes at same time - fault
V(mutex);
}
Pls, feel free to edit my question.
Many thanks
in your 'action loop' what do you do if your semaphore does not exist?
currently your 3rd parameter to semget is 0666 or the PERMISSION_RW constant. You may want to use:
shmget(key, 1, PERMISSION_RW | IPC_CREAT);
this way if your semaphore does not exist it will create one.
So bug was at another place...

Resources