It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I want to write a program which is capable of printing out system properties. Is this possible?
If so, with C/C++, how can one learn system features/properties?
For example, the following properties:
hardware :
Memory 3.8 gib
ubuntu :
release 10.10 ( maveric )
system status:
available disk space 51.1 gib
user name :
xxx
processor :
intel ... duo cpu e4600
The platform being Linux.
In Linux You can simple use the function:
int uname(struct utsname *buf);
by including the header
#include <sys/utsname.h>
it returns the system information as a part of the structure:
struct utsname
{
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined network" */
char release[]; /* OS release (e.g., "2.6.28") */
char version[]; /* OS version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
Well, if not all, atleast it gives you some system properties as you said. There should be other api available which can reveal all the information you need. You will need to check out the documentation & search around a bit for that.
EDIT:
Oh well, I just ripped this one off from the internet. This program shall help you run Linux commands programatically.
char* GetSystemOutput(char* cmd)
{
int buff_size = 32;
char* buff = new char[buff_size];
char* ret = NULL;
string str = "";
int fd[2];
int old_fd[3];
pipe(fd);
old_fd[0] = dup(STDIN_FILENO);
old_fd[1] = dup(STDOUT_FILENO);
old_fd[2] = dup(STDERR_FILENO);
int pid = fork();
switch(pid)
{
case 0:
close(fd[0]);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(fd[1], STDOUT_FILENO);
dup2(fd[1], STDERR_FILENO);
system(cmd);
//execlp((const char*)cmd, cmd,0);
close (fd[1]);
exit(0);
break;
case -1:
cerr << "GetSystemOutput/fork() error\n" << endl;
exit(1);
default:
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
int rc = 1;
while (rc > 0)
{
rc = read(fd[0], buff, buff_size);
str.append(buff, rc);
//memset(buff, 0, buff_size);
}
ret = new char [strlen((char*)str.c_str())];
strcpy(ret, (char*)str.c_str());
waitpid(pid, NULL, 0);
close(fd[0]);
}
dup2(STDIN_FILENO, old_fd[0]);
dup2(STDOUT_FILENO, old_fd[1]);
dup2(STDERR_FILENO, old_fd[2]);
return ret;
}
Api Usage: GetSystemOutput("/usr/bin/lsb_release -a")
And following the commands:
cat /proc/cpuinfo = tells you cpu info
cat /proc/meminfo = tells you memory info
lspci = tells you hardware that is attached (at least if the kernel recognizes it)
cat /proc/ide/hda/* = tells you info of your first ide hard-drive.
Look around in the /proc directory. There's a lot of things that might be considered system properties, but you'll soon be able to determine which properties are of interest to you.
cat /proc/somedir/somefile
is the command you want to use to safely browse /proc.
Every OS has an API that allows you to communicate with it.
Sadly it's not something uniform, you'll need to read search for your target OS's API.
Through the API you can usually get most of the information you need.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am new in linux device driver. I wan to write a C/C++ code to perform file transfer from raspberry pi to usb flash drive. I having difficult for the starting point, so i try on libusb for HID device sample code from signal11 and the code works fine for detecting my optical mouse with its device ID. Then i try to obtain usb flash drive vendor id somehow it give me very wired number. Finally i come out with a very silly try out by writing a bash script for cp a file to usb flash drive and activate the script in C++ and it works but i feel it is not a proper way to do it. Then i start with SCSI protocol and i very hard to understand how it works.Any guideline is appreciated.
int scsi_get_serial(int fd, void *buf, size_t buf_len) {
// we shall retrieve page 0x80 as per http://en.wikipedia.org/wiki/SCSI_Inquiry_Command
unsigned char inq_cmd[] = {INQUIRY, 1, 0x80, 0, buf_len, 0};
unsigned char sense[32];
struct sg_io_hdr io_hdr;
int result;
memset(&io_hdr, 0, sizeof (io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmdp = inq_cmd;
io_hdr.cmd_len = sizeof (inq_cmd);
io_hdr.dxferp = buf;
io_hdr.dxfer_len = buf_len;
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.sbp = sense;
io_hdr.mx_sb_len = sizeof (sense);
io_hdr.timeout = 5000;
result = ioctl(fd, SG_IO, &io_hdr);
if (result < 0)
return result;
if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
return 1;
return 0;
}
int main(int argc, char** argv) {
//char *dev = "/dev/sda";
char *dev = "/dev/sg2";
char scsi_serial[255];
int rc;
int fd;
fd = open(dev, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror(dev);
}
memset(scsi_serial, 0, sizeof (scsi_serial));
rc = scsi_get_serial(fd, scsi_serial, 255);
// scsi_serial[3] is the length of the serial number
// scsi_serial[4] is serial number (raw, NOT null terminated)
if (rc < 0) {
printf("FAIL, rc=%d, errno=%d\n", rc, errno);
} else
if (rc == 1) {
printf("FAIL, rc=%d, drive doesn't report serial number\n", rc);
} else {
if (!scsi_serial[3]) {
printf("Failed to retrieve serial for %s\n", dev);
return -1;
}
printf("Serial Number: %.*s\n", (size_t) scsi_serial[3], (char *) & scsi_serial[4]);
}
close(fd);
return (EXIT_SUCCESS);
}
I get this serial number: 00/1F
Then i try write this in test.sh
cp /home/Desktop/stl4.pdf /media/mini_flash
and run system("./test.sh") in C++
The question seems contradictory, at first you say you want to copy a file using a kernel driver, which seems strange to say the least. Then you say you use libusb, which is an userspace library. Then you say that you try to execute a shell script with cp.
Maybe what you want is simply a code snippet that copies a file form an userspace C/C++ program? Try one of these snippets.
In detail, if all you want to do is a C++ equivalent of cp /home/Desktop/stl4.pdf /media/mini_flash, then this is enough:
ifstream in("/home/Desktop/stl4.pdf",ios::binary);
ofstream out("/media/mini_flash/stl4.pdf",ios::binary);
out<<in.rdbuf();
in.close();
out.close();
Given a pid, I want to find the owner of the process (as uid). Is there a way to get this in osx (or any unix) using C++?
Google didn't help. 'ps' is able to do it; so I assume there should be a way to get it programatically.
Solution from Indhu helped me on my way, so I would like to post my own.
UID from PID with pure C:
#include <sys/sysctl.h>
uid_t uidFromPid(pid_t pid)
{
uid_t uid = -1;
struct kinfo_proc process;
size_t procBufferSize = sizeof(process);
// Compose search path for sysctl. Here you can specify PID directly.
const u_int pathLenth = 4;
int path[pathLenth] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
int sysctlResult = sysctl(path, pathLenth, &process, &procBufferSize, NULL, 0);
// If sysctl did not fail and process with PID available - take UID.
if ((sysctlResult == 0) && (procBufferSize != 0))
{
uid = process.kp_eproc.e_ucred.cr_uid;
}
return uid;
}
No excess allocation, no loops.
The source for the ps command, reveals that there is a function called get_proc_stats defined in proc/readproc.h that (among other things) returns the real user name(UID) & Effective user name(EUID) for a given pid.
You need to do install libproc-dev to get this function. and then you can do:
#include <proc/readproc.h>
void printppid(pid_t pid)
{
proc_t process_info;
get_proc_stats(pid, &process_info);
printf("Real user of the process[%d] is [%s]\n", pid, process_info.ruser);
}
compile it with gcc the-file.c -lproc.
Once you have the real user name you can use getpwnam() and getgrnam() functions to get the uid.
You could look at how ps does it. It looks like it uses the kvm_getprocs function.
However, it's much more portable (you said "any unix", but e.g. the Linux and Solaris way is to look in the /proc filesystem - and other unixes may have different APIs) to just parse the output of ps (ps -o user= -p (pid) for example, to eliminate any extraneous output) than to do any system-specific process stuff
There's not a portable way to do this. On Mac OS, you've got to use poorly documented sysctl interfaces: see this previous stackoverflow question. (As other commenters pointed out, on Linux you can use proc. On FreeBSD, you should be able to use kvm_getfiles, although this is not available on Mac OS.)
Your best bet is to use the source for Apple's ps as a jumping-off point for grabbing process data and then you'll be able to use getpwuid(3) once you have the uid.
Finally found a way to programatically do this without parsing the output of 'ps'
uint getUidUsingSysctl(uint pid)
{
struct kinfo_proc *sProcesses = NULL, *sNewProcesses;
int aiNames[4];
size_t iNamesLength;
int i, iRetCode, iNumProcs;
size_t iSize;
iSize = 0;
aiNames[0] = CTL_KERN;
aiNames[1] = KERN_PROC;
aiNames[2] = KERN_PROC_ALL;
aiNames[3] = 0;
iNamesLength = 3;
iRetCode = sysctl(aiNames, iNamesLength, NULL, &iSize, NULL, 0);
/* allocate memory and populate info in the processes structure */
do
{
iSize += iSize / 10;
sNewProcesses = (kinfo_proc *)realloc(sProcesses, iSize);
if (sNewProcesses == 0)
{
if (sProcesses)
free(sProcesses);
/* could not realloc memory, just return */
return -1;
}
sProcesses = sNewProcesses;
iRetCode = sysctl(aiNames, iNamesLength, sProcesses, &iSize, NULL, 0);
} while (iRetCode == -1 && errno == ENOMEM);
iNumProcs = iSize / sizeof(struct kinfo_proc);
for (i = 0; i < iNumProcs; i++)
{
if (sProcesses[i].kp_proc.p_pid == pid)
{
return sProcesses[i].kp_eproc.e_ucred.cr_uid;
}
}
/* clean up and return to the caller */
free(sProcesses);
return -1;
}
Note: There might be a better way to get 'kinfo_proc' instead of iterating through all process.
According to the question " How to get Linux distribution name and version? ", to get the linux distro name and version, this works:
lsb_release -a
On my system, it shows the needed output:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 9.10
Release: 9.10
Codename: karmic
Now, to get this info in C++, Qt4's QProcess would be a great option but since I am developing without Qt using std c++, I need to know how to get this info in standard C++, i.e. the stdout of the process, and also a way to parse the info.
Uptil now I am trying to use code from here but am stuck on function read().
You can simply use the function:
int uname(struct utsname *buf);
by including the header
#include <sys/utsname.h>
It already returns the name & version as a part of the structure:
struct utsname
{
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined network" */
char release[]; /* OS release (e.g., "2.6.28") */
char version[]; /* OS version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};
Am I missing something?
For recent linux distros you can use following to get the OS info. The output is pretty standard and can be parsed using following spec:
https://www.freedesktop.org/software/systemd/man/os-release.html
cat /etc/os-release
Sample outputs:
NAME=Fedora
VERSION="27 (Twenty Seven)"
ID=fedora
VERSION_ID=27
PRETTY_NAME="Fedora 27 (Twenty Seven)"
NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
ID_LIKE=archlinux
ANSI_COLOR="0;36"
Got it from cplusplus.com forums, a simple call GetSystemOutput("/usr/bin/lsb_release -a") works.
char* GetSystemOutput(char* cmd){
int buff_size = 32;
char* buff = new char[buff_size];
char* ret = NULL;
string str = "";
int fd[2];
int old_fd[3];
pipe(fd);
old_fd[0] = dup(STDIN_FILENO);
old_fd[1] = dup(STDOUT_FILENO);
old_fd[2] = dup(STDERR_FILENO);
int pid = fork();
switch(pid){
case 0:
close(fd[0]);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(fd[1], STDOUT_FILENO);
dup2(fd[1], STDERR_FILENO);
system(cmd);
//execlp((const char*)cmd, cmd,0);
close (fd[1]);
exit(0);
break;
case -1:
cerr << "GetSystemOutput/fork() error\n" << endl;
exit(1);
default:
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
int rc = 1;
while (rc > 0){
rc = read(fd[0], buff, buff_size);
str.append(buff, rc);
//memset(buff, 0, buff_size);
}
ret = new char [strlen((char*)str.c_str())];
strcpy(ret, (char*)str.c_str());
waitpid(pid, NULL, 0);
close(fd[0]);
}
dup2(STDIN_FILENO, old_fd[0]);
dup2(STDOUT_FILENO, old_fd[1]);
dup2(STDERR_FILENO, old_fd[2]);
return ret;
}
int writepipe[2];
if (pipe(writepipe) < 0) {
perror("pipe");
return 1;
}
int ret = fork();
if (ret < 0) {
perror("fork");
return 1;
}
else if (ret == 0) // child process
{
dup2(writepipe[1],1); // set writepipe[1] as stdout
// close fds
close(writepipe[0]);
close(writepipe[1]);
execlp("lsb_release","lsb_release","-a",NULL); //TODO: Error checking
}
else // parent process
{
int status;
waitpid(ret,&status,0); //TODO: Error checking
//do what you need
//read output of lsb_release from writepipe[0]
}
It works for me
There are files named /etc/version and /etc/release which have information like whether you're using Ubuntu or Fedora, etc. (which is what the OP clarified his question to be).
Personally I like the uname solution posted by #Alok Slav, but in case it helps someone who needs to use a command-line utility to get the info, consider using popen.
This question already has answers here:
Can popen() make bidirectional pipes like pipe() + fork()?
(6 answers)
Closed 3 years ago.
Is it possible to read and write to a file descriptor returned by popen. I have an interactive process I'd like to control through C. If this isn't possible with popen, is there any way around it?
As already answered, popen works in one direction. If you need to read and write, You can create a pipe with pipe(), span a new process by fork() and exec functions and then redirect its input and outputs with dup2(). Anyway I prefer exec over popen, as it gives you better control over the process (e.g. you know its pid)
EDITED:
As comments suggested, a pipe can be used in one direction only. Therefore you have to create separate pipes for reading and writing. Since the example posted before was wrong, I deleted it and created a new, correct one:
#include<unistd.h>
#include<sys/wait.h>
#include<sys/prctl.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
int main(int argc, char** argv)
{
pid_t pid = 0;
int inpipefd[2];
int outpipefd[2];
char buf[256];
char msg[256];
int status;
pipe(inpipefd);
pipe(outpipefd);
pid = fork();
if (pid == 0)
{
// Child
dup2(outpipefd[0], STDIN_FILENO);
dup2(inpipefd[1], STDOUT_FILENO);
dup2(inpipefd[1], STDERR_FILENO);
//ask kernel to deliver SIGTERM in case the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM);
//replace tee with your process
execl("/usr/bin/tee", "tee", (char*) NULL);
// Nothing below this line should be executed by child process. If so,
// it means that the execl function wasn't successfull, so lets exit:
exit(1);
}
// The code below will be executed only by parent. You can write and read
// from the child using pipefd descriptors, and you can send signals to
// the process using its pid by kill() function. If the child process will
// exit unexpectedly, the parent process will obtain SIGCHLD signal that
// can be handled (e.g. you can respawn the child process).
//close unused pipe ends
close(outpipefd[0]);
close(inpipefd[1]);
// Now, you can write to outpipefd[1] and read from inpipefd[0] :
while(1)
{
printf("Enter message to send\n");
scanf("%s", msg);
if(strcmp(msg, "exit") == 0) break;
write(outpipefd[1], msg, strlen(msg));
read(inpipefd[0], buf, 256);
printf("Received answer: %s\n", buf);
}
kill(pid, SIGKILL); //send SIGKILL signal to the child process
waitpid(pid, &status, 0);
}
The reason popen() and friends don't offer bidirectional communication is that it would be deadlock-prone, due to buffering in the subprocess. All the makeshift pipework and socketpair() solutions discussed in the answers suffer from the same problem.
Under UNIX, most commands cannot be trusted to read one line and immediately process it and print it, except if their standard output is a tty. The reason is that stdio buffers output in userspace by default, and defers the write() system call until either the buffer is full or the stdio stream is closed (typically because the program or script is about to exit after having seen EOF on input). If you write to such a program's stdin through a pipe, and now wait for an answer from that program's stdout (without closing the ingress pipe), the answer is stuck in the stdio buffers and will never come out - This is a deadlock.
You can trick some line-oriented programs (eg grep) into not buffering by using a pseudo-tty to talk to them; take a look at libexpect(3). But in the general case, you would have to re-run a different subprocess for each message, allowing to use EOF to signal the end of each message and cause whatever buffers in the command (or pipeline of commands) to be flushed. Obviously not a good thing performance-wise.
See more info about this problem in the perlipc man page (it's for bi-directional pipes in Perl but the buffering considerations apply regardless of the language used for the main program).
You want something often called popen2. Here's a basic implementation without error checking (found by a web search, not my code):
// http://media.unpythonic.net/emergent-files/01108826729/popen2.c
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "popen2.h"
int popen2(const char *cmdline, struct popen2 *childinfo) {
pid_t p;
int pipe_stdin[2], pipe_stdout[2];
if(pipe(pipe_stdin)) return -1;
if(pipe(pipe_stdout)) return -1;
//printf("pipe_stdin[0] = %d, pipe_stdin[1] = %d\n", pipe_stdin[0], pipe_stdin[1]);
//printf("pipe_stdout[0] = %d, pipe_stdout[1] = %d\n", pipe_stdout[0], pipe_stdout[1]);
p = fork();
if(p < 0) return p; /* Fork failed */
if(p == 0) { /* child */
close(pipe_stdin[1]);
dup2(pipe_stdin[0], 0);
close(pipe_stdout[0]);
dup2(pipe_stdout[1], 1);
execl("/bin/sh", "sh", "-c", cmdline, NULL);
perror("execl"); exit(99);
}
childinfo->child_pid = p;
childinfo->to_child = pipe_stdin[1];
childinfo->from_child = pipe_stdout[0];
close(pipe_stdin[0]);
close(pipe_stdout[1]);
return 0;
}
//#define TESTING
#ifdef TESTING
int main(void) {
char buf[1000];
struct popen2 kid;
popen2("tr a-z A-Z", &kid);
write(kid.to_child, "testing\n", 8);
close(kid.to_child);
memset(buf, 0, 1000);
read(kid.from_child, buf, 1000);
printf("kill(%d, 0) -> %d\n", kid.child_pid, kill(kid.child_pid, 0));
printf("from child: %s", buf);
printf("waitpid() -> %d\n", waitpid(kid.child_pid, NULL, 0));
printf("kill(%d, 0) -> %d\n", kid.child_pid, kill(kid.child_pid, 0));
return 0;
}
#endif
popen() can only open the pipe in read or write mode, not both. Take a look at this thread for a workaround.
In one of netresolve backends I'm talking to a script and therefore I need to write to its stdin and read from its stdout. The following function executes a command with stdin and stdout redirected to a pipe. You can use it and adapt it to your liking.
static bool
start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
{
int p1[2], p2[2];
if (!pid || !infd || !outfd)
return false;
if (pipe(p1) == -1)
goto err_pipe1;
if (pipe(p2) == -1)
goto err_pipe2;
if ((*pid = fork()) == -1)
goto err_fork;
if (*pid) {
/* Parent process. */
*infd = p1[1];
*outfd = p2[0];
close(p1[0]);
close(p2[1]);
return true;
} else {
/* Child process. */
dup2(p1[0], 0);
dup2(p2[1], 1);
close(p1[0]);
close(p1[1]);
close(p2[0]);
close(p2[1]);
execvp(*command, command);
/* Error occured. */
fprintf(stderr, "error running %s: %s", *command, strerror(errno));
abort();
}
err_fork:
close(p2[1]);
close(p2[0]);
err_pipe2:
close(p1[1]);
close(p1[0]);
err_pipe1:
return false;
}
https://github.com/crossdistro/netresolve/blob/master/backends/exec.c#L46
(I used the same code in Can popen() make bidirectional pipes like pipe() + fork()?)
Use forkpty (it's non-standard, but the API is very nice, and you can always drop in your own implementation if you don't have it) and exec the program you want to communicate with in the child process.
Alternatively, if tty semantics aren't to your liking, you could write something like forkpty but using two pipes, one for each direction of communication, or using socketpair to communicate with the external program over a unix socket.
You can't use popen to use two-way pipes.
In fact, some OSs don't support two-way pipes, in which case a socket-pair (socketpair) is the only way to do it.
popen works for me in both directions (read and write)
I have been using a popen() pipe in both directions..
Reading and writing a child process stdin and stdout with the file descriptor returned by popen(command,"w")
It seems to work fine..
I assumed it would work before I knew better, and it does.
According posts above this shouldn't work.. which worries me a little bit.
gcc on raspbian (raspbery pi debian)
How can I get the PID of a service called abc using C++ on Linux without using a system call? I would appreciate any examples that you care to offer.
Since use of sysctl has been discouraged for ages now, the recommended way of doing this is by examining each of the process entries in /proc and reading the comm file in each folder. If, for your example, the contents of that file are abc\n, that's the process you're looking for.
I don't really speak C++, but here's a possible solution in POSIX C89:
#include <glob.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
pid_t find_pid(const char *process_name)
{
pid_t pid = -1;
glob_t pglob;
char *procname, *readbuf;
int buflen = strlen(process_name) + 2;
unsigned i;
/* Get a list of all comm files. man 5 proc */
if (glob("/proc/*/comm", 0, NULL, &pglob) != 0)
return pid;
/* The comm files include trailing newlines, so... */
procname = malloc(buflen);
strcpy(procname, process_name);
procname[buflen - 2] = '\n';
procname[buflen - 1] = 0;
/* readbuff will hold the contents of the comm files. */
readbuf = malloc(buflen);
for (i = 0; i < pglob.gl_pathc; ++i) {
FILE *comm;
char *ret;
/* Read the contents of the file. */
if ((comm = fopen(pglob.gl_pathv[i], "r")) == NULL)
continue;
ret = fgets(readbuf, buflen, comm);
fclose(comm);
if (ret == NULL)
continue;
/*
If comm matches our process name, extract the process ID from the
path, convert it to a pid_t, and return it.
*/
if (strcmp(readbuf, procname) == 0) {
pid = (pid_t)atoi(pglob.gl_pathv[i] + strlen("/proc/"));
break;
}
}
/* Clean up. */
free(procname);
free(readbuf);
globfree(&pglob);
return pid;
}
Caveat: if there are multiple running processes with the name you're looking for, this code will only return one. If you're going to change that, be aware that with the naive glob written, you'll also examine /proc/self/comm, which could potentially lead to a duplicate entry.
If there are multiple processes with the same name, there isn't really a way to ensure you got the right one. Many daemons have the ability to save their pids to a file for this reason; check your documentation.
Google has this covered :)
http://programming-in-linux.blogspot.com/2008/03/get-process-id-by-name-in-c.html
Although it does use sysctl, which is a system call!
It's C but should work just as well in C++