Skip to content

Instantly share code, notes, and snippets.

@limelier
Last active May 3, 2019 14:11
Show Gist options
  • Save limelier/5a7ba8ab166a1f586a3c4feec355b83b to your computer and use it in GitHub Desktop.
Save limelier/5a7ba8ab166a1f586a3c4feec355b83b to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#define E_PID fprintf(stderr, "[%d] ", pid);
#define PID printf("[%d] ", pid);
struct instr {
int code;
int qty;
};
struct instr ReadInstruction(FILE* instr_file);
void ExecuteInstructions(int stocks_fd, FILE* instr_file);
pid_t pid;
int main(int argc, char* argv[]) {
pid = getpid();
PID printf("Began execution.\n");
// take args
if (argc != 3) {
E_PID fprintf(stderr, "Usage: ./mycritsec3.c <stocks_file> <instr_file> \n");
exit(1);
}
char* stocks_path = argv[1];
char* instr_path = argv[2];
// open stocks file
int stocks_fd = open(stocks_path, O_RDWR);
if (stocks_fd == -1) {
E_PID perror("Error opening stocks file");
exit(2);
}
// open instruction file
FILE* instr_file = fopen(instr_path, "r");
if (instr_file == NULL) {
E_PID perror("Error opening instruction file");
exit(3);
}
/// stuff happens
ExecuteInstructions(stocks_fd, instr_file);
close(stocks_fd);
fclose(instr_file);
PID printf("Finished execution succesfully.\n");
return 0;
}
struct instr ReadInstruction(FILE* instr_file) {
struct instr instr;
fscanf(instr_file, "%d %d\n", &(instr.code), &(instr.qty));
if (ferror(instr_file)) {
E_PID perror("Error reading instruction");
exit(4);
}
return instr;
}
void ExecuteInstructions(int stocks_fd, FILE* instr_file) {
// write lock struct for the next 4B
struct flock qty_lock;
qty_lock.l_type = F_WRLCK;
qty_lock.l_whence = SEEK_CUR;
qty_lock.l_start = 0;
qty_lock.l_len = sizeof(int);
// unlock struct for the previous 4B
struct flock qty_unlock;
qty_unlock.l_type = F_UNLCK;
qty_unlock.l_type = SEEK_CUR;
qty_unlock.l_start = -sizeof(int);
qty_unlock.l_len = sizeof(int);
// lock struct for the next 8B
struct flock field_lock;
field_lock.l_type = F_WRLCK;
field_lock.l_whence = SEEK_END;
field_lock.l_start = 0;
field_lock.l_len = 2 * sizeof(int);
// unlock struct for the previous 8B
struct flock field_unlock;
field_lock.l_type = F_UNLCK;
field_lock.l_whence = SEEK_END;
field_lock.l_start = -2 * sizeof(int);
field_lock.l_len = 2 * sizeof(int);
struct instr instr;
int ret_code;
bool found_code;
int crt_code, crt_qty;
while (!feof(instr_file)) {
instr = ReadInstruction(instr_file);
PID printf("> Received instruction (%d, %d).\n", instr.code, instr.qty);
lseek(stocks_fd, 0, SEEK_SET);
found_code = false;
while (!found_code) {
// read current item code
ret_code = read(stocks_fd, &crt_code, sizeof(int));
if (ret_code == -1) {
E_PID perror("Error on item code read");
exit(5);
}
else if (ret_code == 0) break; // reached EOF
if (crt_code != instr.code) {
lseek(stocks_fd, sizeof(int), SEEK_CUR); // skip the quantity
continue;
}
// lock quantity bytes
PID printf("Placing lock upon quantity of item with code %d.\n", instr.code);
ret_code = fcntl(stocks_fd, F_SETLKW, &qty_lock);
if (ret_code == -1) {
E_PID perror("Error on placing lock upon quantity");
exit(8);
}
// read current stock quantity
ret_code = read(stocks_fd, &crt_qty, sizeof(int));
if (ret_code == -1) {
E_PID perror("Error on stock quantity read");
exit(6);
}
else if (ret_code == 0) {
E_PID fprintf(stderr, "Error: read stock code, but no quantity.\n");
exit(7);
}
// DEBUG: output read info
//printf("Found stock code %d, of quantity %d.\n", crt_code, crt_qty);
if (instr.qty >= 0) {
PID printf("Adding %d quantity to item with code %d...\n", instr.qty, instr.code);
}
else {
PID printf("Subtracting %d quantity from item with code %d...\n", -instr.qty, instr.code);
}
sleep(1); // to pretend this part takes more time
crt_qty += instr.qty;
// write new data
if (crt_qty < 0) {
E_PID fprintf(stderr, "[!] Operation would lead to negative quantity; ignoring.\n");
}
else {
ret_code = lseek(stocks_fd, -sizeof(int), SEEK_CUR);
if (ret_code == -1) {
E_PID perror("Error jumping back before quantity");
exit(8);
}
ret_code = write(stocks_fd, &crt_qty, sizeof(int));
if (ret_code == -1) {
E_PID perror("Error writing new quantity");
exit(9);
}
}
// release lock
PID printf("Releasing lock.\n");
ret_code = fcntl(stocks_fd, F_SETLK, &qty_unlock);
if (ret_code == -1) {
E_PID perror("Error releasing write lock");
exit(10);
}
found_code = true;
}
if (!found_code) {
PID printf("Did not find code %d, adding it to the stocks file...\n", instr.code);
if (instr.qty < 0) {
E_PID fprintf(stderr, "[!] Cannot add negative quantity item to stocks file. Ignoring...\n");
continue;
}
ret_code = fcntl(stocks_fd, F_SETLKW, &field_lock);
if (ret_code == -1) {
E_PID perror("Error on placing lock at EOF");
exit(11);
}
ret_code = lseek(stocks_fd, 0, SEEK_END);
if (ret_code == -1) {
E_PID perror("Error on moving cursor to EOF");
exit(12);
}
write(stocks_fd, &(instr.code), sizeof(int));
write(stocks_fd, &(instr.qty), sizeof(int));
PID printf("Added item %d to stocks file, with quantity %d.\n", instr.code, instr.qty);
ret_code = fcntl(stocks_fd, F_SETLK, &field_unlock);
if (ret_code == -1) {
E_PID perror("Error on releasing lock from EOF");
exit(13);
}
}
}
}
limelier@limelier-K55VM:~/college/so/lab-8/mycritsec3$ ./mycritsec3.exec deposit.bin testinput.txt
[3938] Began execution.
[3938] > Received instruction (1, 1).
[3938] Did not find code 1, adding it to the stocks file...
[3938] Error on placing lock at EOF: Invalid argument
@jamieguinan
Copy link

In your example, you declare field_unlock but re-assign the members of field_lock. Simple copy/paste error. To avoid this kind of problem, you could use designated initializers, like this,

    // unlock struct for the previous 8B
    struct flock field_unlock = {
      .l_type = F_UNLCK,
      .l_whence = SEEK_END,
      .l_start = -2 * sizeof(int),
      .l_len = 2 * sizeof(int)
    };

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment