I'm trying to mount a vfat disk image from DOS, using .C
if( mount( "/mypath/disk.img", "/mypath/img/", "vfat", MS_DIRSYNC | MS_SYNCHRONOUS, "utf8" ) ) {
printf( "Error mount %s errno=%d %s\n", dst.c_str(), errno, strerror( errno ) );
}
I get all the times the error "Block device required". Should i add some parameter or flag?
Note:I can mount from the bash the same file in the same target without any error.
UPDATE:
I had some good result using the function to mount an ISO. When I run the program, it remains stacked on the call ioctl(loop_device_fd, LOOP_CLR_FD, 0);. When I exit from the program (ctrl-c), the image is mounted. Is LOOP_CLR_FD necessary to complete all the steps? In additional,it is mounted in read only and seems not possible to change it in read/write.
const auto loop_control = std::fopen( "/dev/loop-control", "r" );
const auto loop_control_fd = fileno(loop_control);
const auto devnr = ioctl(loop_control_fd, LOOP_CTL_GET_FREE);
std::stringstream loopname;
loopname << "/dev/loop" << devnr;
const auto loop_device_name = loopname.str();
const auto loop_device = std::fopen(loop_device_name.c_str(), "r");
const auto loop_device_fd = fileno(loop_device);
const auto image = std::fopen( dst.c_str(), "r" );
const auto image_fd = fileno(image);
//Associate the loop device with the open file whose file descriptor is passed as the (third) ioctl(2) argument.
ioctl(loop_device_fd, LOOP_SET_FD, image_fd);
const auto result = mount(loop_device_name.c_str(), dst_path_img.c_str(), "vfat", MS_RDONLY, NULL);
if( result ) {
printf( "Error mount %s errno=%d %s\n", dst.c_str(), errno, strerror( errno ) );
return;
}
ioctl(loop_device_fd, LOOP_CLR_FD, 0);
The example code from the link above seems to mount your image quite fine, with minor modifications to retrieve free loop device (I'm assuming it is Dos3.3 diskette image from allbootdisks.com):
#include <sys/mount.h>
#include <linux/loop.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main()
{
int control_fd, file_fd, device_fd;
char loop_device[16];
control_fd = open("/dev/loop-control", O_RDWR);
if (control_fd < 0) {
perror("open loop control device failed");
return 1;
}
int loop_id = ioctl(control_fd, LOOP_CTL_GET_FREE);
sprintf(loop_device, "/dev/loop%d", loop_id);
close(control_fd);
printf("using loop device: %s\n", loop_device);
file_fd = open("./Dos3.3.img", O_RDWR);
if (file_fd < 0) {
perror("open backing file failed");
return 1;
}
device_fd = open(loop_device, O_RDWR);
if (device_fd < 0) {
perror("open loop device failed");
close(file_fd);
return 1;
}
if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
perror("ioctl LOOP_SET_FD failed");
close(file_fd);
close(device_fd);
return 1;
}
close(file_fd);
if (mount(loop_device, "./mnt/", "vfat", MS_DIRSYNC | MS_SYNCHRONOUS, "") < 0) {
perror("mount failed");
} else {
printf("mount successful\n");
}
// always free loop device in the end
ioctl(device_fd, LOOP_CLR_FD, 0);
close(device_fd);
}
As the disk image is not really a device, it cannot be directly mounted.
What you are trying to do, is to mount via a loop device.
Command line equivalent is: mount /mypath/disk.img /mypath/img -t vfat -o loop
I'm not sure, but try whether adding the "loop, utf8" as your last parameter would fix the problem.
The problem here is you're trying to mount an image as you you would do with a block device. A block device has more bindings to the operating system than an image file would, so you need to find a way around this.
Try a loopback device! A loopback device can give you the operating system reference to that image /mypath/disk.img as a block device. You can create a loopback device in bash like so:
# set up a block device
losetup -fP /mypath/disk.img
# now list the loopback devices
losetup -a
Anyway, this solution is in bash, but certainly there is a library out there somewhere for c.
Related
Is it possible for a c application using libwayland-client.so to get the name of the compositor / display server it opened a connection to (e.g. KWin, Sway, ...)? I fail to find it in the docs.
For reference, in X11 this is possible using XProps specified by EWMH: _NET_SUPPORTING_WM_CHECK to get the window id of the window manager and then using _NET_WM_NAME.
Im fine with anything giving me a way to identify it, for example a pretty name, the process name, the pid or similar.
Current solution is to detect which socket file wayland will be using (${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY:-wayland-0}), detecting which process are listening on it and picking the one which is most probably the compositor (similar to what neofetch does in bash). But since i need to open a connection anyway, and this method is very bug prone, i think you can see why i want to have a cleaner solution.
Requirements:
determine the PID of the peer compositor process for a display connection on the client side
must run under Linux
optionally determines the process name
Since this is not directly supported by the API, you can
get the file descriptor of the display context (wl_display_get_fd)
use the file descriptor to read the associated PID of the peer process (getsockopt with the SO_PEERCRED option, see e.g. this nice SO answer)
finally, you can get the process name by reading /proc/<pid>/comm.
You could also retrieve the process command line if you need more information.
However, the output of the following test program would look like this under Ubuntu 22.04 LTS:
pid: 1733, process name: gnome-shell
Self-contained Example in C
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-client.h>
#include <sys/socket.h>
#include <errno.h>
#define PROCESS_NAME_MAX_LENGTH 1024
static pid_t pid_from_fd(int fd) {
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) {
perror("getsockopt failed");
exit(-1);
}
return ucred.pid;
}
static char *process_name_from_pid(const pid_t pid) {
char *name = malloc(PROCESS_NAME_MAX_LENGTH);
if (!name) {
perror("malloc failed");
exit(-1);
}
char proc_buf[64];
sprintf(proc_buf, "/proc/%d/comm", pid);
FILE *fp;
if ((fp = fopen(proc_buf, "r")) == NULL) {
fprintf(stderr, "opening '%s' failed: %s\n", proc_buf, strerror(errno));
exit(-1);
}
if (fgets(name, PROCESS_NAME_MAX_LENGTH, fp) == NULL) {
fprintf(stderr, "reading '%s' failed\n", proc_buf);
exit(-1);
}
name[strcspn(name, "\n")] = 0;
fclose(fp);
return name;
}
int main(void) {
struct wl_display *display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "can't connect to display\n");
exit(-1);
}
int fd = wl_display_get_fd(display);
pid_t pid = pid_from_fd(fd);
char *process_name = process_name_from_pid(pid);
printf("pid: %d, process name: %s\n", pid, process_name);
free(process_name);
wl_display_disconnect(display);
return 0;
}
Seeing the write() function failing on /sys/bus/pci/devices/.../driver/remove_id file returning -1 with errno equal to 19 (ENODEV).
But, same works fine via command line. I have checked the file permission which seems to be fine (--w-------) for user to perform write on this file.
int fp = 0;
int buffer_length = 0;
int bytes_written = 0;
fp = open(cmd_buf, O_WRONLY); // where cmd_buf will hold this string
// "/sys/bus/pci/devices/.../driver/remove_id"
if (fp == -1)
{
return -1;
}
// where inbuf will be a char * pointing to pci vendor device id like
// this, "XXXX YYYY"
bytes_written = write(fp, in_buf, sizeof(in_buf));
printf(" bytes_written : %d \n ", bytes_written);
Seeing bytes_written equal to -1 and errno shows 19.
Please let me know if you find something wrong with the code snippet?
You do not provide enough information to pinpoint the problem.
However, here is an example program, example.c, that shows that it is your implementation that has the bug:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
/* Write string 'data' to existing file or device at 'path'.
Returns 0 if success, errno error code otherwise.
*/
int write_file(const char *path, const char *data)
{
const char *const ends = (data) ? data + strlen(data) : data;
ssize_t n;
int fd;
/* NULL or empty path is invalid. */
if (!path || !*path)
return errno = EINVAL;
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY | O_CLOEXEC, 0666);
if (fd == -1)
return errno; /* errno already set by open(). */
/* Write the contents of data. */
while (data < ends) {
n = write(fd, data, (size_t)(ends - data));
if (n > 0) {
/* Wrote n bytes. */
data += n;
} else
if (n != -1) {
/* C Library bug: Should never occur. */
close(fd);
return errno = EIO;
} else {
/* Error in errno. */
const int saved_errno = errno;
close(fd);
return errno = saved_errno;
}
}
if (close(fd) == -1) {
/* It is possible for close() to report a delayed I/O error. */
return errno;
}
/* Success. */
return 0;
}
static void usage(const char *argv0)
{
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
fprintf(stderr, " %s FILE CONTENTS\n", argv0);
fprintf(stderr, "\n");
fprintf(stderr, "This does the same thing as 'echo -n \"CONTENTS\" > FILE'.\n");
fprintf(stderr, "\n");
}
int main(int argc, char *argv[])
{
if (argc < 2) {
usage((argv && argv[0] && argv[0][0]) ? argv[0] : "(this)");
return EXIT_SUCCESS;
} else
if (argc > 3) {
usage((argv && argv[0] && argv[0][0]) ? argv[0] : "(this)");
return EXIT_FAILURE;
} else
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
usage((argv && argv[0] && argv[0][0]) ? argv[0] : "(this)");
return EXIT_SUCCESS;
}
if (write_file(argv[1], argv[2])) {
fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Compile it using e.g. gcc -Wall -Wextra -O2 example.c -o example, and run using e.g. ./example /sys/bus/pci/devices/.../driver/remove_id "vendor_id device_id".
Run it without arguments, or with -h or --help as the only argument, and it will print usage information to standard error.
The program essentially does what echo -n "vendor_id device_id" > /sys/bus/pci/devices/.../drivers/remove_id does.
If it is successful, it will not output anything, just return success (exit status 0). If there is any kind of an error, it will report it to standard error.
If you know the target path is always a device or a pseudo-file (like those in /sys or /proc), use fd = open(path, O_WRONLY | O_NOCTTY | O_CLOEXEC); instead. O_CLOEXEC means that if the process forks at any point, this particular file descriptor is not copied to the child process. O_NOCTTY means that if the path is a tty device, and the current process does not have a controlling terminal, the kernel is NOT to make the opened device the controlling terminal.
echo -n uses O_CREAT | O_TRUNC, so that if the target path exists and is a normal file, it is truncated, but if it does not exist, it is created. It does not affect opening existing character devices and pseudofiles. Whenever O_CREAT is used, there must be a third parameter, which affects the access mode of the file created. This mode is usually 0666, allowing read and write access as moderated by the current umask. One can obtain the current umask using mode_t mask = umask(0); umask(mask);. Access mode bits set in umask are always zero in the final access mode, and access mode bits clear in umask are taken from the third parameter of the open() command when the file is created.
Two possible problems:
Using sizeof(in_buf) in the write() system call writes the string "vendorId deviceId" and may be more garbage data behind it if in_buf[] is bigger than 10 chars.
Perhaps in_buf is not a table but a pointer and so, sizeof(in_buf) will return 4 or 8 (the size of the pointer respectively for 32 or 64 bits systems) but not the length of the string it points to.
So, in both cases (in_buf defined as a table or a pointer), strlen(in_buf) instead of sizeof(in_buf) is the most secured solution for the length of the data to write provided that the string is terminated by '\0'.
I've read some of the warnings against using the sysctl() call in C, and it seems if I cannot use sysctl() safely, the only other way I can find to make the needed change would be to use soemething like:
system("echo fs.inotify.max_user_watches=NEW_MAX_DIRECTORIES >> /etc/sysctl.conf");
system("sysctl -p");
(of course, this assumes ensuring the binary is running as root. However, I would rather NOT have to shell out using system calls.
Can someone point me in the correct and safe of using sysctl()?
here is a snippet of the code I am using.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
int main ()
{
int ret;
const char *LOGNAME="iNotifyMonitor";
logger(INFO, "================================================");
ret = startDaemon();
daemonRunning = ret;
if (ret == 0)
{
daemonRunning = 1;
FIRST_RUN = 0;
}
if(ret)
{
syslog(LOG_USER | LOG_ERR, "Error starting iNotifyMonitor");
logger(ERR, "Unable to start iNotifyMonitor");
closelog();
return EXIT_FAILURE;
}
signal(SIGINT, signalHandler);
signal(SIGHUP, signalHandler);
char *log_file_name = malloc(sizeof(char *) * sizeof(char *));
sprintf(log_file_name, "%s%s", INM_LOG_DIR, INM_LOG_FILE);
/* Try to open log file to this daemon */
if (INM_OPEN_LOG && INM_LOG_FILE)
{
log_stream = fopen(concatString(INM_LOG_DIR, INM_LOG_FILE), "a+");
if (log_stream == NULL)
{
char *errMsg;
sprintf(errMsg, "Cannot open log file %s, error: %s", concatString(INM_LOG_DIR, INM_LOG_FILE), strerror(errno));
log_stream = stdout;
}
}
else
{
log_stream = stdout;
}
while (daemonRunning == 1)
{
if (ret < 0)
{
logger(LOG_ERR, "Can not write to log stream: %s, error: %s", (log_stream == stdout) ? "stdout" : log_file_name, strerror(errno));
break;
}
ret = fflush(log_stream);
if (ret != 0)
{
logger(LOG_ERR, "Can not fflush() log stream: %s, error: %s",
(log_stream == stdout) ? "stdout" : log_file_name, strerror(errno));
break;
}
int curcount =countDirectory("/home/darrinw/Development/CrossRoads/");
directoryCount = curcount;
if(directoryCounrt > INM_MAX_DIRECTORIES)
{
int newVal = roundUp(directoryCount, 32768);
// call to sysctl() to modify fs.inotify.max_users_watches=newVal
}
sleep(INM_SCAN_INTERVAL);
}
My understanding is that the modern recommended approach to access sysctl variables is via the pseudo-files in /proc/sys. So just open /proc/sys/fs/inotify/max_user_watches and write there.
int fd = open("/proc/sys/fs/inotify/max_user_watches", O_WRONLY);
dprintf(fd, "%d", NEW_MAX_DIRECTORIES);
close(fd);
Error checking left as an exercise.
Modifying /etc/sysctl.conf would make the setting persist across reboots (assuming your distribution uses the file this way, I am not sure if all of them do). That's kind of rude to do automatically; probably better to use the documentation to advise the system administrator to do it themselves if it's needed.
I am trying to write a basic Linux GPIO user space application. For some reason, I am able to open the export file and export the GPIO with the given number. However, after exporting it, I cannot specify whether it is input or output because the /sys/class/gpio/gpio<###>/direction file is not created. As a result, my C errs out.
Here is the code
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int valuefd, exportfd, directionfd;
printf("GPIO test running...\n");
exportfd = open("/sys/class/gpio/export", O_WRONLY);
if(exportfd < 0)
{
printf("Cannot open GPIO to export it\n");
exit(1);
}
write(exportfd, "971", 4);
close(exportfd);
printf("GPIO exported successfully\n");
directionfd = open("/sys/class/gpio971/direction", O_RDWR);
if(directionfd < 0)
{
printf("Cannot open GPIO direction it\n");
exit(1);
}
write(directionfd, "out", 4);
close(directionfd);
printf("GPIO direction set as output successfully\n");
valuefd = open("/sys/class/gpio/gpio971/value", O_RDWR);
if(valuefd < 0)
{
printf("Cannot open GPIO value\n");
exit(1);
}
printf("GPIO value opened, now toggling...\n");
while(1)
{
write(valuefd, "1", 2);
write(valuefd, "0", 2);
}
return 0;
}
Output from run:
root#plnx_arm:~# /usr/bin/basic-gpio
GPIO test running...
GPIO exported successfully
Cannot open GPIO direction it
File is there
root#plnx_arm:~# ls /sys/class/gpio/gpio971/
active_low device direction edge power subsystem
uevent value
You need to open file "/sys/class/gpio/gpio971/direction" and not "/sys/class/gpio971/direction"
directionfd = open("/sys/class/gpio/gpio971/direction", O_RDWR);
if(directionfd < 0)
{
printf("Cannot open GPIO direction it\n");
exit(1);
}
You can refer [1], and get the code to export/unexport/set direction/read/write gpio pin.
[1] https://elinux.org/RPi_GPIO_Code_Samples#sysfs
As everything is file in Linux I would like to print to opened console in terminal window.
I have opened console in Linux and have written command tty. In output I have:
/dev/pts/25
This is the program that copies everything from foo file to bar and console:
/* Trivial file copy program using low-level I/O */
#include <fcntl.h>
#include <stdlib.h>
#define BSIZE 16384
void main()
{
int fin, fout,con; /* Input and output handles */
char buf[BSIZE];
int count;
if ((con = open("/dev/pts/2", O_WRONLY)) < 0) {
perror("open con ");
exit(1);
}
if ((fin = open("foo", O_RDONLY)) < 0) {
perror("foo");
exit(1);
}
if ((fout = open("bar", O_WRONLY | O_CREAT, 0644)) < 0) {
perror("bar");
exit(2);
}
while ((count = read(fin, buf, BSIZE)) > 0)
{
write(fout, buf, count);
write(con, buf, count);
}
close(fin);
close(fout);
close(con);
}
Unfortunately nothing is written in console window while bar contains needed information. How to write to console terminal window?
I have opened console in Linux and have written command tty. In output I have:
/dev/pts/25
This is program that coppyes evrything from foo file to bar and console:
…
if ((con = open("/dev/pts/2", O_WRONLY)) < 0) {
…
Your program opens just a device pts/2 different from pts/25 which you say is your console.