How to read HD serial in Linux without root privileges? - c++

I am building a C/C++ program which needs to read the HD serial. I am aware that if I run these commands:
hdparm -i /dev/sda | grep -i serial
/sbin/udevadm info --query=property --name=sda | grep "ID_SERIAL"
I can get it, the first requires root permissions but the second doesn't.
However, my application cannot access external programs, and it cannot require root privileges, so is there a C/C++ linux library that has a function that returns the HD serial? Or is there any other way that does not require running a program?

By just listing /dev/disk/by-id/ directory, you get IDs of all block devices on your system. The output is not exactly the same as with the commands, but it is close enough.
For this, you do not need root privileges.
On my PC :
$ /sbin/udevadm info --query=property --name=sda | grep "ID_SERIAL"
ID_SERIAL=WDC_WD5000AAKX-60U6AA0_WD-WCC2EHJ93860
ID_SERIAL_SHORT=WD-WCC2EHJ93860
and
$ ll /dev/disk/by-id/ | grep sda
lrwxrwxrwx 1 root root 9 Nov 11 07:47 ata-WDC_WD5000AAKX-60U6AA0_WD-WCC2EHJ93860 -> ../../sda
lrwxrwxrwx 1 root root 10 Nov 11 07:47 ata-WDC_WD5000AAKX-60U6AA0_WD-WCC2EHJ93860-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 Nov 11 07:47 ata-WDC_WD5000AAKX-60U6AA0_WD-WCC2EHJ93860-part2 -> ../../sda2
lrwxrwxrwx 1 root root 10 Nov 11 07:47 ata-WDC_WD5000AAKX-60U6AA0_WD-WCC2EHJ93860-part3 -> ../../sda3

You can use ioctls to access hard drive information, just as hdparm does. The HDIO_GET_IDENTITY ioctl should be sufficient for your needs. It returns a structure which (IIRC) includes the serial number; googling around should help you find the structure definition.

Related

Can't download a file via os.system('scp (...)') whithin a python script launched via a init script

I'm trying to download a remote file using the scp command called by os.system() in a Python script (scp.py) started as a service by a procd init script.
This script is running on OpenWrt 15.05.1 (which uses BusyBox to implement the shell environment). SCP itself is handled by dropbear SSH (https://matt.ucc.asn.au/dropbear/dropbear.html)
The code is quite simple :
import os
import logging
logging.basicConfig(level=logging.DEBUG, filename='/usr/local/www/log/scp_test.log', filemode = 'w')
rc = os.system('scp -i /root/.ssh/id_rsa root#vps500141.ovh.net:/root/simon/test /tmp/hello')
error_code, signal = rc >> 8, rc & 0xFF
logging.debug('error_code -> {}'.format(error_code))
logging.debug('signal -> {}'.format(signal))
When launched in the terminal using the command "python scp.py", the program's behave well. The download is successful and produces the following output :
root#S096C08:/usr/local/bin# python scp.py
test 100% 24 0.0KB/s 00:00
root#S096C08:/usr/local/bin# cat /usr/local/www/log/scp_test.log
DEBUG:root:error_code -> 0
DEBUG:root:signal -> 0
But this program fails to download anything when launched as a service using the command /etc/init.d/scp_test start
root#S096C08:/usr/local/bin# /etc/init.d/scp_test start
root#S096C08:/usr/local/bin# cat /usr/local/www/log/scp_test.log
DEBUG:root:error_code -> 1
DEBUG:root:signal -> 0
Furthermore, a quick investigation of the syslogs using the logread command shows this :
Wed May 15 10:24:58 2019 daemon.err python[3156]: Host 'vps500141.ovh.net' is not in the trusted hosts file.
Wed May 15 10:24:58 2019 daemon.err python[3156]: (ssh-rsa fingerprint md5 41:aa:2b:57:48:be:01:81:48:a3:d0:ac:b6:56:16:34)
Wed May 15 10:24:58 2019 daemon.err python[3156]: Do you want to continue connecting? (y/n)
Wed May 15 10:24:58 2019 daemon.err python[3156]: /usr/bin/dbclient: Connection to root#vps500141.ovh.net:22 exited: Didn't validate host key
vps500141.ovh.net already have an entry in /root/.ssh/known_hosts so this is quite surprising that it is not found when the script is running.
I've also tried to add the "-o StrictHostKeyChecking=no" option to the scp command but it doesn't seems to work either.
NB : this is the content of the init script /etc/init.d/scp_test
#!/bin/sh /etc/rc.common
# Copyright (C) 2015 CZ.NIC z.s.p.o. (http://www.nic.cz/)
START=99
STOP=0
USE_PROCD=1
SCRIPT="/usr/local/bin/scp.py"
start_service() {
procd_open_instance
procd_set_param user root
procd_set_param command python "$SCRIPT"
procd_set_param stderr 1
procd_close_instance
}
Problem resolved after moving /root/.ssh/known_hosts to /.ssh/known_hosts

Incron doesn't do anything

I intstalled on a new vm with centos 7 incron.
I try to make it work but a simple command does nothing.
incrontab -e :
/home/test IN_CLOSE_WRITE touch "$#/$#.new"
nothing special
When i watch the log cron i see this :
May 13 11:40:57 Minions incrond[2785]: (root) CMD (touch "/home/test/test.new")
but nothing is created in the directory
[root#Minions test]# ll
total 0
-rw-r--r--. 1 root root 0 13 mai 11:40 test
Do you have an idea what is wrong ?
I just del quote like this :
/home/test IN_CLOSE_WRITE touch $#/$#.new
This is rather old but... maybe your incrond service isn't running.
# systemctl enable incrond.service
# systemctl start incrond.service

ERROR: ld.so: object '/opt/xyz/mylib.so' from LD_PRELOAD cannot be preloaded: ignored

After upgrading a software from 32 to 64-bit, a pre-compiled binary starts to fail with the error:
[root#localhost /root]# LD_PRELOAD=/opt/xyz/lib/mylib.so mycommand /inputfile.txt /outputfile.txt
ERROR: ld.so: object '/opt/xyz/lib/mylib.so' from LD_PRELOAD cannot be preloaded: ignored.
mycommand: error while loading shared libraries: mylib.so: cannot open shared object file: No such file or directory
mycommand is a precompiled binary that sits in /usr/bin/mycommand. It requires the library as LD_PRELOAD.
Obviously I made sure that the file /opt/xyz/lib/mylib.so does exist:
[root#localhost lib]# ls -alh
total 512K
drwxr-xr-x 2 root root 4.0K Mar 1 15:40 .
drwxr-xr-x 10 root root 4.0K Feb 24 10:54 ..
-rwxr-xr-x 1 root root 218K Oct 28 22:41 mylib64.so
lrwxrwxrwx 1 root root 14 Mar 1 15:40 mylib.so -> mylib64.so
Is there any more debugging information I can extract other that this error?
It seems like not relevant if I simply delete the mylib.so or not, the error stays the same. It's kind of hard to say if it can't preload the library or if it can't find the library.
Is there any other environment variables or libraries that are required for LD_PRELOAD to work?
It seems to me essential to acquire a version of the source code of the mycommand binary and re-compile it. However to do that I think it would be probably useful to see why it actually fails right now.
LD_PRELOAD will not work on symlinks. You will need to set the path to the actual location of the library. For example:
LD_PRELOAD=/opt/xyz/lib/mylib64.so
I agree that a more specific error message would've been useful.

Linux - Reading File from Sudo - "Permission Denied"

When performing a recursive directory scan of the drive to generate a hash for each file by running the program executable under sudo, I'm discovering 1,000s of files are throwing "Permission Denied" errors.
My Question: Is this by design, why is sudo unable to read the files? Is what I'm doing even possible because files might be encrypted or currently in use during the time of the scan?
When I compile to Mac OSX and perform the same scan under sudo, I don't have this issue, just Linux.
Distro: 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
An example of files with permission denied:
Can't open file: "/sys/class/gpio/unexport"
MSG: "Permission denied"
Can't open file: "/sys/class/gpio/export"
MSG: "Permission denied"
Sample of permission settings:
/sys/class/gpio$ ls -al
total 0
drwxr-xr-x 2 root root 0 Oct 5 04:51 .
drwxr-xr-x 57 root root 0 Oct 4 11:25 ..
--w------- 1 root root 4096 Oct 5 04:51 export
--w------- 1 root root 4096 Oct 5 04:51 unexport
MD5 Function where file reads fail:
QByteArray MD5(QString sPath)
{
QByteArray resultMD5 = NULL;
QFile* file = new QFile(sPath);
if(file->open(QIODevice::ReadOnly))
{
QCryptographicHash* pHashMD5 = NULL;
resultMD5 = pHashMD5->hash(file->readAll(),QCryptographicHash::Md5);
file->close();
//Clean up pointer
delete pHashMD5;
delete file;
}
else
{
qDebug() << "Can't open file: " << sPath;
qDebug() << "MSG: " << file->errorString();
file->close();
delete file;
}
return resultMD5;
}
What is under /sys are not really files. It's an interface into the kernel.
With regard to the examples you have mentioned, see here for an explanation of what they do.
Given their function, it makes no sense to consider that such "files" could be read.

Windows vs. Linux GCC argv[0] value [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Get path of executable
I'm programming on Windows using MinGW, gcc 4.4.3. When I use the main function like this:
int main(int argc, char* argv[]){
cout << "path is " << argv[0] << endl;
}
On Windows I get a full path like this: "C:/dev/stuff/bin/Test". When I run the same application on Linux, however, I get some sort of relative path: "bin/Test". It's breaking my application! Any idea on how to make sure the path is absolute on both systems?
No, there isn't. Under most shells on Linux, argv[0] contains exactly what the user typed to run the binary. This allows binaries to do different things depending on what the user types.
For example, a program with several different command-line commands may install the binary once, and then hard-link the various different commands to the same binary. For example, on my system:
$ ls -l /usr/bin/git*
-rwxr-xr-x 109 root wheel 2500640 16 May 18:44 /usr/bin/git
-rwxr-xr-x 2 root wheel 121453 16 May 18:43 /usr/bin/git-cvsserver
-rwxr-xr-x 109 root wheel 2500640 16 May 18:44 /usr/bin/git-receive-pack
-rwxr-xr-x 2 root wheel 1021264 16 May 18:44 /usr/bin/git-shell
-rwxr-xr-x 109 root wheel 2500640 16 May 18:44 /usr/bin/git-upload-archive
-rwxr-xr-x 2 root wheel 1042560 16 May 18:44 /usr/bin/git-upload-pack
-rwxr-xr-x 1 root wheel 323897 16 May 18:43 /usr/bin/gitk
Notice how some of these files have exactly the same size. More investigation reveals:
$ stat /usr/bin/git
234881026 459240 -rwxr-xr-x 109 root wheel 0 2500640 "Oct 29 08:51:50 2011" "May 16 18:44:05 2011" "Jul 26 20:28:29 2011" "May 16 18:44:05 2011" 4096 4888 0 /usr/bin/git
$ stat /usr/bin/git-receive-pack
234881026 459240 -rwxr-xr-x 109 root wheel 0 2500640 "Oct 29 08:51:50 2011" "May 16 18:44:05 2011" "Jul 26 20:28:29 2011" "May 16 18:44:05 2011" 4096 4888 0 /usr/bin/git-receive-pack
The inode number (459240) is identical and so these are two links to the same file on disk. When run, the binary uses the contents of argv[0] to determine which function to execute. You can see this (sort of) in the code for Git's main().
argv array
argv[0] is a parameter like any others: it can be an arbitrary NUL terminated byte string. It can be the empty string. It is whatever the launching process wants.
By default, the shell with set argv[0] to whatever is used to name the program: a name looked-up in $PATH, a relative or an absolute path. It can be a symbolic link or a regular file.
To invoke a program with some other value, with zsh (dunno with other shells) use:
ARGV0=whatever_you_want some_program arguments
If you really need the path to the executable, you cannot use the command line on Unix.
Linux only
On Linux: /proc/self/exe is a symbolic link to the executable file.
You can readlink it. You can also stat or open it directly.
Renaming and soft link
A normal soft link is a dumb string, and doesn't know what happens to its target (if it exists at all). But the /proc/self/exe soft link is magic.
In case of renaming, the soft-but-magic-link will follow renaming. In case there are several hard links, it will follow the name of the particular hard link that was used. (So different hard links to the same file are not perfectly equivalent under Linux.)
If this hard link is unlinked, I think " (deleted)" is appended to the value of the symbolic link. Note that this is a valid file name, so another unrelated file could have that name.
In any case, the symbolic link is a hard link to the file, so you can stat or open it directly.
I don't think you can count on anything on a network file system if the binary is renamed or unlinked on another system than the one where the executable is launched.
Security considerations
When your program gets to use the /proc/self/exe special file, it is possible for the file used to launch your program to be unlinked or renamed. This should be taken seriously in case the program is privileged (SUID or Set Capabilities): even if the user doesn't have write access to the original "Set Something" binary, he may be able to make a hard link to it if he has write access to a directory on the same file system, so he may be able to change the name if a running privileged binary.
By the time you readlink, the value returned may refer to another file. (Of course, there is always an unavoidable race condition with opening the result of readlink.)
As usual, NFS does not provides all the same guaranties that local file systems have.
There is no way to ensure that argv[0] is an absolute path because it is supposed to be exactly how the user invoked the program. So, if on a Linux command line you invoke your program via ./bin/Test, then argv[0] should be exactly "./bin/Test".
It seems like a bug in MinGW's runtime if when you invoke the program from a command prompt via .\bin\Test, argv[0] is "C:/dev/stuff/bin/Test". With the latest MinGW (gcc version 4.5.2), invoking a binary via .\bin\Test means argv[0] is ".\bin\Test". A Microsoft Visual C++-built binary (cl version 16.00.40219.01) invoked via .\bin\Test also has ".\bin\Test" for argv[0].