race condition when writing to same file in c - c

i wrote a program to answer this question
but when i run the program i get this result
as of the answer of this exercise, i expect that the volume of the f1 be 2MB but when i run the program the result was 1Mb. can someone explain this difference?
the code was compiled by gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04).
int main(int argc, char *argv[]) {
int is_append = 1;
int fd;
int flags;
int number_of_bytes;
char buf = '0';
off_t offset;
mode_t mode;
if (argc < 3 || argv[3] == "help")
{
usage_error();
return -1;
}
if(4 == argc && strcmp("x", argv[3])) {
usage_error();
return -1;
}
if(4 == argc) { // the x argument is specified
is_append = 0;
}
flags = O_CREAT | (O_APPEND & is_append) | O_WRONLY;
mode = S_IWUSR | S_IRUSR;
number_of_bytes = atoi(argv[3]);
if (number_of_bytes <= 0)
{
printf("num-bytes must be grater than 0!\n");
return -1;
}
fd = open(argv[3], flags, mode);
if(-1 == fd) {
printf("error in open.\n");
return -1;
}
for (size_t i = 0; i < number_of_bytes; i++)
{
if(!is_append) {
offset = lseek(fd, 0, SEEK_END);
}
if(-1 == write(fd, &buf, 1)) {
printf("error in write.\n");
return -1;
}
}
return 0;
}

Related

testing the program for various memory allocation errors and memory leaks

The tee utility copies its standard input to both stdout and to a file. This allows the user to view the output of a command on the console while writing a log to a file at the same time.
My program implements the tee command from linux POSIX system calls, with the -a option.
How can I modify the program to test for possible memory allocation errors? Positive memory leaks.
Also, the memory allocation doesn't seem right to me. When creating a new buffer each time I call getline(), should I declare and initialize line outside the loop and reallocate it only after the loop has ended?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "apue.h"
int writeAll(int fd, char *buf, int buflen);
int main(int argc, char *argv[]) {
struct stat status;
int option;
bool append = false;
int errCode = 0;
while ((option = getopt(argc, argv, "a")) != -1) {
switch (option) {
case 'a':
append = true;
break;
}
}
// We need to write in all the files given as parameter AND stdout.
int numFileDescriptors = argc - optind + 1;
int *fileDescriptors = malloc((numFileDescriptors + 1) * sizeof(*fileDescriptors));
char **fileNames = malloc((numFileDescriptors + 1) * sizeof(*fileNames));
int lastFileDescriptor = 0;
fileDescriptors[0] = STDOUT_FILENO;
fileNames[0] = "stdout";
int flags = O_CREAT | O_WRONLY;
if (append) {
flags = flags | O_APPEND;
} else {
flags = flags | O_TRUNC;
}
for (int i = optind; i < argc; i++) {
if (access(argv[i], F_OK) == 0) {
if (access(argv[i], W_OK) < 0) {
err_msg("%s: Permission denied", argv[i]);
errCode = 1;
continue;
}
}
if (lstat(argv[i], &status) < 0) {
status.st_mode = 0;
}
if (S_ISDIR(status.st_mode)) {
err_msg("%s: Is a directory", argv[i]);
errCode = 1;
continue;
}
int fd = open(argv[i], flags, 0644);
if (fd < 0) {
err_msg("%s: Failed to open", argv[i]);
errCode = 1;
continue;
}
lastFileDescriptor = lastFileDescriptor + 1;
fileDescriptors[lastFileDescriptor] = fd;
fileNames[lastFileDescriptor] = argv[i];
}
while (true) {
size_t len = 0;
ssize_t read = 0;
char *line = NULL;
read = getline(&line, &len, stdin);
if (read == -1) {
break;
}
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, strlen(line));
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
for (int i = 0; i <= lastFileDescriptor; i++) {
close(fileDescriptors[i]);
}
free(fileDescriptors);
free(fileNames);
return errCode;
}
int writeAll(int fd, char *buf, int buflen) {
ssize_t written = 0;
while (written < buflen) {
int writtenThisTime = write(fd, buf + written, buflen - written);
if (writtenThisTime < 0) {
return writtenThisTime;
}
written = written + writtenThisTime;
}
return written;
}
Testing for memory allocation failure is simple: just add tests, report the failure and exit with a non zero exit status.
To avoid memory leaks, you must free the line that was allocated by getline inside the while (true) loop:
while (true) {
size_t len = 0;
char *line = NULL;
ssize_t nread = getline(&line, &len, stdin);
if (nread == -1) {
if (errno == ENOMEM) {
fprintf(stderr, "out of memory\n");
exit(1);
}
free(line);
break;
}
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, nread);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
free(line);
}
Alternately, you can reuse the same line for the next iteration and only free the buffer after the while loop:
size_t len = 0;
char *line = NULL;
while (true) {
ssize_t nread = getline(&line, &len, stdin);
if (nread == -1) {
if (errno == ENOMEM) {
fprintf(stderr, "out of memory\n");
exit(1);
}
break;
}
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, nread);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
free(line);
Note that reading a full line at a time is risky as the input might contain very long, possibly unlimited lines (eg: /dev/zero). You might want to use fgets() to read a line with a limited length and dispatch the contents as you read, possibly splitting long lines:
char line[4096];
while (fgets(line, sizeof line, stdin)) {
size_t len = strlen(line);
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, len);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
The above code has a limitation: if the input streams contains null bytes, they will cause some data to be lost in translation. A solution is to not use fgets(), but getchar() directly:
for (;;) {
char line[4096];
size_t len = 0;
int c;
while (len < sizeof(line) && (c = getchar()) != EOF)) {
if ((line[len++] = c) == '\n')
break;
}
if (len > 0) {
for (int i = 0; i <= lastFileDescriptor; i++) {
int written = writeAll(fileDescriptors[i], line, len);
if (written < 0) {
err_msg("%s: Failed to write", fileNames[i]);
errCode = 1;
}
}
}
if (c == EOF)
break;
}

Why am I getting extra character when trying to write to file?

This is supposed to flips upper and lower case letters but its not flipping just adding random characters.
int in = open(argv[1], O_RDONLY);
int out = open(argv[2], O_CREAT | O_WRONLY, 0624);
char buff[65];
buff[64] = '\0';
if(argc < 2){
printf("Not enough arguments");
return 1;
}
else if(argv[1] == 0 || argv[2] == 0){
printf("No file");
return 1;
}
int i = read(in,buff,64);
for (i = 0; buff[i]!='\0'; i++) {
if(buff[i] >= 'a' && buff[i] <= 'z') {
printf("%d", buff[i]-32);
} else if (buff[i] >= 'A' && buff[i] <= 'Z') {
printf("%d", buff[i]+32);
} else {
printf("%d", buff[i]);
}
}
write(out, buff, 64);
close(in);
close(out);
return 0;
}
How do I get it to read the character and flip without extras?
If your input file does not contain a '\0' as last character, your condition buff[i]!='\0' depends on random contents.
Change these lines:
char buff[65];
buff[64] = '\0';
to this line:
char buff[65] = { 0 };
However, read() tells you the number of bytes it read. You can use that value to mark the end:
int n = read(in,buff,64);
for (i = 0; i < n; i++) {
/* ... */
}
write(out, buff, n);
Write a function that reads a line, up to some maximum size; separate the logic of reading the file from other processing,
int readline(int fh, char* buff, int maxsize) {
int rc = read(fh,buff,maxsize);
if( rc < 0 ) {
printf("read error, %d\n",rc);
return rc;
}
return rc;
}
Write a function that writes the converted buffer, separate the logic of writing the file and other processing,
int writeline(int fh, char* buff, int len) {
int wc = write(fh, buff, len);
return wc;
}
Write a function that flips the case; separate the logic from reading and writing the file,
char* flipcase(char* buff, int len) {
if(!buff || len<1) return buff;
char* cp = buff;
for (int ix = 0; ix<len; ix++, cp++ ) {
if( isupper(*cp) { // in [A-Z]
// printf("%d", *cp-32); // not portable
*cp = tolower(*cp); // modify buff[ix]
}
else if( islower(*cp) ) { // in [a-z]
// printf("%d", *cp+32); // not portable
*cp = toupper(*cp); // modify buff[ix]
}
// else {
// unchanged
// }
// printf("%d", *cp);
}
return buff;
}
Build a function that handles each line separately,
# define MAXLINE (256) // named 'constant'
int doline(int fin, int fout) {
char buff[MAXLINE+1] = { 0 };
int rc = readline(fin, buff, MAXLINE);
// check results of readline here
flipcase(buff, rc);
int wc = writeline(fout, buff, rc);
// check results of writeline here
return rc;
}
Here you would handle your (argc, argv) and open your files,
if(argc < 3) {
printf("Not enough arguments");
return 1;
}
if(argv[1] == 0 || argv[2] == 0) {
printf("No file");
return 1;
}
int fin = open(argv[1], O_RDONLY);
if( !fin ) {
printf("open %s failed\n",argv[1]);
return 2;
}
int fout = open(argv[2], O_CREAT | O_WRONLY, 0624);
if( !fout ) {
printf("open %s failed\n",argv[2]);
close(fout);
return 2;
}
int rc = 0;
// process one line
rc = doline(fin,fout);
// or, process every line in file
for( ; rc = doline(fin,fout) >= 0; ) {
}
close(fin);
close(fh);

SegFault in read function for serial device

I'm attempting to interface with a measurement device through serial. I have already created one successful program that works and does what I want, but it doesn't have live user input.
My problem comes from a program I'm creating where I want to make a live serial terminal to interact with the device. In this program I have the user type the commands to the machine and for some commands the machine has to return a 1 or 0. This is where the problem comes. In the live environment, when I read a 1 after a command I get a segfault.
This is the segment that deals with commands that require the machine to send a 1 or 0.
buf = malloc(1);
if (buf == NULL)
{
perror("memory error");
goto fail;
}
...
if (write == 0)
{
for (i = 0; i < read_com.num; i++)
{
if (strcmp(buff, read_com.check[i]) == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
ret = read_port(fd, buf, 1);
if (ret < 0)
goto fail;
printf("Read success");
write = 1;
break;
}
}
}
This is the read port function where the segfault is occurring
int read_port(int fd, char *buf, const size_t size)
{
ssize_t r;
size_t received;
received = 0;
while (received < size)
{
r = read(fd, buf + received, size - received);
if (r < 0)
{
perror("failed to read from port");
return -1;
}
if (r == 0)
{
break;
}
received += r;
}
return received;
}
All code below:
live.c:
#include "GPIB_prof.h"
#include "serial.h"
#include "commands.h"
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
const struct com read_com = {3, {"OPC?;PRES;\r", "OPC?;WAIT;\r", "CORRON;\r"}};
const struct com numc = {3, {"STAR", "STOP", "POIN"}};
int main(int argc, char *argv[])
{
int fd;
int ret;
char *buff;
char *buf;
int i;
bool write = 0;
int fin = 0;
char *numb;
char *rem;
int star;
int stop;
int poin;
char *dat;
int fc = 0;
char *file;
FILE *temp;
FILE *f;
rem = malloc(256);
if (rem == NULL)
{
perror("memory error");
goto fail;
}
numb = malloc(4);
if (numb == NULL)
{
perror("memory error");
goto fail;
}
buff = malloc(256);
if (buff == NULL)
{
perror("memory error");
goto fail;
}
buf = malloc(1);
if (buf == NULL)
{
perror("memory error");
goto fail;
}
file = malloc(5);
if (file == NULL)
{
perror("memory error");
goto fail;
}
if (argc < 3)
{
printf("Usage: %s [serial device] [baud rate]", argv[0]);
goto fail;
}
fd = open_port(argv[1], atoi(argv[2]));
if (fd < 0)
goto fail;
ret = GPIB_conf(fd, 0);
if (ret < 0)
goto fail;
while (fin == 0)
{
write = 0;
scanf("%s", buff);
strcat(buff, "\r");
//if (ret<0) goto fail;
for (i = 0; i < strlen(buff); i++)
{
if (i < 4)
{
numb[i] = buff[i];
}
else
{
rem[i - 4] = buff[i];
}
}
if (strcmp(numb, "OUTP") == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
ret = read_port(fd, dat, 50 * poin);
if (ret < 0)
goto fail;
else
goto data;
}
if (write == 0)
{
for (i = 0; i < read_com.num; i++)
{
if (strcmp(buff, read_com.check[i]) == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
ret = read_port(fd, buf, 1);
if (ret < 0)
goto fail;
printf("Read success");
write = 1;
break;
}
}
}
if (write == 0)
{
for (i = 0; i < numc.num; i++)
{
if (strcmp(numb, numc.check[i]) == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
if (strcmp(numb, "STAR") == 0)
{
star = atoi(rem);
}
else if (strcmp(numb, "STOP") == 0)
{
stop = atoi(rem);
}
else if (strcmp(numb, "POIN") == 0)
{
poin = atoi(rem);
dat = malloc(50 * poin);
if (dat == NULL)
{
perror("memory error");
goto fail;
}
fc++;
}
break;
}
}
if (write == 0)
{
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
}
}
}
printf("Start freq: %d\nStop freq: %d\n", star, stop);
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return 0;
data:
ret = sprintf(file, "data%d", fc);
if (ret < 0)
goto fail;
temp = fopen(file, "w+");
if (temp == NULL)
{
perror("failed to open file");
fclose(temp);
goto fail;
}
fclose(temp);
ret = remove(file);
if (ret != 0)
{
perror("failed to remove file");
goto fail;
}
f = fopen(file, "w");
if (f == NULL)
{
perror("failed to open file");
fclose(f);
goto fail;
}
for (i = 0; i < (50 * poin); i++)
{
ret = fprintf(f, "%c", dat[i]);
if (ret < 0)
{
fclose(f);
goto fail;
}
}
fclose(f);
fin++;
fail:
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return -1;
}
serial.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdint.h>
#include <unistd.h>
#include "serial.h"
#include "GPIB_prof.h"
struct termios options;
int open_port(const char *dev, uint32_t baud)
{
int fd;
int ret;
char *baud_f;
struct termios opt;
baud_f = malloc(8 * sizeof(char));
if (baud_f == NULL)
{
perror("memory error");
goto fail;
}
fd = open(dev, O_RDWR, 0777);
if (fd < 0)
{
perror(dev);
goto fail;
}
ret = tcflush(fd, TCIOFLUSH);
if (ret)
{
perror("tcgetattr failed");
goto fail;
}
opt.c_cflag = (opt.c_cflag & ~CSIZE) | CS8;
opt.c_cflag &= ~IGNBRK;
opt.c_lflag = 0;
opt.c_oflag = 0;
opt.c_cc[VTIME] = 5;
opt.c_cc[VMIN] = 1;
opt.c_iflag &= ~(IXON | IXOFF | IXANY);
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= 0;
opt.c_cflag &= ~CSTOPB;
ret = sprintf(baud_f, "B%d", baud);
if (ret < 0)
{
perror("memory error");
goto fail;
}
baud = (uintptr_t)baud_f;
cfsetospeed(&opt, baud);
cfsetispeed(&opt, baud);
ret = tcsetattr(fd, TCSANOW, &opt);
if (ret)
{
perror("tcsetarre failed");
goto fail;
}
free(baud_f);
return fd;
fail:
free(baud_f);
close(fd);
return -1;
}
int read_port(int fd, char *buf, const size_t size)
{
ssize_t r;
size_t received;
received = 0;
while (received < size)
{
r = read(fd, buf + received, size - received);
if (r < 0)
{
perror("failed to read from port");
return -1;
}
if (r == 0)
{
break;
}
received += r;
}
return received;
}
int write_port(int fd, const char *buf, const size_t size)
{
ssize_t res;
res = write(fd, buf, size);
if (res != (ssize_t)size)
{
perror("failed to write to port");
return -1;
}
usleep(size * 100);
return 0;
}
int GPIB_conf(int fd, int profile)
{
int ret;
switch (profile)
{
case 0:
ret = def(fd);
if (ret < 0)
goto fail;
}
return 0;
fail:
return -1;
}
serial.h
#ifndef _SERIAL_H_
#define _SERIAL_H_
#include <stdint.h>
#include <stddef.h>
#include "GPIB_prof.h"
int open_port (const char *dev, uint32_t baud);
int read_port (int fd, char *buf, size_t size);
int write_port (int fd, const char *buf, size_t size);
int GPIB_conf (int fd, int profile);
#endif
commands.h:
#ifndef _COMMANDS_H_
#define _COMMANDS_H_
struct com
{
const int num;
const char *check[];
};
#endif
GPIB_prof.c:
#include "GPIB_prof.h"
#include "serial.h"
int def(int fd)
{
int ret;
ret = write_port(fd, "++mode 1\r", 9);
if (ret < 0)
goto fail;
ret = write_port(fd, "++addr 16\r", 10);
if (ret < 0)
goto fail;
ret = write_port(fd, "++eoi 0\r", 8);
if (ret < 0)
goto fail;
ret = write_port(fd, "++eot_enable 1\r", 15);
if (ret < 0)
goto fail;
ret = write_port(fd, "++eot_char 13\r", 14);
if (ret < 0)
goto fail;
ret = write_port(fd, "++ifc\r", 6);
if (ret < 0)
goto fail;
ret = write_port(fd, "++auto 1\r", 9);
if (ret < 0)
goto fail;
return 0;
fail:
return -1;
}
GPIB_prof.h:
#ifndef _PROFILE_H_
#define _PROFILE_H_
int def(int fd);
#endif
Caveat: This may not be a total solution as there are many compiler warnings for possibly uninitialized variables, etc.
Note that I'd rename some variables. You have a global called read. That tends to conflict with the standard read function. (i.e.) don't define functions/variables that conflict with standard functions/variables: caveat emptor.
Here is the compiler output I get for (e.g.) cc -o orig orig.c -Wall -Wextra -O2.
Notably, a number of pointer variables may have uninitialized values. This really should be restructured and the warnings fixed as the code is fragile and the compiler is pointing out things that could easily explain your runtime error(s).
orig.c: In function ‘GPIB_conf’:
orig.c:136:15: warning: unused parameter ‘fd’ [-Wunused-parameter]
GPIB_conf(int fd, int profile)
~~~~^~
orig.c: In function ‘main’:
orig.c:217:17: warning: comparison of integer expressions of different signedness: ‘int’ and ‘size_t’ {aka ‘long unsigned int’} [-Wsign-compare]
for (i = 0; i < strlen(buff); i++) {
^
orig.c:325:5: warning: increment of a boolean expression [-Wbool-operation]
fin++;
^~
orig.c: In function ‘open_port’:
orig.c:96:2: warning: ‘fd’ may be used uninitialized in this function [-Wmaybe-uninitialized]
close(fd);
^~~~~~~~~
orig.c: In function ‘main’:
orig.c:295:27: warning: ‘%d’ directive writing between 1 and 10 bytes into a region of size 1 [-Wformat-overflow=]
ret = sprintf(file, "data%d", fc);
^~
orig.c:295:22: note: directive argument in the range [0, 2147483647]
ret = sprintf(file, "data%d", fc);
^~~~~~~~
orig.c:295:8: note: ‘sprintf’ output between 6 and 15 bytes into a destination of size 5
ret = sprintf(file, "data%d", fc);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
orig.c:332:2: warning: ‘file’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(file);
^~~~~~~~~~
orig.c:333:2: warning: ‘dat’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(dat);
^~~~~~~~~
orig.c:329:2: warning: ‘numb’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(numb);
^~~~~~~~~~
orig.c:331:2: warning: ‘buf’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(buf);
^~~~~~~~~
orig.c:330:2: warning: ‘buff’ may be used uninitialized in this function [-Wmaybe-uninitialized]
free(buff);
^~~~~~~~~~
orig.c:230:32: warning: ‘poin’ may be used uninitialized in this function [-Wmaybe-uninitialized]
ret = read_port(fd, dat, 50 * poin);
~~~^~~~~~
I had to refactor/nop some of the code to get it to compile without the full definitions in the [missing] .h files. However, these hacks do not account for the warnings above.
#include "GPIB_prof.h"
#include "serial.h"
#include "commands.h"
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#define def(_fd) \
0
struct com {
int num;
char *check[3];
};
const struct com read_com = { 3, {"OPC?;PRES;\r", "OPC?;WAIT;\r", "CORRON;\r"} };
const struct com numc = { 3, {"STAR", "STOP", "POIN"} };
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <stdint.h>
#include <unistd.h>
#include "serial.h"
#include "GPIB_prof.h"
struct termios options;
int
open_port(const char *dev, uint32_t baud)
{
int fd;
int ret;
char *baud_f;
struct termios opt;
baud_f = malloc(8 * sizeof(char));
if (baud_f == NULL) {
perror("memory error");
goto fail;
}
fd = open(dev, O_RDWR, 0777);
if (fd < 0) {
perror(dev);
goto fail;
}
ret = tcflush(fd, TCIOFLUSH);
if (ret) {
perror("tcgetattr failed");
goto fail;
}
opt.c_cflag = (opt.c_cflag & ~CSIZE) | CS8;
opt.c_cflag &= ~IGNBRK;
opt.c_lflag = 0;
opt.c_oflag = 0;
opt.c_cc[VTIME] = 5;
opt.c_cc[VMIN] = 1;
opt.c_iflag &= ~(IXON | IXOFF | IXANY);
opt.c_cflag |= (CLOCAL | CREAD);
opt.c_cflag &= ~(PARENB | PARODD);
opt.c_cflag |= 0;
opt.c_cflag &= ~CSTOPB;
ret = sprintf(baud_f, "B%d", baud);
if (ret < 0) {
perror("memory error");
goto fail;
}
baud = (uintptr_t) baud_f;
cfsetospeed(&opt, baud);
cfsetispeed(&opt, baud);
ret = tcsetattr(fd, TCSANOW, &opt);
if (ret) {
perror("tcsetarre failed");
goto fail;
}
free(baud_f);
return fd;
fail:
free(baud_f);
close(fd);
return -1;
}
int
read_port(int fd, char *buf, const size_t size)
{
ssize_t r;
size_t received;
received = 0;
while (received < size) {
r = read(fd, buf + received, size - received);
if (r < 0) {
perror("failed to read from port");
return -1;
}
if (r == 0) {
break;
}
received += r;
}
return received;
}
int
write_port(int fd, const char *buf, const size_t size)
{
ssize_t res;
res = write(fd, buf, size);
if (res != (ssize_t) size) {
perror("failed to write to port");
return -1;
}
usleep(size * 100);
return 0;
}
int
GPIB_conf(int fd, int profile)
{
int ret;
switch (profile) {
case 0:
ret = def(fd);
if (ret < 0)
goto fail;
}
return 0;
fail:
return -1;
}
int
main(int argc, char *argv[])
{
int fd;
int ret;
char *buff;
char *buf;
int i;
bool write = 0;
bool fin = 0;
char *numb;
char *rem;
int star;
int stop;
int poin;
char *dat;
int fc = 0;
char *file;
FILE *temp;
FILE *f;
rem = malloc(256);
if (rem == NULL) {
perror("memory error");
goto fail;
}
numb = malloc(4);
if (numb == NULL) {
perror("memory error");
goto fail;
}
buff = malloc(256);
if (buff == NULL) {
perror("memory error");
goto fail;
}
buf = malloc(1);
if (buf == NULL) {
perror("memory error");
goto fail;
}
file = malloc(5);
if (file == NULL) {
perror("memory error");
goto fail;
}
if (argc < 3) {
printf("Usage: %s [serial device] [baud rate]", argv[0]);
goto fail;
}
fd = open_port(argv[1], atoi(argv[2]));
if (fd < 0)
goto fail;
ret = GPIB_conf(fd, 0);
if (ret < 0)
goto fail;
while (fin == 0) {
write = 0;
scanf("%s", buff);
strcat(buff, "\r");
// if (ret<0) goto fail;
for (i = 0; i < strlen(buff); i++) {
if (i < 4) {
numb[i] = buff[i];
}
else {
rem[i - 4] = buff[i];
}
}
if (strcmp(numb, "OUTP") == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
ret = read_port(fd, dat, 50 * poin);
if (ret < 0)
goto fail;
else
goto data;
}
if (write == 0) {
for (i = 0; i < read_com.num; i++) {
if (strcmp(buff, read_com.check[i]) == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
ret = read_port(fd, buf, 1);
if (ret < 0)
goto fail;
printf("Read success");
write = 1;
break;
}
}
}
if (write == 0) {
for (i = 0; i < numc.num; i++) {
if (strcmp(numb, numc.check[i]) == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
if (strcmp(numb, "STAR") == 0) {
star = atoi(rem);
}
else if (strcmp(numb, "STOP") == 0) {
stop = atoi(rem);
}
else if (strcmp(numb, "POIN") == 0) {
poin = atoi(rem);
dat = malloc(50 * poin);
if (dat == NULL) {
perror("memory error");
goto fail;
}
fc++;
}
break;
}
}
if (write == 0) {
ret = write_port(fd, buff, strlen(buff));
if (ret < 0)
goto fail;
write = 1;
}
}
}
printf("Start freq: %d\nStop freq: %d\n", star, stop);
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return 0;
data:
ret = sprintf(file, "data%d", fc);
if (ret < 0)
goto fail;
temp = fopen(file, "w+");
if (temp == NULL) {
perror("failed to open file");
fclose(temp);
goto fail;
}
fclose(temp);
ret = remove(file);
if (ret != 0) {
perror("failed to remove file");
goto fail;
}
f = fopen(file, "w");
if (f == NULL) {
perror("failed to open file");
fclose(f);
goto fail;
}
for (i = 0; i < (50 * poin); i++) {
ret = fprintf(f, "%c", dat[i]);
if (ret < 0) {
fclose(f);
goto fail;
}
}
fclose(f);
fin++;
fail:
free(rem);
free(numb);
free(buff);
free(buf);
free(file);
free(dat);
return -1;
}

Bad address in my file I/O operation function

I am learning Linux file I/O operation functions and trying to write a program that could creat a new file, read or write it as well as change the permissions and attributes of a file. When I try to use function "open(pathname, O_RDWR);" to get a file descriptor and use "read()" function to read current file, there is always "bad address" error. However, when I use "open(pathname, O_RDWR|O_CREATE,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)" before write, the file will be writen currectly.
Here are the source code when I using that two function.
//the welcome function is a function that serve as a function nemu bar
void Create()
{
char filepath[8];
int fd;
printf("请输入要创建的文件所在的目录及其名称:\n");
scanf("%s",&filepath);
fd = open(filepath, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH );//总是以默认的方式创建文件
if(fd == -1)
{
printf("创建失败,请重新输入文件名及其所在目录创建\n");
sleep(5);
Create();
}
else
{
char is;
printf("创建成功!是否对新创建的文件进行写操作?");
scanf("%s",&is);
if(is == 'y'||is == 'Y')
Write(fd,filepath);
else if(is == 'n'||is == 'N')
{
close(fd);
welcome();
}
else
{
printf("您的输入有误,回到欢迎界面中…\n");
close(fd);
sleep(5);
welcome();
}
}
}
void Write(int fd, char *path)
{
volatile int len;
if(fd == -1)
{
len = 0;
char filepath[8];
printf("请输入要写的文件的完整路径及其名称:");
scanf("%s",&filepath);
fd = open(filepath, O_RDWR);
if(fd == -1)
{
perror("open during write");
Write(-1, "");
}
char w1[BUFFERSIZE], *w;
printf("请输入要写入文件的内容,以回车结束:\n");
scanf("%s",&w1);
w = w1;
//用于写入的模块
int n = 1;
while(n > 0)
{
if(n = write(fd, w+len, (strlen(w)-len))<0)
{
perror("write");
return;
}
len += n;
}
char is;
printf("是否查看写入的内容?");
scanf("%s",&is);
if(is == 'Y'||is == 'y')
{
close(fd);
Read(filepath,strlen(w));
}
else
{
close(fd);
welcome();
}
}
else
{
printf("请输入要写入文件的数据:\n");
char w1[BUFFERSIZE];
char *w;
scanf("%s",&w1);
w = w1;
len = 0;
int n = 1;
while(n > 0)
{
n = write(fd, w+len, (strlen(w)-len));
len += n;
}
char is;
printf("是否查看写入的内容?");
scanf("%s",&is);
if(is == 'Y'||is == 'y')
{
close(fd);
Read(path,strlen(w));
}
else
{
close(fd);
welcome();
}
}
};
Could you please help me solve this question? I would be highly appreciated if you could help me!

C Programming in Linux, Creating A Simple Database, no data is being inserted into the database

I was working on a C programming database tutorial (linked here- https://www.youtube.com/watch?v=SEenaPQXxFs )
When I go to run my code and insert new data into the database it does generate a data file, but no data is stored in the data file/database at all- im not really sure why its not working, and as far as I can tell no errors populate.
The code I was working on is as follows
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
//give structure to record
typedef struct
{
unsigned int key; //primary key assingment
char fname[16]; // defines length allowed for names
char lname[16]; //same but for last name
unsigned int age;
} person_rec; //gives name to definition
int open_record(char *filename) //function to open record
{
int fd;
fd = open(filename, O_CREAT | O_APPEND, 0644);
if(fd == -1)
perror("open_record");
return fd;
}
void close_record(int fd) //close record
{
close(fd);
}
int insert_record(int fd, person_rec *rec) //unkkown
{
int ret;
ret = write(fd, rec, sizeof(person_rec));
return ret;
}
//function to delete and print
int get_record(int fd, person_rec *rec, int key)
{
int ret;
while( ( ret = read(fd, rec, sizeof(person_rec)) ) != -1)
{
if(ret == 0)
{
memset(rec, 0, sizeof(person_rec)); //clear any errors by resetting size
break;
return ret;
}
else if (key == rec->key)
return ret;
}
memset(rec, 0, sizeof(person_rec)); //clear record if error due to -1 size
return ret;
}
//delete function
int delete_record(int fd, int key)
{
int ret;
person_rec rec;
off_t pos;
pos = lseek(fd, 0, SEEK_SET);
while( ( ret = read(fd, &rec, sizeof(person_rec)) ) != -1)
{
if(ret == 0)
{
return ret;
}
else if (key == rec.key)
{
lseek(fd, pos, SEEK_SET);
rec.key = 0;
ret = write(fd, &rec, sizeof(person_rec));
return ret;
}
pos = lseek(fd, 0, SEEK_CUR);
}
return ret;
}
int main(int argc, char *argv[]) //main function/uses all prior defined function to make database ect
{
int fd;
person_rec rec;
fd = open_record("data1");
if(argc > 1)
{
/* insert */
if(argc > 5 && !strcmp(argv[1], "insert"))
{
rec.key = atoi(argv[2]);
strcpy(rec.fname, argv[3]);
strcpy(rec.lname, argv[4]);
rec.age = atoi(argv[5]);
insert_record(fd, &rec);
}
/* delete */
if(argc > 2 && !strcmp(argv[1], "delete"))
delete_record(fd, atoi(argv[2]));
/*print */
if(argc > 2 && !strcmp(argv[1], "print"))
{
get_record(fd, &rec, atoi(argv[2]));
printf("key = %d\n", rec.key);
printf("First = %s\n", rec.fname);
printf("Last = %s\n", rec.lname);
printf("Age = %d\n", rec.age);
}
}
return 0;
}
From the open man page:
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR.
So:
fd = open(filename, O_CREAT | O_APPEND, 0644);
should be:
fd = open(filename, O_CREAT | O_APPEND | O_RDWR, 0644);
I don't see any call to fclose() or fflush() to empty buffer to disk. Add fflush() after every write or fclose() before exiting the program.

Resources