Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

noahgolm

macrumors member
Original poster
Aug 18, 2010
65
0
Hi, I have a slight problem here. I am planning to develop a simple app (with a GUI) where a user can enter an ip address, and the computer tells if it is up or not. I am planning to use the system function here. I already have a bash script which accomplishes this, but I wonder how I can use it if system() only takes one-line arguments. Here's the bash script:
Code:
#!/bin/bash
echo "Enter an IP address: "
read ip
if ! ping -c 1 -W 5 "$ip" &>/dev/null ; then
echo "$ip is down"
else
echo "$ip is up"
fi
How can I put this in an objective-c app?
Thank you!
 
There's really only one command you need to run, the ping. Test the result of system, and act accordingly.

-Lee
 
You really are only running a single line
Code:
ping -c 1 -W 5 "$ip"
the rest is wrapper code you should implement in Objective-C.

EDIT: lee1210 beat me to it.

B
 
Thanks everyone for the help so far. I've managed to get it to the point of a C program (to test the code), which can ping and display the result, but I don't know how to make the program actually test whether it's up (as in my "if [ping is successful] then [echo host is up]").
In my bash, it accomplishes this with the "if ! ping -c 1 -W 5 "$ip" &>/dev/null" line, followed by the "then" statement. How can I recreate this, if I may ask?
 
How can I recreate this, if I may ask?
Use the return code (exit status) of the ping, it's zero if up, non-zero if down. That's what the shell script is using.

man 3 system said:
The system() function returns the exit status of the shell as returned by
waitpid(2), or -1 if an error occurred when invoking fork(2) or
waitpid(2). A return value of 127 means the execution of the shell
failed.

B
 
Thanks! I got it! I just incorporated the entire "if" statement into one line, which I'm not used to. I did this:
Code:
if ping -c 1 -W 5 %s &>/dev/null ; then echo "host is up"; else echo "host is down" ; fi
 
Thanks! I got it! I just incorporated the entire "if" statement into one line, which I'm not used to. I did this:
Code:
if ping -c 1 -W 5 %s &>/dev/null ; then echo "host is up"; else echo "host is down" ; fi

=( That is not so good.

Code:
if(system(pingGoesHere) == 0) {
  printf("Host is up\n");
} else {
  printf("Host is down\n");
}

Doing it like this allows you to do whatever you want with the result. Your version just gets some text in stdout, which is inflexible.

-Lee
 
THe problem here is that I can't seem to use a C variable in the system() function! In my pinging, I use system("ping -c 1 -W 5 %s &>/dev/null", ip) but it cannot read this! Is there any way to resolve this? And I still thank you for the MUCH better method for the if statement.
 
THe problem here is that I can't seem to use a C variable in the system() function! In my pinging, I use system("ping -c 1 -W 5 %s &>/dev/null", ip) but it cannot read this! Is there any way to resolve this? And I still thank you for the MUCH better method for the if statement.

1. What did you expect to happen?
2. What actually did happen?

If you're expecting system() to act like sprintf(), you are deeply mistaken.

Break it down. First build a string that contains the ip address, then pass that to system().

There are any number of ways to build one string from several parts. I recommend looking at the printf() family of functions, particularly snprintf(). I assume you know how to use man pages. If not, see Xcode's Help menu, choose Open man Page, enter snprintf, then read the resulting man page.

What is a man page?
http://en.wikipedia.org/wiki/Man_page

You could also google the search terms: what is snprintf
 
I don't expect it to act like sprintf, and I have tried my own things, such as...
Code:
char command[512];
sprintf(command, "my command with %s", ip);
if(system(command) == 0){
}

However, this returns a segmentation fault error.
 
I was being lazy because I don't like to type code on my phone and also prefer that I can compile/test code... But I'll give it a whirl:
Code:
#include <stdio.h>
int main(int argc, char *argv) {
  char *myIP = "10.1.2.3";
  char myCommand[100];
  int result = 0;
  myCommand[99]='\0';
  snprintf(myCommand,sizeof(myCommand),"ping -c 1 -W 5 %s",myIP);
  if(myCommand[99] != 0) {
    fprintf(stderr,"IP is too long for command buffer.\n");
    return -1;
  }
  result = system(myCommand);
  if(result == 0) {
    printf("Host is up!\n");
  } else if (result > 0 && result != 127) {
    printf("Host is down!\n");
  } else {
    fprintf(stderr,"Could not run ping command.\n");
    return -2;
  }
  return 0;
}

Not tested, but something like that should do it.

-Lee
 
Wow, that seems to work great! Only problem is that once I add the scanf part, which is scanf("%s", myIP), it goes back with the errors again (same as before...). Am I using the string properly and allocation properly?
 
Wow, that seems to work great! Only problem is that once I add the scanf part, which is scanf("%s", myIP), it goes back with the errors again (same as before...). Am I using the string properly and allocation properly?

I have absolutely no idea, because I can't see your code. I can hazard a guess and say that you are not using some string correctly if you are getting a crash. What does (all of) your code look like? Where does it crash?

-Lee

Edit: if you just added that line to my code, bad things will happen. I initialized myIP using a string literal. If you try to write over that nothing good will happen. That is not your memory to crush. You'll need a buffer allocated for your read that is big enough for a huge amount of input. A valid IP can only be 15 characters, but nothing forces someone to enter a valid IP.
 
Here's the program:
Code:
#include <stdio.h>
int main(int argc, char *argv) {
	printf("Please enter an IP address:");
	char *myIP;
	scanf("%s", myIP);
	char myCommand[100];
	int result = 0;
	myCommand[99]='\0';
	snprintf(myCommand,sizeof(myCommand),"ping -c 1 -W 5 %s &>/dev/null",myIP);
	if(myCommand[99] != 0) {
		fprintf(stderr,"IP is too long for command buffer.\n");
		return -1;
	}
	result = system(myCommand);
	if(result == 0) {
		printf("Host is up!\n");
	} else if (result > 0 && result != 127) {
		printf("Host is down!\n");
	} else {
		fprintf(stderr,"Could not run ping command.\n");
		return -2;
	}
	return 0;
}

Once I enter an ip address and press return, it tells me that there is a bus error, then exits the program. I'm guessing there's something wrong here with how I'm allocating the myIP variable, right?
 
Here's the program:
Code:
#include <stdio.h>
int main(int argc, char *argv) {
	printf("Please enter an IP address:");
	char *myIP;
	scanf("%s", myIP);
	char myCommand[100];
	int result = 0;
	myCommand[99]='\0';
	snprintf(myCommand,sizeof(myCommand),"ping -c 1 -W 5 %s &>/dev/null",myIP);
	if(myCommand[99] != 0) {
		fprintf(stderr,"IP is too long for command buffer.\n");
		return -1;
	}
	result = system(myCommand);
	if(result == 0) {
		printf("Host is up!\n");
	} else if (result > 0 && result != 127) {
		printf("Host is down!\n");
	} else {
		fprintf(stderr,"Could not run ping command.\n");
		return -2;
	}
	return 0;
}

Once I enter an ip address and press return, it tells me that there is a bus error, then exits the program. I'm guessing there's something wrong here with how I'm allocating the myIP variable, right?

There is something fundamentally wrong with using myIP this way. It is uninitialized. It could point anywhere in memory. If it points to something you have permission to change, it's still going to overwrite something. There is a better chance that it points out into the aether, and you're trying to plunk some input into an area you have no claim to. You need to statically allocate a large char [] for your input, or assign the result of malloc with a large size to myIP then free this when you're done.

scanf is dangerous (EDIT: I meant with %s) because you can't limit the input length, but for this test you can get away with it as long as you pass a pointer to a buffer you own.

-Lee

Edit: you should be able to fix this by making myIP:
char myIP[1000];

I should have checked result explicitly against -1 not > 0, but ping returns 0, 1, or 2, so it should be OK.
 
Last edited:
Thank you very much for this help! I'm sorry, I have not programmed in C in quite some time. I resolved the issue by adding a buffer and slightly changing the definition of myIP. The code where scanf is now looks like this:
Code:
char myIP[30] = {'\0}'};
scanf("%29s", myIP);

Thank you!
 
Here's the program:
Code:
	snprintf(myCommand,sizeof(myCommand),"ping -c 1 -W 5 %s &>/dev/null",myIP);
	if(myCommand[99] != 0) {
		fprintf(stderr,"IP is too long for command buffer.\n");
		return -1;
	}
}
You should really spend a little time reading man pages.

snprintf() returns an int. It's the count of how many chars it would have written if the size were infinite. Since snprintf() will NOT run past the given size, and WILL always nul-terminate a buffer, the if(myCommand[99] != 0) will NEVER be true. All this is very concisely described in the man page.
 
If this is part of code you intend to distribute, implement some additional input verification.

Fortunately your system doesn't require privileged access, but you should really be checking for anything that doesn't look like an IP in the input string. Make sure it only uses digits and periods, or alphanumerics if you are allowing hostnames as well.

Read the appropriate RFC if necessary or find an existing function or library that will help.

B
 
You should really spend a little time reading man pages.

snprintf() returns an int. It's the count of how many chars it would have written if the size were infinite. Since snprintf() will NOT run past the given size, and WILL always nul-terminate a buffer, the if(myCommand[99] != 0) will NEVER be true. All this is very concisely described in the man page.

That was 100% my fault, that was code I provided. I didn't look that part up, and for whatever reason thought if the result was greater than size as much as possible would be written without null-termination. Mea culpa.

-Lee
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.