I want to find the size of file on disk on linux OS .
I know command to do so:
du -s -h
Is there any way to find it using c/c++ code ?
Yes, use the stat(2) system call:
#include <sys/stat.h>
...
struct stat statbuf;
if (stat("file.dat", &statbuf) == -1) {
/* check the value of errno */
}
printf("%9jd", (intmax_t) statbuf.st_size);
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 am trying to print the path of the current directory using
this
execl ("/bin/pwd", "pwd", NULL);
output: /home/user/Ubuntu
and want to print a desired text before the current path.
for example:
my name /home/user/ubntu
how this will be done?
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
using namespace std;
int main(){
string command;
while(command != "exit"){
cout<< "B-17235"<<return execl ("/bin/pwd", "pwd", NULL);
cin>> command;
}
return 0;
}
Think that the majority of Unix-Linux-Gnu commands are written in C or C++. Generally there are direct API calls either system calls (man 2) or standard C library (man 3) to get the information or do the job.
To get working directory, just use getcwd() as suggested by alk.
char buffer[256];
if (NULL == getcwd(buffer, sizeof(buffer))) {
perror("can't get current dir");
return 1;
}
If you wanted to get the output of a more complex command, the most direct way would be to use popen that encloses the fork, exec, and pipe management for you :
FILE *fd = popen("/bin/pwd", "r");
char buffer[256];
if (fgets(buffer, sizeof(buffer), fd) == NULL) {
perror("can't read command");
return 1;
}
if (buffer[strlen(buffer) - 1] != '\n') {
fprintf(stderr, "path too long";
return 1;
}
pclose(fd);
// ok the working directory is is buffer
You should not use that for a command as simple as pwd.
And don't forget : man is your friend ! man getcwd and man popen will give you plenty of information ...
I am trying to print the path of the current directory
Use the library function getcwd().
To have the function available it might be necessary to #define _XOPEN_SOURCE 500 or similar (please see the man-page linked above for details on this).
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.
Is there a way to check which libraries is a running process using?
To be more specific, if a program loads some shared libraries using dlopen, then readelf or ldd is not going to show it.
Is it possible at all to get that information from a running process? If yes, how?
Other people are on the right track. Here are a couple ways.
cat /proc/NNNN/maps | awk '{print $6}' | grep '\.so' | sort | uniq
Or, with strace:
strace CMD.... 2>&1 | grep -E '^open(at)?\(.*\.so'
Both of these assume that shared libraries have ".so" somewhere in their paths, but you can modify that. The first one gives fairly pretty output as just a list of libraries, one per line. The second one will keep on listing libraries as they are opened, so that's nice.
And of course lsof...
lsof -p NNNN | awk '{print $9}' | grep '\.so'
May be lsof - the swiss army knife of linux will help?
edit: to run, lsof -p <pid>, lists all sorts of useful information, for example, if the process is java, lists all the open jars - very cool...
Actually, you can do this in your code in the following way:
#include <link.h>
using UnknownStruct = struct unknown_struct {
void* pointers[3];
struct unknown_struct* ptr;
};
using LinkMap = struct link_map;
auto* handle = dlopen(NULL, RTLD_NOW);
auto* p = reinterpret_cast<UnknownStruct*>(handle)->ptr;
auto* map = reinterpret_cast<LinkMap*>(p->ptr);
while (map) {
std::cout << map->l_name << std::endl;
// do something with |map| like with handle, returned by |dlopen()|.
map = map->l_next;
}
The link_map structure contains at least the base address and the absolute file name. It's the structure that is actually returned by dlopen() with non-NULL first argument. For more details see here.
ltrace seems to be your friend.
From ltrace manual:
ltrace is a program that simply
runs the specified command until it
exits. It intercepts and records the dynamic library calls
which are
called by the executed process and the signals which are
received by
that process. It can also intercept and print the system calls
exe‐
cuted by the program.
Its use is very similar to strace(1).
On Linux, /proc/<processid>/maps contains a list of all the files mapped into memory, which I believe should include any loaded by dlopen().
On solaris there is also the pldd command.
You can do so programmatically on Linux. You can use the function dl_iterate_phdr.
Here is a small example taken from the man page :
#define _GNU_SOURCE
#include <link.h>
#include <stdlib.h>
#include <stdio.h>
static int
callback(struct dl_phdr_info *info, size_t size, void *data)
{
int j;
printf("name=%s (%d segments)\n", info->dlpi_name,
info->dlpi_phnum);
for (j = 0; j < info->dlpi_phnum; j++)
printf("\t\t header %2d: address=%10p\n", j,
(void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));
return 0;
}
int
main(int argc, char *argv[])
{
dl_iterate_phdr(callback, NULL);
exit(EXIT_SUCCESS);
}
Would strace trace the library file being opened?
The question is whether you want to know it about a foreign process:
$ sleep 1h&p=$!;sleep 0.1;gdb -p $p -batch -ex 'info shared'
[1] 637756
...
From To Syms Read Shared Object Library
0x00007f795ffc4700 0x00007f7960135aed Yes /lib64/libc.so.6
0x00007f79601cc0a0 0x00007f79601f2d35 Yes /lib64/ld-linux-x86-64.so.2
[Inferior 1 (process 637756) detached]
Or about your own process:
#include <iostream>
#include <link.h>
#include <cassert>
#include <dlfcn.h>
int main() {
// prevent R_X86_64_COPY and r_state inconsistency if we accessed "_r_debug" directly.
r_debug *debug = (r_debug *) dlsym(RTLD_DEFAULT, "_r_debug");
assert(debug);
assert(debug->r_version == 1);
assert(debug->r_state == r_debug::RT_CONSISTENT);
link_map *prev = NULL;
for (link_map *map = debug->r_map; map; prev = map, map = map->l_next) {
assert(map->l_prev == prev);
std::cout << map << " " << (!map->l_name[0] ? "<empty>" : map->l_name) << std::endl;
}
}