Related
the last two days I've been trying to come up with a suitable solution to make this shell simulator that executes linux command run with fork(), dup2(), close(), pipes() and wait() functions. Up to now I have achieved an implementation that leaves me unsatisfied because I have been able to execute a command but I can't get the information from the stdout to be passed to a following command by means of pipes, for example, when writing ls 'l | wc, it would be possible to execute the first command, second of the second that will be carried out according to the information obtained with the first. I would appreciate if someone could clarify what the error in my code is so that I can implement something that allows me to enter a sequence of more than 3 commands that can share their information through the pipe line and print a final result. :)
#include <errno.h> //presentan un informe de error
#include <iostream> //Emplear cin cout c++
#include <stdio.h> //librerÃa estandar de entrada y salida
#include <string.h> //Para manejo de strigs
#include <sys/types.h> // obtener información sobre ficheros
#include <sys/wait.h> //permite el uso de wait
#include <unistd.h> //para poder llamar fork
using namespace std;
// Strig processor
int strProcessor(char *words[50]) {
char command[500]; // Array of char that recieves a full command line
cout << "myshell$"; // print specified value
cin.getline(command, 500); // getline instead of simple cin to read spaces
char *word =
strtok(command, " "); // Pointer for each token starting at the first one
int index = -1;
while (word != NULL) { // Iterate the array to save each string
index += 1; // increase the number of the index
words[index] = word; // Inicialize the each necessary space
word = strtok(NULL, " "); // Save next string of the pointer
}
return index; // Return index because it will be important for later on
}
// Single command processor
int splitCommand(char *words[50], char *singleCommand[50], int index, int start) {
int newIndex = 0; //aux
while (start <= index && strcmp(words[start], "|")) {
singleCommand[newIndex] = words[start];
start += 1;
newIndex += 1;
}
start += 1;
singleCommand[newIndex] = NULL;
return start;
}
//Count the number of commands
int commandCounter(char *words[50], int index){
int counter = 1;
for(int i=0;i<=index;i++) {
if (!strcmp(words[i],"|") && i != index) {
counter += 1;
}
}
return counter;
}
int process(){
int READ = 0;
int WRITE = 1;
int fd[20][2]; // file directory for pipe
int index = -1; // useful index
char *words[50]; // Save all tokens in an array
int start = 0; // useful index
char *singleCommand[20]; // Save an individual command with NULL at the end
//Handling no command written
while (index == -1) {
index = strProcessor(words);
}
//Exit if user types it
if (!strcmp(words[0], "exit")) {
return 0;
}
//Establish the number of commands to exe
int commandNumber = commandCounter(words, index);
//Create a piper for each command
for (int i = 0; i < commandNumber - 1;i++) {
pipe(fd[i]);
}
for (int i = 0; i < commandNumber;i++) {
start = splitCommand(words, singleCommand, index, start); // Get first command
int pid=fork();
if (pid == 0) {
if (i == 0) {
dup2(fd[i][1], STDOUT_FILENO);
close(fd[i][1]);
close(fd[i][0]);
execvp(singleCommand[0], singleCommand);
} else if (i > 0) {
dup2(fd[i-1][0], STDOUT_FILENO);
close(fd[i-1][1]);
close(fd[i-1][0]);
dup2(fd[i][1], STDOUT_FILENO);
close(fd[i][1]);
close(fd[i][0]);
execvp(singleCommand[0], singleCommand);
}
} else {
if (i == 0) {
int stat;
wait(&stat);
close(fd[i][1]);
close(fd[i][0]);
cout << "Process: " << pid << " exits with status:" << stat << endl;
} else if (i > 0) {
int stat;
wait(&stat);
wait(&stat);
close(fd[i-1][1]);
close(fd[i-1][0]);
close(fd[i][1]);
close(fd[i][0]);
cout << "Process: " << pid << " exits with status:" << stat << endl;
}
}
}
return 0;
}
int main() {
process();
return 0;
}
Example input:
ls -alF / | grep bin | cat -n
The displayed messages of the shell should be like:
Process 16480 exits with 0
Process 16481 exits with 0
1 drwxr-xr-x 2 root root 4096 Mar 30 04:07 bin/
2 drwxr-xr-x 2 root root 12288 Mar 30 04:07 sbin/
Process 16482 exits with 0
ls -alF / | grep bin | tr a-z A-Z | rev | cat -n
The displayed messages of the shell should be like:
Process 16554 exits with 0
Process 16555 exits with 0
Process 16556 exits with 0
1 /NIB 70:40 03 RAM 6904 TOOR TOOR 2 X-RX-RXWRD
2 /NIBS 70:40 03 RAM 88221 TOOR TOOR 2 X-RX-RXWRD
Process 16557 exits with 0
Process 16558 exits with 0
I'm making work to school and I have a problem with "cut" command when I try launch this command in c++. So this is my exercise-> I want launch this command in C++ -> "cut -d':' -f5 < file" I wrote text from the file to variable input in main function.
expected as result of command -> "five"
but I got only an error message "cut: the delimiter must be a single character
Try 'cut --help' for more information."
do you know why ? Thanks for help :)
this is my test code:
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
#include <string>
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdlib>
const int BUFFER_SIZE = 4096;
using namespace std;
char *argCat[] = { "cat", (char *)0 };
char *argEcho[] = { "echo", "Hello", (char *)0 };
char *argCut[] = { "cut", "-d':'", "-f5", (char *)0};
char *stringCharConvertor(string paString)
{
char * temp = new char[paString.size() + 1];
std::copy(paString.begin(), paString.end(), temp);
temp[paString.size()] = '\0';
return temp;
}
void executeCommand(char** paCommand, string &paOutput, string &paInput)
{
char** arg = paCommand;
bool validInput = paInput == "" ? false : true;
int PARRENT_TO_CHILD[2];
int CHILD_TO_PARRENT[2];
if(pipe(CHILD_TO_PARRENT) < 0)
perror("pipe error");
if(validInput)
{
if(pipe(PARRENT_TO_CHILD) < 0)
perror("pipe error");
char* temp = stringCharConvertor(paInput);
write(PARRENT_TO_CHILD[1], temp, strlen(temp));
close(PARRENT_TO_CHILD[1]);
}
pid_t PID = fork();
if(PID > 0)
{
int s;
char buffer[BUFFER_SIZE+1];
memset(buffer, '\0', sizeof(buffer));
close[CHILD_TO_PARRENT[1]];
wait(&s);
if(read(CHILD_TO_PARRENT[0], buffer, BUFFER_SIZE) < 0)
printf("error ");
close(CHILD_TO_PARRENT[0]);
paOutput = buffer;
if(validInput)
close(PARRENT_TO_CHILD[0]);
cout << "\n"+paInput;
}
else
if(PID == 0)
{
dup2(CHILD_TO_PARRENT[1], STDOUT_FILENO);
close(CHILD_TO_PARRENT[1]);
close(CHILD_TO_PARRENT[0]);
if(validInput)
{
dup2(PARRENT_TO_CHILD[0], STDIN_FILENO);
close(PARRENT_TO_CHILD[0]);
close(PARRENT_TO_CHILD[1]);
}
if(execvp(arg[0], arg) < 0)
close(CHILD_TO_PARRENT[1]);
}
}
int main()
{
string input = "one:two:three:four:five:six:seven:eight:nine:ten";
string output = "";
executeCommand(argCut, output, input);
cout << "\n INPUT: "+input <<endl;
cout << "\n OUTPUT: "+output <<endl;
return 0;
}
you should try to replace
char *argCut[] = { "cut", "-d':'", "-f5", (char *)0};
by
char *argCut[] = { "cut", "-d:", "-f5", (char *)0};
no need for quotes
here's some rationale:
running strace on your code shows:
[pid 7641] execve("/usr/bin/cut", ["cut", "-d':'", "-f5"], [/* 85 vars */]) = 0
which is more or less equivalent to the call
/bin/cut "-d':'" "-f5"
which gives the same error
In fact the shell does remove the extra quotes as you may see:
$ echo one:two:three:four:five | strace -f /bin/cut -d':' -f5
execve("/bin/cut", ["/bin/cut", "-d:", "-f5"], [/* 85 vars */]) = 0
=> success
whereas:
$ echo one:two:three:four:five | strace -f /bin/cut "-d':'" -f5
execve("/bin/cut", ["/bin/cut", "-d':'", "-f5"], [/* 85 vars */]) = 0
=> failure
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);
}
I've written a function to convert datetimes from one format to another -
int convertDateTime(char* source_fmt,char* dest_fmt,char* source,char* dest)
{
struct tm tmpptr;
if (strptime(source,source_fmt,&tmpptr) == NULL)
{
strcpy(dest,"");
return -1;
}
strftime(dest,100,dest_fmt,&tmpptr);
return 0;
}
It works fine for most formats, But when I use format = "%y%j", all I get is 10001; the julian day does not work.
I'm using gcc on solaris 10. Any idea what i need to change?
Check the expected behaviour of strptime, in some implementations it is greedy and will consume as many digits as it can.
This has been a problem for me on MacOS, the implementation changed in 10.5 with the UNIX standards compliance efforts. Before this the following call worked fine.
strptime("20071124", "%Y%m%d")
As of 10.5 you have to do the following to get it to work.
#define _NONSTD_SOURCE
Your compiler libraries and OS may differ though.
I can tell you what the problem is. When you use strptime() with the %j format, it only populates the tm_yday field on your struct tm. This isn't limited to Solaris by the way, CygWin gcc is doing the same thing.
Because your strftime() is most likely using other fields (tm_mon and tm_mday), and these are still set to zero, that's why you're getting the wrong day of the year.
The following code illustrates this:
#include <time.h>
#include <stdio.h>
#include <string.h>
#define dump() \
printf ("DEBUG tm_sec = %d, tm_min = %d, tm_hour = %d, tm_mday = %d, " \
"tm_mon = %d, tm_year = %d, tm_wday = %d, tm_yday = %d, " \
"tm_isdst = %d\n", \
tmpptr.tm_sec, tmpptr.tm_min, tmpptr.tm_hour, tmpptr.tm_mday, \
tmpptr.tm_mon, tmpptr.tm_year, tmpptr.tm_wday, tmpptr.tm_yday, \
tmpptr.tm_isdst)
int convertDateTime(char* source_fmt,char* dest_fmt,char* source,char* dest) {
struct tm tmpptr;
memset (&tmpptr,0,sizeof(tmpptr));
dump();
if (strptime(source,source_fmt,&tmpptr) == NULL) {
strcpy(dest,"");
return -1;
}
dump();
strftime(dest,100,dest_fmt,&tmpptr);
return 0;
}
int main (int argc, char *argv[]) {
char dest[1000];
printf ("1: [%s]\n", argv[1]);
printf ("2: [%s]\n", argv[2]);
printf ("3: [%s]\n", argv[3]);
printf ("retval = %d\n", convertDateTime (argv[1],argv[2],argv[3],dest));
printf ("=: [%s]\n", dest);
return 0;
}
When you run it thus:
pax> date ; ./tetsprog %y%j %Y-%m-%d 10162
you get:
Tue Aug 3 12:46:13 WAST 2010
1: [%y%j]
2: [%Y-%m-%d]
3: [10162]
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 0, tm_mon = 0, tm_year = 0,
tm_wday = 0, tm_yday = 0, tm_isdst = 0
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 0, tm_mon = 0, tm_year = 110,
tm_wday = 0, tm_yday = 161, tm_isdst = 0
retval = 0
=: [2010-01-00]
Fixing it is tricky, I'm not aware of any standard time function that will rebuild tm_mday and tm_mon from tm_yday.
But, if you're stuck for a solution, try this out:
static void fixIt (struct tm *t) {
static int monthDaysN[] = {31,28,31,30,31,30,31,31,30,31,30,31};
static int monthDaysL[] = {31,29,31,30,31,30,31,31,30,31,30,31};
int *monthDays = monthDaysN;
int base = 0;
int i;
if (((t->tm_year + 1900) % 4) == 0) monthDays = monthDaysL;
if (((t->tm_year + 1900) % 100) == 0) monthDays = monthDaysN;
if (((t->tm_year + 1900) % 400) == 0) monthDays = monthDaysL;
// Leap years irrelevant for January dates.
if (t->tm_yday < 31) monthDays = monthDaysN;
for (i = 0; i < 12; i++) {
if (t->tm_yday - base < monthDays[i]) {
t->tm_mday = t->tm_yday - base + 1;
t->tm_mon = i;
return;
}
base += monthDays[i];
}
}
It will set those two fields based on tm_year and tm_yday and it's a bit of a kludge but will get you going at least (and maybe you'll find a better way).
I would insert a call to this in your convert function and only call it under specific circumstances so as not to overwrite values that are already set:
int convertDateTime(char* source_fmt,char* dest_fmt,char* source,char* dest) {
struct tm tmpptr;
memset (&tmpptr,0,sizeof(tmpptr));
dump();
if (strptime(source,source_fmt,&tmpptr) == NULL) {
strcpy(dest,"");
return -1;
}
if ((tmpptr.tm_yday != 0) && (tmpptr.tm_mday == 0))
fixIt (&tmpptr);
dump();
strftime(dest,100,dest_fmt,&tmpptr);
return 0;
}
which gives:
pax> date ; testprog %y%j %Y-%m-%d 10162
Tue Aug 3 13:34:36 WAST 2010
1: [%y%j]
2: [%Y-%m-%d]
3: [10162]
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 0, tm_mon = 0, tm_year = 0,
tm_wday = 0, tm_yday = 0, tm_isdst = 0
DEBUG tm_sec = 0, tm_min = 0, tm_hour = 0,
tm_mday = 11, tm_mon = 5, tm_year = 110,
tm_wday = 0, tm_yday = 161, tm_isdst = 0
retval = 0
=: [2010-06-11]
And, like all code here, you should test it thoroughly. I'm pretty certain I got all the edge cases but, since you haven't paid me cold hard cash for my services, you should assume this is general advice only, not a specific solution :-)
Update
The original answer (below) presumed that the "%y%j" format was used on the output (strftime) not the input (strptime). The mktime function will compute yday from valid info, but it doesn't work the other way.
If you want to decode something like that you need to do it manually. Some example code follows. It has had minimal testing and almost certainly has bugs. You may need to alter ir, depending in the input format you want.
#include <string>
#include <ctime>
#include <cassert>
#include <iostream>
int GetCurrentYear()
{
time_t tNow(::time(NULL));
struct tm tmBuff = *::localtime(&tNow);
return tmBuff.tm_year;
}
bool IsLeapYear(int nYear)
{
if (0 == (nYear%1000)) return true;
if (0 == (nYear%100)) return false;
if (0 == (nYear%4)) return true;
return false;
}
// nMonth = 0 (Jan) to 11 (Dec)
int DaysPerMonth(int nMonth, bool bLeapYear)
{
// J F M A M J J A S O N D
int nDays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
assert(nMonth>=0 && nMonth<12);
int nRet = nDays[nMonth];
if (bLeapYear && nMonth==1)
nRet++;
return nRet;
}
// sDate is in the format YYDDD where YY is the last 2 digits of the year
// and YYY is the day of the year (1/1 = 1, 31/12 = 365 for non-leap year)
bool DecodeDate(const std::string &sDate, struct tm &tmBuff)
{
if (sDate.length() != 5 ||
!isdigit(sDate[0]) ||
!isdigit(sDate[1]) ||
!isdigit(sDate[2]) ||
!isdigit(sDate[3]) ||
!isdigit(sDate[4]))
{
return false;
}
::memset(&tmBuff, 0, sizeof(struct tm));
tmBuff.tm_year = GetCurrentYear();
// drop last 2 digits
tmBuff.tm_year -= tmBuff.tm_year%100;
// replace last 2 digits
tmBuff.tm_year += ::atoi(sDate.substr(0, 2).c_str());
tmBuff.tm_yday = ::atoi(sDate.substr(2).c_str());
int nDays(tmBuff.tm_yday);
bool bLeapYear(IsLeapYear(1900 + tmBuff.tm_year));
int nTmp = DaysPerMonth(0, bLeapYear);
while (nTmp < nDays)
{
nDays -= nTmp;
tmBuff.tm_mon++;
nTmp = DaysPerMonth(tmBuff.tm_mon, bLeapYear);
}
tmBuff.tm_mday = nDays;
::mktime(&tmBuff);
return true;
}
int main(int argc, char *argv[])
{
for (int i=1; i<argc; i++)
{
struct tm tmBuff;
DecodeDate(argv[i], tmBuff);
const size_t nSize(128);
char szBuff[nSize];
strftime(szBuff, nSize, "%A, %d %B %Y", &tmBuff);
std::cout << argv[i] << '\t' << szBuff << std::endl;
}
return 0;
}
================================================
C:\Dvl\Tmp>Test.exe 07123 08123 08124
07123 Thursday, 03 May 2007
08123 Friday, 02 May 2008
08124 Saturday, 03 May 2008
End Update
After you call strptime(), call mktime() which will populate any missing members of the struct. Also, you should zero out the struct before beginning.
#include <string>
#include <ctime>
int convertDateTime(const std::string &sSourceFmt,
const std::string &sDestFmt,
const std::string &sSource,
std::string &sDest)
{
struct tm tmbuff = { 0 };
if (::strptime(sSource.c_str(), sSourceFmt.c_str(), &tmbuff) != NULL)
{
::mktime(&tmbuff);
const size_t nSize(256);
char szBuff[nSize+1] = "";
if (::strftime(szBuff, nSize, sDestFmt.c_str(), &tmbuff))
{
sDest = szBuff;
return 0;
}
}
sDest.clear();
return -1;
}
I have to call ping from c++ code.I'd like to easily read the output for further utilizations.
I have come up with two solutions:
use a fork and a pipe, redirect ping output to the pipe and then parse it
find a library suited for the purpose to use a ping(ip_addresss) function directly
I'd like the latter but i didn't find anything that was clearly a standard solution.
How would you do it ?
From the educational point of view invoking an external binary is very inadvisable. Especially for a simple task such as sending an ICMP echo request, you should learn a bit of socket.
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#define PACKETSIZE 64
struct packet
{
struct icmphdr hdr;
char msg[PACKETSIZE-sizeof(struct icmphdr)];
};
int pid=-1;
struct protoent *proto=NULL;
int cnt=1;
/*--------------------------------------------------------------------*/
/*--- checksum - standard 1s complement checksum ---*/
/*--------------------------------------------------------------------*/
unsigned short checksum(void *b, int len)
{
unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;
for ( sum = 0; len > 1; len -= 2 )
sum += *buf++;
if ( len == 1 )
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
/*--------------------------------------------------------------------*/
/*--- ping - Create message and send it. ---*/
/* return 0 is ping Ok, return 1 is ping not OK. ---*/
/*--------------------------------------------------------------------*/
int ping(char *adress)
{
const int val=255;
int i, sd;
struct packet pckt;
struct sockaddr_in r_addr;
int loop;
struct hostent *hname;
struct sockaddr_in addr_ping,*addr;
pid = getpid();
proto = getprotobyname("ICMP");
hname = gethostbyname(adress);
bzero(&addr_ping, sizeof(addr_ping));
addr_ping.sin_family = hname->h_addrtype;
addr_ping.sin_port = 0;
addr_ping.sin_addr.s_addr = *(long*)hname->h_addr;
addr = &addr_ping;
sd = socket(PF_INET, SOCK_RAW, proto->p_proto);
if ( sd < 0 )
{
perror("socket");
return 1;
}
if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
{
perror("Set TTL option");
return 1;
}
if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )
{
perror("Request nonblocking I/O");
return 1;
}
for (loop=0;loop < 10; loop++)
{
int len=sizeof(r_addr);
if ( recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, &len) > 0 )
{
return 0;
}
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = pid;
for ( i = 0; i < sizeof(pckt.msg)-1; i++ )
pckt.msg[i] = i+'0';
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = cnt++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
if ( sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 )
perror("sendto");
usleep(300000);
}
return 1;
}
/*--------------------------------------------------------------------*/
/*--- main - look up host and start ping processes. ---*/
/*--------------------------------------------------------------------*/
int main(int argc, char *argv[])
{
if (ping("www.google.com"))
printf("Ping is not OK. \n");
else
printf("Ping is OK. \n");
return 0;
}
I would go with your first option. Linux is built around the concept of having small, specialized apps which do one thing really well, communicating with pipes. Your app shouldn't include a library to implement ping, since there is already a built-in command to do it, and it works very well!
Check out BusyBox's source for 'ping' - you can use the ping4 and ping6 functions. Just be mindful of the GPL.
Spawning 'ping' should work too - check out popen(2) for a simpler API that also runs a shell. If it's a problem, pipe + fork + exec should work.
how about https://github.com/octo/liboping ?
#include <oping.h>
int main(){
// run ping 100times
for (uint32_t i=0; i< 100; i++){
pingobj_t * pingObj = ping_construct();
ping_host_add(pingObj, "www.gmx.de");
auto startTime = std::chrono::high_resolution_clock::now();
auto ret = ping_send(pingObj);
auto endTime = std::chrono::high_resolution_clock::now();
if (ret > 0){
auto duration = (double)std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count()/1000.0;
std::cout << "success -- ping in " << duration << "ms" << std::endl;
} else {
std::cout << "failed" << std::endl;
}
ping_destroy(pingObj);
// wait 1sec
std::this_thread::sleep_for(std::chrono::milliseconds (1000));
}
}
liboping should be present in most linux systems
install liboping-dev (ex: sudo apt install liboping-dev)
linking against liboping
I've managed to do like this:
I use popen which basically creates a pipe, fork and exec
Then, if I need, i can wait with pclose.