We know input function or operator (cin, scanf,gets….etc) wait to take input form user & this time has no limit.
Now, I will ask a question & user give the answer, till now there no problem but my problem is “user has a time(may 30 or 40 sec) to give the input, if he fail then input statement will automatically deactivated & execute next statement.”
I think you get my problem. Then please help me in this situation. It will be better if someone give me some really working example code.
I use codebolck 12.11 in windows 7.
An approach for *IX'ish systems (including Cygwin on windows):
You could use alarm() to schedule a SIGALRM, then use read(fileno(stdin), ...).
When the signal arrives read() shall return with -1 and had set errno to EINTR.
Example:
#define _POSIX_SOURCE 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
void handler_SIGALRM(int signo)
{
signo = 0; /* Get rid of warning "unused parameter ‘signo’" (in a portable way). */
/* Do nothing. */
}
int main()
{
/* Override SIGALRM's default handler, as the default handler might end the program. */
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler_SIGALRM;
if (-1 == sigaction(SIGALRM, &sa, NULL ))
{
perror("sigaction() failed");
exit(EXIT_FAILURE);
}
}
alarm(2); /* Set alarm to occur in two seconds. */
{
char buffer[16] = { 0 };
int result = read(fileno(stdin), buffer, sizeof(buffer) - 1);
if (-1 == result)
{
if (EINTR != errno)
{
perror("read() failed");
exit(EXIT_FAILURE);
}
printf("Game over!\n");
}
else
{
alarm(0); /* Switch of alarm. */
printf("You entered '%s'\n", buffer);
}
}
return EXIT_SUCCESS;
}
Note: In the example above the blocking call to read() would be interupted on any signal arriving. The code to avoid this is left as an execise to the reader ... :-)
Another Method:
You can use POSIX select() function (and some macros FD_ZERO, FD_SET, FD_ISSET) to check which file descriptors (descriptor number 0 i.e. stdin, in this case) are ready to be read in a given time interval. When they are ready, use appropriate function to read the data (scanf() in this case).
This code might help you understand, what I want to say:
#include <sys/select.h>
#include <sys/time.h>
#include <stdio.h>
#define STDIN 0 // Standard Input File Descriptor
int main()
{
fd_set input; // declare a "file descriptor set" to hold all file descriptors you want to check
int fds, ret_val, num; // fds: Number of file descriptors;
struct timeval tv; // structure to store Timeout value in the format used by select() function
unsigned int timeout = 5; // Your timeout period in seconds
tv.tv_sec = timeout;
tv.tv_usec = 0;
fds = STDIN + 1; // Set number of file decriptors to "1 more than the greatest file descriptor"
// Here, we are using only stdin which is equal to 0
FD_ZERO(&input); // Initialize the set with 0
FD_SET(STDIN, &input); // Add STDIN to set
printf("Enter a number within %d secs\n", timeout);
ret_val = select(fds, &input, NULL, NULL, &tv);
// We need to call select only for monitoring the "input file descriptor set"
// Pass rest of them as NULL
if (ret_val == -1) // Some error occured
perror("select()");
else if (ret_val > 0) // At least one of the file descriptor is ready to be read
{
// printf("Data is available now.\n");
if(FD_ISSET(0, &input)) // Check if stdin is set, here its not necessary as we are using STDIN only
// So ret_val>0 means STDIN is raedy to read
{
scanf("%d", &num);
}
}
else
printf("No data within five seconds.\n"); // select returns zero on timeout
return 0;
}
More Help:
select(2)
You can also try using poll() function available in (again a POSIX standard function) as an alternative to select(). See poll() & poll(2)
#include <cstddef>
#include <ctime>
#include <iostream>
#include <conio.h>
bool get_input ( char *buffer, std::size_t size, int timeout )
{
std::time_t start = std::time ( 0 );
std::size_t n = 0;
for ( ; ; ) {
if ( n == 0 && std::difftime ( std::time ( 0 ), start ) >= timeout )
return false;
if ( kbhit() ) {
if ( n == size - 1 )
break;
char ch = (int)getche();
if ( ch == '\r' ) {
buffer[n++] = '\n';
break;
}
else
buffer[n++] = ch;
}
}
buffer[n] = '\0';
return true;
}
int main()
{
char buffer[512] = {0};
if ( !get_input ( buffer, 512, 5 ) ) {
std::cout<<"Input timed out\n";
buffer[0] = '\n';
}
std::cout<<"input: \""<< buffer <<"\"\n";
}
Related
I'm still new to programming. I have been trying my best to finish this assignment. When I run the program it display: sent of total 0 bytes. It should display total bytes sending out. assignment prompt question:
The Sender:
The sender shall be invoked as ./sender where is the name of
the file to send to the receiver. For example, ./sender file.txt will send the file named
file.txt.
When invoked, the sender shall open the message queue named cpsc351messagequeue. If
it does not exist, the sender shall terminate with an error.
Otherwise, the sender shall open the file specified at the command line and proceed as
follows:
(a) Read at most 4096 bytes from the file.
(b) Send the bytes read through the message queue using mq send() and a message priority of 1.
(c) Repeat the previous steps until the end of file is reached.
(d) When the end of the file is reached, send an empty message to the receiver with a priority of 2 to tell the receiver that the sending is done.
Terminate.
my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <mqueue.h>
#include <unistd.h>
#include <signal.h>
#define MSQ_NAME "/cpsc351queue"
int main(int argc, char** argv)
{
// The file size
int fileSize = -1;
// The buffer used to store the message copied
// copied from the shared memory
char buff[4096];
// The variable to hold the message queue ID
int msqid = -1;
// The total number of bytes written
int totalBytesRead = 0;
// The number of bytes
int bytesRead = 0;
// Whether we are done reading
bool finishedReading = false;
// TODO: Define a data structure
// of type mq_attr to specify a
// queue that can hold up to 10
// messages with the maximum message
// size being 4096 bytes
mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 4096;
attr.mq_curmsgs = 0;
// Sanity checks -- make sure the user has provided a file
if(argc < 2)
{
fprintf(stderr, "USAGE: %s <FILE NAME>\n", argv[0]);
exit(1);
}
// Open the file for reading
int fd = open(argv[1], O_RDONLY);
// Make sure the file was opened
if(fd < 0)
{
perror("open");
exit(1);
}
// TODO: Gain access to the message queue
// whose name is defined by the macro
// MSQ_NAME macro above. We assume that
// the receiver has allocated the message queue.
mqd_t qid = mq_open("/cpsc351queue", O_RDWR, 0600, &attr);
//TODO: Loop below attempts to read the
// file 4096 bytes at a time.
// Modify the loop as necessary to send
// each chunk of data read as message
// through the message queue. You can use
// 1 for the priority of the message.
// Keep writing until all data has been written
while((totalBytesRead < fileSize) && !finishedReading)
{
totalBytesRead = read(fd, buff, bytesRead);
bytesRead = mq_send(qid, totalBytesRead, 4096, 1);
// Something went wrong
if(bytesRead < 0)
{
perror("read");
exit(1);
}
// We are at the end of file
else if(bytesRead == 0)
{
// We are at the end of file
finishedReading = true;
}
totalBytesRead += bytesRead;
}
// TODO: Send a message with size of 0
// to the receiver to tell it that the
// transmission is done
fprintf(stderr, "Sent a total of %d bytes\n", totalBytesRead);
// TODO: Close the file
close(fd);
return 0;
}
The program should open the message queue named /cpsc351queue, not /cpsc351messagequeue.
The mq_send function should be called with the following arguments: qid, buff, bytesRead, 1. Currently, it is being called with totalBytesRead, 4096, and 1.
The read function should be called with the following arguments: fd, buff, and 4096. Currently, it is being called with fd, buff, and bytesRead.
The totalBytesRead variable should be updated after the read function is called, not before.
The bytesRead variable should be updated after the mq_send function is called, not before.
The loop should continue until the end of the file is reached, which can be determined by checking whether bytesRead is less than 0. Currently, the loop is continuing until bytesRead is equal to 0.
After the loop finishes, the program should send an empty message to the receiver with a priority of 2 to tell the receiver that the sending is done. This can be done by calling the mq_send function with a message size of 0 and a priority of 2.
With these changes, the program should read the file in 4096-byte chunks, send each chunk through the message queue, and then send an empty message to the receiver when it reaches the end of the file.
#include <fcntl.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#define QUEUE_NAME "/cpsc351messagequeue"
#define MAX_MESSAGE_SIZE 4096
#define MAX_QUEUE_SIZE 8192
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <file-name>\n", argv[0]);
return 1;
}
// Open the message queue
mqd_t queue = mq_open(QUEUE_NAME, O_WRONLY);
if (queue == (mqd_t)-1) {
perror("Error opening message queue");
return 1;
}
// Open the file
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
// Read at most 4096 bytes from the file and send them through the message queue
char buffer[MAX_MESSAGE_SIZE];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, MAX_MESSAGE_SIZE, file)) > 0) {
if (mq_send(queue, buffer, bytes_read, 1) == -1) {
perror("Error sending message");
return 1;
}
}
// Send an empty message to the receiver with a priority of 2 to indicate that the sending is done
if (mq_send(queue, "", 0, 2) == -1) {
perror("Error sending message");
return 1;
}
// Close the file and message queue
fclose(file);
mq_close(queue);
return 0;
}
I'm new to socket programming and wanted to try something simple. This program can manipulate settings on my tv. All messages are 24 bytes. There may be one or more messages returned. I cannot figure out a good solution to get all of the messages without read() blocking on me.
What is below would be what I hoped to be a simple solution. It seems to work in a lot of example code I have found. However, what happens is after the first loop it seems to just block on the read() operation infinitely. If I remove the loop and just put multiple reads, the same thing happens. As long as I don't try to read more information that is sent, I'm ok.
I did try a couple of other things like turning off blocking, and adding a timer. neither worked. At this point I can live with a couple seconds of blocking. I just want the program to exit normally after the read.
adding output for a power_on command. It correctly outputs the two lines it should then blocks indefinitely.
Dans-MBP:~ mreff555$ ./tvthing
24: *SAPOWR0000000000000000
24: *SNPOWR0000000000000001
code below:
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/time.h>
#define PORT 20060
#define POWER_ON "*SCPOWR0000000000000001\n"
#define POWER_OFF "*SCPOWR0000000000000000\n"
#define POWER_STATUS "*SEPOWR################\n"
#define POWER_TOGGLE "*STPOWR################\n"
int main(int argc, char const * argv[])
{
struct sockaddr_in tvAddress;
struct hostent *host = gethostbyname("192.168.1.128");
memset(&tvAddress, 0, sizeof(tvAddress));
tvAddress.sin_family = AF_INET;
tvAddress.sin_addr.s_addr = htonl(INADDR_ANY);
tvAddress.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
tvAddress.sin_port = htons(PORT);
char sendBuffer[24] = {0};
char recBuffer[24] = {0};
int socket_fd;
if((socket_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
else
{
if(connect(socket_fd, (struct sockaddr *)&tvAddress, sizeof(struct sockaddr)))
{
perror("connection failed failed");
exit(EXIT_FAILURE);
}
memcpy(&sendBuffer, &POWER_STATUS, sizeof(sendBuffer));
write(socket_fd, sendBuffer, strlen(sendBuffer));
int ret;
while((ret = read(socket_fd, recBuffer, sizeof(recBuffer)) > 0))
{
printf("%d: %s\n", ret, recBuffer);
}
close(socket_fd);
}
}
You need to read until your buffer is full like this:
unsigned readLen = 0;
unsigned totalLen = sizeof(recBuffer);
while (readLen < totalLen) {
int ret = read(socket_fd, recBuffer + readLen, totalLen - readLen);
if (ret > 0) {
readLen += ret;
} else {
// error handling here
break;
}
}
This is needed because read() returns only the currently available amount of bytes which might be less than you have requested. From the corresponding man-page:
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
If you need to receive several responses you can put the described algorithm into a function and use it repeatedly. In any case you need to know how many responses to expect otherwise your read() will block because it seems that your TV's server is programmed to keep the connection open and it is client's responsibility to choose when to disconnect.
If you decide to make your application more sophisticated you can use one of the IO Multiplexing mechanisms to make your wait for response interruptable by timer or terminal input. For example:
while (true) {
pollfd fds[] = {
{ socket_fd, POLLIN, 0 },
{ STDIN_FILENO, POLLIN, 0 }
};
int ret = poll(fds, sizeof(fds) / sizeof(*fds), -1);
if (ret > 0) {
if (fds[0].revents & POLLIN) {
readResponse(); // read and process response
}
if (fds[1].revents & POLLIN) {
break; // exit on terminal input
}
}
}
As it turns out, select is designed exactly for that purpose. It checks the specified file descriptors for a specified time interval, and if successful repeats the process. Tweaking the time interval minimizes the blocking while allowing enough time for additional messages to come in.
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#define PORT 20060
#define POWER_ON "*SCPOWR0000000000000001\n"
#define POWER_OFF "*SCPOWR0000000000000000\n"
#define POWER_STATUS "*SEPOWR################\n"
#define POWER_TOGGLE "*STPOWR################\n"
int main(int argc, char const * argv[])
{
struct sockaddr_in tvAddress;
struct hostent *host = gethostbyname("192.168.1.128");
memset(&tvAddress, 0, sizeof(tvAddress));
tvAddress.sin_family = AF_INET;
tvAddress.sin_addr.s_addr = htonl(INADDR_ANY);
tvAddress.sin_addr.s_addr = ((struct in_addr*)(host->h_addr))->s_addr;
tvAddress.sin_port = htons(PORT);
char sendBuffer[24] = {0};
char recBuffer[24] = {0};
int socket_fd;
if((socket_fd = socket(AF_INET,SOCK_STREAM, 0)) < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
else
{
if(connect(socket_fd, (struct sockaddr *)&tvAddress, sizeof(struct sockaddr)))
{
perror("connection failed failed");
exit(EXIT_FAILURE);
}
struct timeval tv;
fd_set sockRead;
int selectStatus;
memcpy(&sendBuffer, &POWER_ON, sizeof(sendBuffer));
write(socket_fd, sendBuffer, strlen(sendBuffer));
do
{
FD_ZERO(&sockRead);
FD_SET(socket_fd, &sockRead);
tv.tv_sec = 2;
tv.tv_usec = 500000;
selectStatus = select(socket_fd + 1, &sockRead, NULL, NULL, &tv);
switch(selectStatus)
{
case -1:
perror("select()");
exit(EXIT_FAILURE);
break;
case 0:
break;
default:
printf("Ready for Reading\n");
read(socket_fd, recBuffer, sizeof(recBuffer));
printf("%s\n", recBuffer);
}
}while (selectStatus > 0);
close(socket_fd);
}
}
I am trying to develop a little application in C++, within a Linux environment, which does the following:
1) gets a data stream (a series of arrays of doubles) from the output of a 'black-box' and writes it to a pipe. The black-box can be thought as an ADC;
2) reads the data stream from the pipe and feeds it to another application which requires these data as stdin;
Unfortunately, I was not able to find tutorials or examples. The best way I found to realize this is summarized in the following test-bench example:
#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#define FIFO "/tmp/data"
using namespace std;
int main() {
int fd;
int res = mkfifo(FIFO,0777);
float *writer = new float[10];
float *buffer = new float[10];
if( res == 0 ) {
cout<<"FIFO created"<<endl;
int fres = fork();
if( fres == -1 ) {
// throw an error
}
if( fres == 0 )
{
fd = open(FIFO, O_WRONLY);
int idx = 1;
while( idx <= 10) {
for(int i=0; i<10; i++) writer[i]=1*idx;
write(fd, writer, sizeof(writer)*10);
}
close(fd);
}
else
{
fd = open(FIFO, O_RDONLY);
while(1) {
read(fd, buffer, sizeof(buffer)*10);
for(int i=0; i<10; i++) printf("buf: %f",buffer[i]);
cout<<"\n"<<endl;
}
close(fd);
}
}
delete[] writer;
delete[] buffer;
}
The problem is that, by running this example, I do not get a printout of all the 10 arrays I am feeding to the pipe, whereas I keep getting always the first array (filled by 1).
Any suggestion/correction/reference is very welcome to make it work and learn more about the behavior of pipes.
EDIT:
Sorry guys! I found a very trivial error in my code: in the while loop within the writer part, I am not incrementing the index idx......once I correct it, I get the printout of all the arrays.
But now I am facing another problem: when using a lot of large arrays, these are randomly printed out (the whole sequence is not printed); as if the reader part is not able to cope with the speed of the writer. Here is the new sample code:
#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#define FIFO "/tmp/data"
using namespace std;
int main(int argc, char** argv) {
int fd;
int res = mkfifo(FIFO,0777);
int N(1000);
float writer[N];
float buffer[N];
if( res == 0 ) {
cout<<"FIFO created"<<endl;
int fres = fork();
if( fres == -1 ) {
// throw an error
}
if( fres == 0 )
{
fd = open(FIFO, O_WRONLY | O_NONBLOCK);
int idx = 1;
while( idx <= 1000 ) {
for(int i=0; i<N; i++) writer[i]=1*idx;
write(fd, &writer, sizeof(float)*N);
idx++;
}
close(fd);
unlink(FIFO);
}
else
{
fd = open(FIFO, O_RDONLY);
while(1) {
int res = read(fd, &buffer, sizeof(float)*N);
if( res == 0 ) break;
for(int i=0; i<N; i++) printf(" buf: %f",buffer[i]);
cout<<"\n"<<endl;
}
close(fd);
}
}
}
Is there some mechanism to implement in order to make the write() wait until read() is still reading data from the fifo, or am I missing something trivial also in this case?
Thank you for those who have already given answers to the previous version of my question, I have implemented the suggestions.
The arguments to read and write are incorrect. Correct ones:
write(fd, writer, 10 * sizeof *writer);
read(fd, buffer, 10 * sizeof *buffer);
Also, these functions may do partial reads/writes, so that the code needs to check the return values to determine whether the operation must be continued.
Not sure why while( idx <= 10) loop in the writer, this loop never ends. Even on a 5GHz CPU. Same comment for the reader.
Is it possible to use getline(cin,buffer); at the top of my program, then have a "animated menu" still running below it?
For example (very basic):
#include <iostream>
#include <string>
using namespace std;
int stringLen=0;
string buffer;
getline(cin, buffer);
for (int i = 0; i < kMaxWait;i++)
{
printf("counter waiting for user input %d",i);
if (1 >= buffer.length())
break;
}
Would I have to fork that loop somehow so it would keep counting and display the counter until the user enters something??
One possible answer, given in the comments, is to use threads. But it's not necessary, there's a way to do this without threads.
Make stdin a non-blocking file descriptor.
Wait for stdin to become readable, via poll()/select(), in the meantime do your animation, etc...
Make stdin a blocking file descriptor, again.
Use std::getline().
There are also some ancillary issues to consider, such as the buffering that comes from std::streambuf, so before doing all that, check if there's already something to read from std::cin, first.
This is something I used sometime ago. It's quite rudimentary, but you can get the gist of the process - using poll. It returns true if there is input, and puts it in str, false otherwise. So, you can put this in your loop somewhere, and take action when there is input.
bool polled_input(std::string& str)
{
struct pollfd fd_user_in;
fd_user_in.fd = STDIN_FILENO;
fd_user_in.events = POLLIN;
fd_user_in.revents = 0;
int rv = poll(&fd_user_in, 1, 0);
if (rv == -1) {/* error */}
else if (rv == 0) return false;
else if (fd_user_in.revents & POLLIN)
{
char buffer[MAX_BUFF_SIZE];
int rc = read(STDIN_FILENO, buffer, MAX_BUFF_SIZE-1);
if (rc >= 0)
{
buffer[rc]='\0';
str = std::string(buffer);
return true;
}
else {/* error */}
}
else {/* error */}
}
select is meant for this, multiplexed, blocking I/O. It can be done without a poll I think:
#include <iostream>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **arg)
{
const int time_in_secs = 10;
const int buffer_size = 1024;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
struct timeval tv;
tv.tv_sec = time_in_secs;
tv.tv_usec = 0;
int ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
if (!ret)
{
std::cout << "Timeout\n";
exit(1);
}
char buf[buffer_size];
if (FD_ISSET(STDIN_FILENO, &readfds))
{
int len = read(STDIN_FILENO, buf, buffer_size);
buf[len] = '\0';
}
std::cout << "You typed: " << buf << "\n";
return 0;
}
I need a C/C++ API that allows me to list the running processes on a Linux system, and list the files each process has open.
I do not want to end up reading the /proc/ file system directly.
Can anyone think of a way to do this?
http://procps.sourceforge.net/
http://procps.cvs.sourceforge.net/viewvc/procps/procps/proc/readproc.c?view=markup
Is the source of ps and other process tools. They do indeed use proc (indicating it is probably the conventional and best way). Their source is quite readable. The file
/procps-3.2.8/proc/readproc.c
May be useful. Also a useful suggestion as posted by ephemient is linking to the API provided by libproc, which should be available in your repo (or already installed I would say) but you will need the "-dev" variation for the headers and what-not.
Good Luck
If you do not want to read from '/proc. Then you can consider writing a Kernel module which will implement your own system call. And your system call should be written so that it can obtain the list of current processes, such as:
/* ProcessList.c
Robert Love Chapter 3
*/
#include < linux/kernel.h >
#include < linux/sched.h >
#include < linux/module.h >
int init_module(void) {
struct task_struct *task;
for_each_process(task) {
printk("%s [%d]\n",task->comm , task->pid);
}
return 0;
}
void cleanup_module(void) {
printk(KERN_INFO "Cleaning Up.\n");
}
The code above is taken from my article here at http://linuxgazette.net/133/saha.html.Once you have your own system call, you can call it from your user space program.
Here you go (C/C++):
You could have found it here:
http://ubuntuforums.org/showthread.php?t=657097
Essentially, what it does is loop through all numeric folders in /proc/<pid>, and then it does a readlink on /proc/<pid>/exe, or if you want the command-line-arguments cat /proc/<pid>/cmdline
The file-descriptors open by the process are in /proc/<pid>/fd/<descriptor>, and you get the file name by doing a readlink on each symlink, e.g. readlink /proc/<pid>/fd/<descriptor>. fd can be a device, such as /dev/null, a socket, or a file, and potentially more.
#include <unistd.h>
ssize_t readlink(const char *path, char *buf, size_t bufsiz);
On success, readlink() returns the number of bytes placed in buf.
On error, -1 is returned and errno is set to indicate the error.
This is, by the way, the same that readproc.c does (or at least did).
Of course, hopefully they did it without buffer overflow possiblity.
#ifndef __cplusplus
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h> // for opendir(), readdir(), closedir()
#include <sys/stat.h> // for stat()
#ifdef __cplusplus
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#endif
#define PROC_DIRECTORY "/proc/"
#define CASE_SENSITIVE 1
#define CASE_INSENSITIVE 0
#define EXACT_MATCH 1
#define INEXACT_MATCH 0
int IsNumeric(const char* ccharptr_CharacterList)
{
for ( ; *ccharptr_CharacterList; ccharptr_CharacterList++)
if (*ccharptr_CharacterList < '0' || *ccharptr_CharacterList > '9')
return 0; // false
return 1; // true
}
int strcmp_Wrapper(const char *s1, const char *s2, int intCaseSensitive)
{
if (intCaseSensitive)
return !strcmp(s1, s2);
else
return !strcasecmp(s1, s2);
}
int strstr_Wrapper(const char* haystack, const char* needle, int intCaseSensitive)
{
if (intCaseSensitive)
return (int) strstr(haystack, needle);
else
return (int) strcasestr(haystack, needle);
}
#ifdef __cplusplus
pid_t GetPIDbyName(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)
#else
pid_t GetPIDbyName_implements(const char* cchrptr_ProcessName, int intCaseSensitiveness, int intExactMatch)
#endif
{
char chrarry_CommandLinePath[100] ;
char chrarry_NameOfProcess[300] ;
char* chrptr_StringToCompare = NULL ;
pid_t pid_ProcessIdentifier = (pid_t) -1 ;
struct dirent* de_DirEntity = NULL ;
DIR* dir_proc = NULL ;
int (*CompareFunction) (const char*, const char*, int) ;
if (intExactMatch)
CompareFunction = &strcmp_Wrapper;
else
CompareFunction = &strstr_Wrapper;
dir_proc = opendir(PROC_DIRECTORY) ;
if (dir_proc == NULL)
{
perror("Couldn't open the " PROC_DIRECTORY " directory") ;
return (pid_t) -2 ;
}
// Loop while not NULL
while ( (de_DirEntity = readdir(dir_proc)) )
{
if (de_DirEntity->d_type == DT_DIR)
{
if (IsNumeric(de_DirEntity->d_name))
{
strcpy(chrarry_CommandLinePath, PROC_DIRECTORY) ;
strcat(chrarry_CommandLinePath, de_DirEntity->d_name) ;
strcat(chrarry_CommandLinePath, "/cmdline") ;
FILE* fd_CmdLineFile = fopen (chrarry_CommandLinePath, "rt") ; // open the file for reading text
if (fd_CmdLineFile)
{
fscanf(fd_CmdLineFile, "%s", chrarry_NameOfProcess) ; // read from /proc/<NR>/cmdline
fclose(fd_CmdLineFile); // close the file prior to exiting the routine
if (strrchr(chrarry_NameOfProcess, '/'))
chrptr_StringToCompare = strrchr(chrarry_NameOfProcess, '/') +1 ;
else
chrptr_StringToCompare = chrarry_NameOfProcess ;
//printf("Process name: %s\n", chrarry_NameOfProcess);
//printf("Pure Process name: %s\n", chrptr_StringToCompare );
if ( CompareFunction(chrptr_StringToCompare, cchrptr_ProcessName, intCaseSensitiveness) )
{
pid_ProcessIdentifier = (pid_t) atoi(de_DirEntity->d_name) ;
closedir(dir_proc) ;
return pid_ProcessIdentifier ;
}
}
}
}
}
closedir(dir_proc) ;
return pid_ProcessIdentifier ;
}
#ifdef __cplusplus
pid_t GetPIDbyName(const char* cchrptr_ProcessName)
{
return GetPIDbyName(cchrptr_ProcessName, CASE_INSENSITIVE, EXACT_MATCH) ;
}
#else
// C cannot overload functions - fixed
pid_t GetPIDbyName_Wrapper(const char* cchrptr_ProcessName, ... )
{
int intTempArgument ;
int intInputArguments[2] ;
// intInputArguments[0] = 0 ;
// intInputArguments[1] = 0 ;
memset(intInputArguments, 0, sizeof(intInputArguments) ) ;
int intInputIndex ;
va_list argptr;
va_start( argptr, cchrptr_ProcessName );
for (intInputIndex = 0; (intTempArgument = va_arg( argptr, int )) != 15; ++intInputIndex)
{
intInputArguments[intInputIndex] = intTempArgument ;
}
va_end( argptr );
return GetPIDbyName_implements(cchrptr_ProcessName, intInputArguments[0], intInputArguments[1]);
}
#define GetPIDbyName(ProcessName,...) GetPIDbyName_Wrapper(ProcessName, ##__VA_ARGS__, (int) 15)
#endif
int main()
{
pid_t pid = GetPIDbyName("bash") ; // If -1 = not found, if -2 = proc fs access error
printf("PID %d\n", pid);
return EXIT_SUCCESS ;
}
If you don't do it, then I guess whatever API you will use will end up reading the /proc filesystem. Here are some examples of program doing this:
qps
htop
procps
But unfortunately, that does not constitute an API.
PS and every other tool(EXCEPT for Kernel Modules) read from /proc. /proc is a special filesystem created on the fly by the kernel so that user mode processes can read data that will otherwise only be available for the kernel.
The recommended way is therefore, reading from /proc.
You can quickly intuitively look at the /proc filesystem to see how its structured.
For every process there is a /proc/pid where pid is the process id number. Inside this folder there are several files which include different data about the current process.
If you run
strace ps -aux
you will see how the program ps reads this data from /proc.
The only way to do this without reading /proc would be to call "ps aux", go through every line, read the second column (the PID) and call lsof -p [PID] with it.
...I'd suggest reading /proc ;)
There's a library libprocps from the procps-ng project. On Ubuntu 13.04, if you do strace ps, then you can see that ps uses libprocps.
Reading proc is not too bad. I can't show you in C++, but the following D code should point you in the right direction:
import std.stdio;
import std.string;
import std.file;
import std.regexp;
import std.c.linux.linux;
alias std.string.split explode;
string srex = "^/proc/[0-9]+$";
string trex = "State:[ \t][SR]";
RegExp rex;
RegExp rext;
string[] scanPidDirs(string target)
{
string[] result;
bool callback(DirEntry* de)
{
if (de.isdir)
{
if (rex.find(de.name) >= 0)
{
string[] a = explode(de.name, "/");
string pid = a[a.length-1];
string x = cast(string) std.file.read(de.name ~ "/status");
int n = rext.find(x);
if (n >= 0)
{
x = cast(string) std.file.read(de.name ~ "/cmdline");
// This is null terminated
if (x.length) x.length = x.length-1;
a = explode(x, "/");
if (a.length)
x = a[a.length-1];
else
x = "";
if (x == target)
{
result ~= pid ~ "/" ~x;
}
}
}
}
return true;
}
listdir("/proc", &callback);
return result.dup;
}
void main(string[] args)
{
rex= new RegExp(srex);
rext= new RegExp(trex);
string[] a = scanPidDirs(args[1]);
if (!a.length)
{
writefln("Not found");
return;
}
writefln("%d matching processes", a.length);
foreach (s; a)
{
string[] p = explode(s, "/");
int pid = atoi(p[0]);
writef("Stop %s (%d)? ", s, pid);
string r = readln();
if (r == "Y\n" || r == "y\n")
kill(pid, SIGUSR1);
}
}
Easy way to fin pid of any process by name
pid_t GetPIDbyName(char* ps_name)
{
FILE *fp;
char *cmd=(char*)calloc(1,200);
sprintf(cmd,"pidof %s",ps_name);
fp=popen(cmd,"r");
fread(cmd,1,200,fp);
fclose(fp);
return atoi(cmd);
}