My program receives an executable binary file through a TCP socket.
I need to save this file in to the harddisk as a executable program. File is successfully received but the problem is the default file attribute is being set to non executable.
How to change the file's attribute as executable in C in Ubuntu?
Thank you,
Regards,
Robo
How about int chmod(const char *path, mode_t mode) and int fchmod(int fd, mode_t mode) ?
apropos chmod
man 2 chmod
The most basic example:
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
char * fpath = "/path/to/binary";
int ret=0;
if(ret = chmod(fpath, S_IRUSR|S_IXUSR) < 0){
perror("chmod failed");
exit(1);
}
printf("chmod ok\n");
exit(0);
}
How are you creating and writing the file? If you know it's going to be executable, just make the file with the correct mode in the first place.
int fd = open("path/to/file", O_WRONLY | O_CREAT, 0777);
Unless umask is stripping the executable bits (common values are 0022 and 0002 which leave the executable bits alone), path/to/file will be created initially executable.
You can change the file mode with chmod. Read the man page(man 2 chmod) for detail(roughly the same as shell command chmod).
Related
My code(below) fails:
11:Resource temporarily unavailable
The code is running as root (in an abrt hook) but has seteuid to the user that the pid in question is running as.
Writing to /proc/self/coredump_filter from within the process works OK.
How can I write to the coredump_filter from the abrt hook?
void SetDumpFlags(pid_t pid, int dumpflags){
std::string c_filter_name = "/proc/" + std::to_string( pid ) + "/coredump_filter";
int f = open( c_filter_name.c_str(), O_WRONLY );
if (f < 0) {
fprintf( log, "Couldn't open %s\n", c_filter_name.c_str());
bail_out(1);
}
int wsz = write( f, &dumpflags, sizeof dumpflags);
if (wsz != sizeof dumpflags){
fprintf( log, "Couldn't write to %s, %d:%s\n", c_filter_name.c_str(),errno, strerror(errno));
close( f );
bail_out(1);
}
close( f );
fprintf( log, "Pid %d, dump filter set to 0x%x\n", pid, dumpflags);
}
I tried to replicate your problem with a C example
(I would use C++11 but I'm on an ancient netbook without C++11 and it'd be hard to get it here and aclimate in the language).
I got an EACCESS on the open (and my guess you might be getting it too but the errno could get overwritten elsewhere?).
It seems the coredump_filter (at least on this Linux 3.2) starts as owned by
root and the seteuid doesn't change it.
I tried chown before setuid to no avail.
What did work (as expected) was to open the fd while you're still root
and keep it open during the seteuid call.
Then I could write to the file again successfully even after my euid changed.
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define FLAGS "0x11"
#define FLAGSSZ (sizeof(FLAGS)-1)
int main()
{
pid_t pid = getpid();
char buf[sizeof("/proc/XXXXXXXXXXXXXX/coredump_filter")];
sprintf(buf,"/proc/%ld/coredump_filter",(long)pid);
int f;
if(0>(f=open(buf,O_WRONLY|O_TRUNC))) {perror("open");exit(1);}
if(FLAGSSZ != write(f,FLAGS,FLAGSSZ)){perror("write");exit(1);}
puts("ok");
char cat[sizeof("cat /proc/XXXXXXXXXXXXXX/coredump_filter")];
sprintf(cat,"cat /proc/%ld/coredump_filter", (long)pid);
system(cat);
char ls[sizeof("ls -l /proc/XXXXXXXXXXXXXX/coredump_filter")];
sprintf(ls,"ls -l /proc/%ld/coredump_filter", (long)pid);
system(ls); //owned by root, not writable by others
if(0>chown(buf,getuid(),getgid())){perror("chown"); exit(1); }
//chown returns success but ls -l doesn't agree
system(ls); //still owned by root
if(0>seteuid(getuid())){
perror("seteuid");
exit(1);
}
//can't reopen because of the perms but can still
//use the old fd if we kept it open
if(0>lseek(f,SEEK_SET,0)){perror("lseek"); exit(1);}
#define ALTFLAGS "0x22"
#define ALTFLAGSSZ (sizeof(ALTFLAGS)-1)
if(ALTFLAGSSZ != write(f,ALTFLAGS,ALTFLAGSSZ)){perror("write");exit(1);}
puts("ok");
system(cat);
}
I compiled with gcc c.c and made the a.out setuid root with sudo sh -c 'chown 0 $1 && chmod u+s $1' - a.out before running it.
I was trying to write data to the coredump_filter whereas I should have written a string! Doing it with a literal (e.g. #define FLAGS "0x11" as in the answer given by PSkocik ) fixes the problem.
The /proc/nnnnn/coredump_filter file is owned by the user that process nnnnn is running as. In my case this is root for some processes and another user for others. Switching user (in the abrt hook) to the appropriate user, before trying to write the coredump_filter, works OK.
We have a piece of legacy code that uses Flex with C-style FILE* descriptors. To support reading compressed files into Flex, we extended the "open" semantics to open gzip'ed files using
FILE* file = popen("gzip -cd <filename>");
rather than fopen.
We've encountered some problems recently where attempting this across a unix filesystem (probably another filesystem mounted using NFS on a NetApp) causes this entire code stream to crash (segfault), the first message we see is
gzip: stdout: Broken Pipe
and our own crash frame.
If we take the file and move it to the local filesystem where the process is running, there is no segfault and everything works as normal.
What have we tried to replicate or fix?
read files compressed using gzip/ bzip2 etc from internal test NFS filesystems
verify that the target file can be opened
"open" the file and read a few bytes to make sure it can be opened by this process
All of this succeeds and yet we still encounter the crash.
We are out of ideas and could use some suggestions.
Sam Appleton
When you test it, SIGPIPE has its default action (kill the gzip process). When the process runs on your client's side, SIGPIPE is masked. Here's a minimal program that reproduces the error:
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#define SZ 4096
void mask()
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
if (-1 == sigaction(SIGPIPE, &sa, 0))
{
perror("sigaction");
exit(1);
}
}
int main(int argc, char ** argv)
{
char buf[SZ];
#ifdef MASK
mask();
#endif
FILE * f = popen("gzip -dc foo.gz", "r");
if (0 != fread(buf, SZ, 1, f))
{
fwrite(buf, SZ, 1, stdout);
}
fprintf(stderr, "%d\n", pclose(f));
}
And here's the output with and without MASK:
$ gcc -o foo foo.c
$ gcc -DMASK -o foomask foo.c
$ /foo > /dev/null
13
$ /foomask > /dev/null
gzip: stdout: Broken pipe
256
$
In short, it has nothing to do with NFS. That's a red herring.
I have a device file(SYMLINK) /dev/CDMAModem generated by a udev rule. I want to find the bus number and device number of the actual device. Actually I want to perform USBDEVFS_RESET ioctl on device /dev/bus/usb/BUS_NO/DEVICE_NO in my C++ program.
----udev rule----
SUBSYSTEMS=="usb", ACTION=="add", DRIVERS=="zte_ev", ATTRS{bNumEndpoints}=="03", SYMLINK+="CDMAModem"
SUBSYSTEMS=="usb", ACTION=="remove", DRIVERS=="zte_ev", ATTRS{bNumEndpoints}=="03", SYMLINK-="CDMAModem"
I think libudev will give you that:
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
int main(int argc, char **argv)
{
struct udev *udev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;
struct udev_device *dev;
udev = udev_new();
enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "CDMAModem");
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices) {
const char *path;
path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(udev, path);
fprintf(stderr, "devnum: %s\n",
udev_device_get_sysattr_value(dev, "devnum"));
fprintf(stderr, "busnum: %s\n",
udev_device_get_sysattr_value(dev, 'busnum:));
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
udev_unref(udev);
return 0;
}
You can then use this information with ioctl() as in:
[charles#localhost 2-1]$ cd /sys/class/mem/random
[charles#localhost 2-1]$echo $PWD
/sys/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-1
You can perform an ioctl on the file represented by the symlink /dev/CDMAModem as you would on the file under the /dev/bus/ structure.
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
int f = open("/dev/CDMAModem", O_RDWR);
ioctl(f, USBDEVFS_RESET);
If you actually want to find where this link is pointing, the file command will tell you.
> file /dev/CDMAModem
/dev/CDMAModem: symbolic link to `bus/usb/BUS/DEV'
I think the stat() library call would be a good place to start... Along with libusb.
If all you want to do is resolve the link, you can use readlink and parse the information later with string functions.
Function: ssize_t readlink (const char *filename, char *buffer, size_t size)
The readlink function gets the value of the symbolic link filename. The file name that the link points to is copied into buffer. This file name string is not null-terminated; readlink normally returns the number of characters copied. The size argument specifies the maximum number of characters to copy, usually the allocation size of buffer.
~$ sudo udevadm info -a -p $(sudo udevadm info -q path -n /dev/CDMAModem)
[sudo] password for gowtham:
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/ttyUSB0/tty/ttyUSB0':
KERNEL=="ttyUSB0"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/ttyUSB0':
KERNELS=="ttyUSB0"
SUBSYSTEMS=="usb-serial"
DRIVERS=="zte_ev"
ATTRS{port_number}=="0"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0':
KERNELS=="2-1.2:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="zte_ev"
ATTRS{bInterfaceClass}=="ff"
ATTRS{bInterfaceSubClass}=="ff"
ATTRS{bInterfaceProtocol}=="ff"
ATTRS{bNumEndpoints}=="03"
ATTRS{supports_autosuspend}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="00"
ATTRS{interface}=="Data Interface"
looking at parent device '/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2':
KERNELS=="2-1.2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{devpath}=="1.2"
ATTRS{idVendor}=="19d2"
ATTRS{speed}=="12"
ATTRS{bNumInterfaces}==" 6"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{busnum}=="2"
ATTRS{devnum}=="8"
ATTRS{busnum}=="2"
ATTRS{devnum}=="8"
Though this is ugly but works. From C++ program call udevadm and filter for busnum and devnum attributes from the output. I hope some developer who involved in libudev development shall help and may be udev mailing-list will help.
I am running the code below and I cannot redirect to a file. The file is made, but nothing is put into it. If I remove the last dup2(saveout,1) statement, I can create and write into the file, but I cannot get back to the terminal, which is important. As soon as I put the dup2(saveout,1) back in my code, the redirection stops working, but I can get back to the terminal. I do not understand why this is happening. I would like to redirect and go back into the terminal.
main.cpp
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
using namespace std;
void printmessage() {
printf("this is the message\n");
}
int main(int argc, char** argv) {
int saveout;
int fd;
saveout = dup(1);
for (int i = 0; i < 10; i++) {
fd = creat("/home/carl/example.txt",O_CREAT|O_APPEND);
dup2(fd, 1);
close(fd);
printf("Testing the message");
printmessage();
dup2(saveout,1);
close(saveout);
}
return 0;
}
This is a file rights issue, you should read the man pages of the functions you are using.
creat() takes as first argument the filename, and as second the file creation rights, not its opening mode.
The creat() functions is a simple open() call, with some particular flags, so that you'll just have to set up the rights.
if you want to open your file, and create it if he doesn't exists, use
open(filename, O_CREAT | O_RDWR | O_APPEND, 0600) for example, or
creat(filename, 0600),
which is mostly its equivalent, but you wont be able to append text, as "creat() is equivalent to open() with flags equal to O_CREAT | O_WRONLY | O_TRUNC"
The second dup2(saveout,1); will fail because you closed saveout.
printf is buffered by default. (line-by-line for output to a tty, perhaps differently for output to something else). Before both your calls to dup2(..., 1), you should flush with fflush:
fflush(stdout);
I am writing a program that will open an image file, but strange thing happened. This is the output from cmd:
C:\Users\Karl\Pictures>testcvconsole mypic.jpg
argv[0]==testcvconsole
argv[1]==mypic.jpg
fopen is null
strerror(errno)==No such file or directory
Are there something I should consider when fopen simply failed to open my file when the file is right there along side with the executable file in the same directory?
This is on Windows 7, Visual Studios Express 2010. C++.
EDIT: code below
#include "stdafx.h"
#include <string.h>
#include <errno.h>
int goMain(int argc, char** argv);
int _tmain(int argc, _TCHAR* argv[])
{
goMain(argc, (char**)argv);
return 0;
}
int goMain( int argc, char** argv ){
if (argv[1] != NULL){
printf("argv[0]==%S\nargv[1]==%S\n", argv[0], argv[1]);
if (fopen(argv[1], "r") == NULL){
printf("fopen is null\n");
printf(strerror(errno));
}
}
return 0;
}
EDIT2:
I have tried
char *workingDir =_getcwd(NULL, 0);
printf("workingDir == %S", workingDir);
as TomK has suggested and it returned:
workingDir ==
Nothing at all. Hmm...
EDIT3:
I am getting something. I tried
argv[1] = "C:/Users/Karl/Pictures/mypic.jpg";
And fopen can open it. This statement above is inserted right before the fopen.
Make absolutely sure they are in the same directory. I'm saying this because you're using Visual Studio, for which the "same" directory isn't always so clear, because it depends on how you execute the executable through the IDE.
C:\Users\Karl\Pictures>testcvconsole mypic.jpg
Are you sure mypic.jpg is located in C:\Users\Karl\Pictures ?
Can u check whether the working directory is correct?
#include <direct.h>
char *workingDir =_getcwd(NULL, 0);
Can you run your application with admin privileges?
Usually the .exe is created in sub-directory either Debug or Release - try giving the absolute path to the image ...
I've had this problem, and it turned out that Visual Studio's runtime wasn't setting the current directory. I never figured out the problem: instead I simply used an absolute path. Without the absolute path, your program is looking in C:\. You can also try using ".\\mypic.jpg" or GetCurrentDirectory().