linux file attributes - linux

Use open syscall to write and create a file ,there's no attributes with the file. fedora16 gcc-4.6.3
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char * str= "helloworld";
int fd = open("test.db",O_WRONLY|O_CREAT|O_TRUNC|O_APPEND);
write(fd,str,10);
close(fd);
return 0;
}
ll test.db
----------. 1 jiamo jiamo 14 Apr 17 11:34 test.db
While it don't create file with the default file attributes such like touch test.db
umask : 0002
if drop the O_TRUNC
int fd = open("test1.db",O_WRONLY|O_CREAT|O_APPEND)
the file attributs is :
----rwx---. 1 jiamo jiamo 14 Apr 17 12:29 test1.db

Add the required permissions to the open() syscall:
int fd = open("test.db",O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0666);
From the documentation:
mode must be specified when O_CREAT is in the flags, and is ignored otherwise.
The argument mode specifies the permissions to use in case a new file is created.

You need to pass the mode to open. Then it will set the permissions too. open is a variable argument function and you can pass more arguments to it
int open(const char *path, int oflag, ... );
Do something like
open(LOCKFILE, O_WRONLY | O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Check the various permission bits here

Related

How to force g++ to respect #define _POSIX_C_SOURCE 200809L

I need to use strerror_r to translate error numbers into human readable messages compiled with g++ on Linux Debian Bullseye. The man page notes:
int strerror_r(int errnum, char *buf, size_t buflen);
/* XSI-compliant */
char *strerror_r(int errnum, char *buf, size_t buflen);
/* GNU-specific */
strerror_r():
The XSI-compliant version is provided if:
(_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
Otherwise, the GNU-specific version is provided.
We have two different types of the return value: int or char* depending on the version defined by _POSIX_C_SOURCE. I have this small test program:
~$ cat strerror_r.c
#include <string.h>
#include <stdio.h>
// #define _POSIX_C_SOURCE 200112L
// #undef _GNU_SOURCE
#define ERROR_BUFFER_LEN (size_t)256
int main(int argc, char **argv)
{
#if _POSIX_C_SOURCE < 200112L
char* ret;
#else
int ret;
#endif
char errorBuffer[ERROR_BUFFER_LEN];
int errno;
errno = 0;
ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
fprintf(stderr, "Error message by pointer = '%s'\n", ret);
fprintf(stderr, "Content of errorBuffer = '%s'\n", errorBuffer);
return 0;
}
If I compile it with gcc everything is as expected:
$ gcc strerror_r.c && ./a.out; rm a.out
Error message by pointer = '(null)'
Content of errorBuffer = 'Success'
If I compile it with g++ I get this:
$ g++ strerror_r.c && ./a.out; rm a.out
strerror_r.c: In function ‘int main(int, char**)’:
strerror_r.c:24:21: error: invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
24 | ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| char*
rm: cannot remove 'a.out': No such file or directory
If I try to force the needed version by uncommenting
#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE
I get:
$ g++ strerror_r.c && ./a.out; rm a.out
strerror_r.c:7: warning: "_POSIX_C_SOURCE" redefined
7 | #define _POSIX_C_SOURCE 200112L
|
In file included from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
from /usr/include/string.h:26,
from strerror_r.c:3:
/usr/include/features.h:281: note: this is the location of the previous definition
281 | # define _POSIX_C_SOURCE 200809L
|
strerror_r.c: In function ‘int main(int, char**)’:
strerror_r.c:24:21: error: invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
24 | ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| char*
rm: cannot remove 'a.out': No such file or directory
What I'm missing here? Why g++ does not compile the default thread save version of strerror_r? I need that version. How can I fix it?
Reference
Feature Test Macros
You need to specify the #define and #undef directives before you include any header files, so the first few lines should look like this:
#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE
#include <string.h>
#include <stdio.h>
That's because those header files or internal header files they include need those values defined to choose the proper variant. If you define them after including the headers, the headers don't see the right values and they don't include the version you want.
Often people specify these values on the command like with the -D and -U arguments so they are always specified before header files are included.

How do I check if a file has a certain mode in Rust?

I'd expect this to work:
use std::fs::OpenOptions;
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
const MODE: u32 = 0o700;
fn main() {
let f = OpenOptions::new()
.write(true)
.create_new(true)
.mode(MODE)
.open("myfile")
.unwrap();
let f_mode = f.metadata().unwrap().permissions().mode();
assert_eq!(f_mode, MODE);
}
When run, I get:
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `33216`,
right: `448`', src/main.rs:14:5
If I check the output of ls:
$ ls -al myfile
-rwx------ 1 edd edd 0 Apr 26 14:50 myfile
Clearly there's some other information encoded in the mode field once it gets committed to the file-system.
Is there a good way to check if the file is -rwx------ besides using bitwise operators on underlying the octal representation (masking off the irrelevant parts)?
If you are going to use the low-level primitives of OS-specific permissions, you need to deal with those details:
#define S_IFMT 0170000 /* type of file */
#define S_IFIFO 0010000 /* named pipe (fifo) */
#define S_IFCHR 0020000 /* character special */
#define S_IFDIR 0040000 /* directory */
#define S_IFBLK 0060000 /* block special */
#define S_IFREG 0100000 /* regular */
#define S_IFLNK 0120000 /* symbolic link */
#define S_IFSOCK 0140000 /* socket */
#define S_IFWHT 0160000 /* whiteout */
#define S_ISUID 0004000 /* set user id on execution */
#define S_ISGID 0002000 /* set group id on execution */
#define S_ISVTX 0001000 /* save swapped text even after use */
#define S_IRUSR 0000400 /* read permission, owner */
#define S_IWUSR 0000200 /* write permission, owner */
#define S_IXUSR 0000100 /* execute/search permission, owner */
When you get the mode, you also get information on what kind of file it is. Here, you have S_IFREG | S_IRUSR | S_IWUSR | S_IXUSR.
Doing a bitwise AND is the simplest fix:
assert_eq!(f_mode & 0o777, MODE);
Of course, you can create your own accessor functions in an extension trait and implement them to have nice meaning, or there may be a crate which has already done so.

second shm_open() fails with ENOENT

mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
shm_fd = shm_open("/ipc_shm", O_CREAT | O_RDWR, mode);
This works, returns 4 for shm_fd. The same process then calls a library function that also calls
fd = shm_open("/ipc_shm", O_RDWR, 0);
This one fails with errno set to 2, i.e. ENOENT (No such file or directory). There is no shm_unlink call in the middle. Any idea why the second call is failing. Appreciate your help.
my test.c:
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
int main (int argc, char *argv[])
{
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
int shm_fd = shm_open("/ipc_shm", O_CREAT | O_RDWR, mode);
int fd = shm_open("/ipc_shm", O_RDWR, 0);
return 0;
}
compiled with gcc test.c -Wall -lrt works as expected:
$strace ./a.out
....
statfs("/dev/shm/", {f_type=0x1021994, f_bsize=4096, f_blocks=22290, f_bfree=22290, f_bavail=22290, f_files=55725, f_ffree=55723, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0
futex(0xb6f5d1c0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
open("/dev/shm/ipc_shm", O_RDWR|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0777) = 3
fcntl64(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
open("/dev/shm/ipc_shm", O_RDWR|O_NOFOLLOW|O_CLOEXEC) = 4
exit_group(0)
Please run strace on your application, and search for all occurrences of ipc, and maybe chroot(). Maybe something unlinks the file?

Linux read() system call takes longer than my expectation ( serial port programming )

I am trying to read data sent from the tty/USB0 and print it out with byte format.
Question:
I expect to print out the data once the reading bytes reach 40 However, the time takes much longer than I expect. The read() system call hangs and I believe the data should already be larger than 40. The data will finally be printed out but it should not take so long. Did I make anything wrong in this programming ?
thanks
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyUSB0"
#define FALSE 0
#define TRUE 1
main()
{
int fd,c, res;
struct termios oldtio,newtio;
unsigned char buf[40];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio);
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 1;
newtio.c_lflag = ICANON;
tcflush(fd, TCIOFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
int i;
while (1) {
res = read(fd,buf,40);
if(res==40){
printf("res reaches 40 \n");
}
printf("res: %d\n",res);
for(i=0;i<res;++i){
printf("%02x ", buf[i]);
}
return;
}
}
--------------------raw mode code------------------------
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/ttyUSB0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
unsigned char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 40;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
int i;
while (STOP==FALSE) {
res = read(fd,buf,255);
for( i=0;i<res;++i){
printf("%02x \n", buf[i]);
}
}
tcsetattr(fd,TCSANOW,&oldtio);
}
It now can print out the data once buffer capacity is full ( which is 40 ).
1 question:
When I modified the printf
printf("%02x ", buf[i]); ( remove "\n" )
It will not print out when the buffer is full until more bytes are received. Why this happens?
Thanks
You need to switch the terminal to raw mode to disable line buffering.
Citing this answer:
The terms raw and cooked only apply to terminal drivers. "Cooked" is
called canonical and "raw" is called non-canonical mode.
The terminal driver is, by default a line-based system: characters are
buffered internally until a carriage return (Enter or Return) before
it is passed to the program - this is called "cooked". This allows
certain characters to be processed (see stty(1)), such as Cntl-D,
Cntl-S, Ctrl-U Backspace); essentially rudimentary line-editing. The
terminal driver "cooks" the characters before serving them up.
The terminal can be placed into "raw" mode where the characters are
not processed by the terminal driver, but are sent straight through
(it can be set that INTR and QUIT characters are still processed).
This allows programs like emacs and vi to use the entire screen more
easily.
You can read more about this in the "Canonical mode" section of the
termios(3) manpage.
See e.g. this or this how to achieve that programmatically (did not check the code, but it should be easy to find it).
Alternatively you could use e.g. strace or ltrace to check what stty -F /dev/ttyUSB0 raw does (or read the manual page where it is described).
EDIT>
Regarding printf without a newline -- fflush(stdout); immediately after it should help (another line-buffering is taking place).
You might consider reading this and maybe this.

Difficulty in using execve

I am trying to execute "word count" command on file given by absolute path - "/home/aaa/xxzz.txt" . I have closed the stdin so as to take input from file but the program doesn't give any output .
Also if I add some statement after "execve" command, it is also getting executed . Shouldn't the program exit after execve ?
int main()
{
char *envp[]={NULL };
int fd=open("/home/aaa/xxzz.txt",O_RDONLY);
close(0);
dup(fd);
char *param[]={ "/bin/wc",NULL } ;
execve("/bin/wc",param,envp);
}
Probably wc does not live in /bin (except for some systems which symlink that to /usr/bin, because wc normally lives in the latter). If I change the path in your example to /usr/bin/wc, it works for me:
#include <unistd.h>
#include <fcntl.h>
int
main()
{
char *envp[] = {NULL};
int fd = open("/home/aaa/xxzz.txt", O_RDONLY);
close(0);
dup(fd);
char *program = "/usr/bin/wc";
char *param[] = {program,NULL};
execve(program, param, envp);
}

Resources