0

I am trying to write a program that writes a file with some text in it, then makes that file executable. This is what I have:

#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { char name[] = "foo"; FILE * fp; fp = fopen(name, "w"); fprintf(fp, "This file should be executable.\n"); execl("/usr/bin/chmod", "/usr/bin/chmod", "+x", name, NULL); return 0; } 

The problem I am having that running execl seems to remove the contents of the file I wrote. If I remove the execl, it works as expected, and writes a file with the desired text. But when I leave in the execl, it writes a file, makes it executable, but the file is blank. How do I make it so the file still has the text in it, and is executable?

3
  • 4
    Call fclosebefore execl Commented Jul 23, 2020 at 23:08
  • 3
    See man 2 chmod There is no need to call execl to change the Linux permission bits. Commented Jul 23, 2020 at 23:10
  • I think you've got the order wrong. Create the file with the permissions you want. eg, use open to create the file and then fdopen to get a handle. Commented Jul 23, 2020 at 23:11

2 Answers 2

2

The problem is that output to the file is buffered. When you call execl(), you replace the process with chmod, but never write the stdio buffer to the file.

You need to call fclose(fp) before execl() to force everything to be written. You could also use fflush(fp), but fclose() more complete.

Sign up to request clarification or add additional context in comments.

1 Comment

Also, both fflush() and fclose() can fail, just like any other I/O call that writes data. The advantage of using fflush() is such a failure doesn't cause the FILE * handle to become invalid.
0

Creating the file with the wrong permissions and then changing them is not what you want to do. Just create the file with the desired permissions in the first place. If you want the file to be executable you can (with one caveat mentioned below) run:

/* CAUTION: all error checking omitted for clarity */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main(void) { char name[] = "foo"; FILE * fp; int fd = open(name, O_RDWR | O_CREAT, 0777); fp = fdopen(fd, "w"); fprintf(fp, "This file should be executable.\n"); return 0; } 

This will create the file with mode 0777 (modified by the umask) when executed. (eg, if umask is 111, the executable bits will not be set)

But, if you do want to create the file with the wrong permissions and then change them, don't exec out to /usr/bin/chmod. Just use chmod(2). eg chmod(name, 0777);

+x is convenient if you are just adding a permission, but since you are creating the file you are in complete control and you know what the permissions are.

4 Comments

Just create the file with the desired permissions in the first place That doesn't work because the process's umask setting will mask out bits, and in general that cannot be addressed by setting umask prior to opening the file because of potential race conditions. It's also possible that the file already existed with different permissions. The only way that's guaranteed to be free of race conditions and to set a file's permission bits to an exact value is to explicitly set them after creating the file. If the file is still open, fchmod() is likely preferable.
@AndrewHenle What's the race condition? Changing umask is synchronous. Your point about the file already existing is valid, though.
@Barmar The umask is a per-process attribute. Imagine multiple threads doing mode_t old = umask(0); int fd = open(...); umask(old);. What's the final state of the process's umask? What file permissions did you actually get?
I believe the proper solution to those issues is to add O_EXCL to the flags and handle the open error. (eg, emit an error message and abort)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.