I'm getting a "too many arguments in function call" error in my C program. The error occurs at a line where I'm calling a function that has a fixed number of arguments. I'm not sure why I'm getting this error, as I'm not passing in more arguments than the function expects. Here's the code where the error occurs:
if (mkdir(path, 0777) == -1)
Here is full code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#define BUF_SIZE 1024
#define MAX_ARGS 10
// Print the usage message for the program
void print_usage() {
fprintf(stderr, "Usage: syscalls <command> [arguments]\n");
}
// Read the contents of a file and write them to stdout
int read_file(const char *path) {
static char buf[BUF_SIZE];
int fd = open(path, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
ssize_t num_read;
while ((num_read = read(fd, buf, BUF_SIZE)) > 0) {
if (write(STDOUT_FILENO, buf, num_read) != num_read) {
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
return 1;
}
}
if (num_read == -1) {
fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno));
return 1;
}
return 0;
}
// Write a set of lines to a file
int write_file(const char *path, char *lines[], int num_lines) {
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return 1;
}
int total_bytes = 0;
for (int i = 0; i < num_lines; i++) {
const char *line = lines[i];
size_t len = strlen(line);
ssize_t num_written = pwrite(fd, line, len, total_bytes);
if (num_written == -1) {
fprintf(stderr, "Failed to write to %s: %s\n", path, strerror(errno));
return 1;
}
total_bytes += num_written;
}
printf("Wrote %d B\n", total_bytes);
return 0;
}
// Create a directory
int make_directory(const char *path) {
if (mkdir(path, 0777) == -1) {
if (errno == EEXIST) {
fprintf(stderr, "%s already exists\n", path);
} else {
fprintf(stderr, "Failed to create %s: %s\n", path, strerror(errno));
}
return 1;
}
return 0;
}
// List the contents of a directory
int list_directory(const char *path) {
DIR *dir = opendir(path);
if (dir == NULL) {
fprintf(stderr, "Failed to open directory %s: %s\n", path, strerror(errno));
return 1;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
printf("%s\n", entry->d_name);
}
if (closedir(dir) == -1) {
fprintf(stderr, "Failed to close directory %s: %s\n", path, strerror(errno));
return 1;
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
print_usage();
return 1;
}
char *command = argv[1];
if (strcmp(command, "read") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return read_file(argv[2]);
} else if (strcmp(command, "write") == 0) {
if (argc < 4 || argc > MAX_ARGS + 2) {
print_usage();
return 1;
}
return write_file(argv[2], argv + 3, argc - 3);
} else if (strcmp(command, "mkdir") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return make_directory(argv[2]);
} else if (strcmp(command, "ls") == 0) {
if (argc != 3) {
print_usage();
return 1;
}
return list_directory(argv[2]);
} else {
print_usage();
return 1;
}
}
I am getting this error in terminal:
syscalls.c: In function 'write_file':
syscalls.c:54:31: warning: implicit declaration of function 'pwrite' [-Wimplicit-function-declaration]
ssize_t num_written = pwrite(fd, line, len, total_bytes);
^~~~~~
syscalls.c: In function 'make_directory':
syscalls.c:67:9: error: too many arguments to function 'mkdir'
if (mkdir(path, 0777) == -1) {
^~~~~
In file included from c:\mingw\include\unistd.h:56:0,
from syscalls.c:3:
c:\mingw\include\io.h:516:38: note: declared here
_CRTIMP __cdecl __MINGW_NOTHROW int mkdir (const char *);
Please help me to resolve this issue. Thank you
mkdir() is not specified in the C standard. It is specified in the POSIX standard, which is more or less a superset of the C standard.
This declaration of mkdir():
c:\mingw\include\io.h:516:38: note: declared here
_CRTIMP __cdecl __MINGW_NOTHROW int mkdir (const char *);
is the Microsoft version of the function, which takes a single argument, and does not conform to the POSIX standard.
From Microsoft's page:
The Microsoft-implemented POSIX function name mkdir is a deprecated
alias for the _mkdir function.
int _mkdir(
const char *dirname
);
Possible fix:
#ifdef _CRTIMP
#define mkdir(d,m) (mkdir)(d)
#endif
Credit: #chqrlie
Related
I've been trying to find out why my tester is failing, it says that destination and source file don't match. link for testers: https://github.com/ShiraWolf/hwOP.git
Output Requirements & Testing:
It must output one of the following types of messages (precisely and case-sensitive):
Unable to open source file for reading
Unable to open destination file for writing
Unable to write to destination file
Unable to write buffer content to destination file
Unable to read source file
Unable to close source file
Unable to close destination file
File was successfully copied to
Or one of the various arguments parsing errors, as described in the examples above.
My code:
/*
* ex1.c
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_BUFFER_SIZE 65536
#define DESTINATION_FILE_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
extern int opterr, optind;
void exit_with_usage(const char *message) {
fprintf(stderr, "%s\n", message);
fprintf(stderr, "Usage:\n\tex1 [-f] BUFFER_SIZE SOURCE DEST\n");
exit(EXIT_FAILURE);
}
void copy_file(const char *source_file, const char *dest_file, int buffer_size, int force_flag) {
/*
* Copy source_file content to dest_file, buffer_size bytes at a time.
* If force_flag is true, then also overwrite dest_file. Otherwise print error, and exit.
*
* TODO:
* 1. Open source_file for reading
* 2. Open dest_file for writing (Hint: is force_flag true?)
* 3. Loop reading from source and writing to the destination buffer_size bytes each time
* 4. Close source_file and dest_file
*
* ALWAYS check the return values of syscalls for errors!
* If an error was found, use perror(3) to print it with a message, and then exit(EXIT_FAILURE)
*/
int c = 0;
int sourcef = 0;
int destf = 0;
sourcef = open(source_file, O_RDONLY);
if (sourcef == -1) {
perror("Unable to open source file for reading");
exit(EXIT_FAILURE);
}
destf = open(dest_file, O_WRONLY |O_CREAT | O_EXCL, 00700);
if (destf == -1) {
if (force_flag) {
destf = open(dest_file, O_WRONLY, 00700);
if (destf == -1) {
if (close(sourcef) == -1) {
perror("couldn't close source file");
exit(EXIT_FAILURE);
}
perror("Unable to open destination for writing");
exit(EXIT_FAILURE);
}
} else {
perror("Unable to open destination for writing");
exit(EXIT_FAILURE);
}
}
char *buffer = malloc(sizeof(char) * buffer_size);
while ((c = read(sourcef, buffer, buffer_size)) != 0) {
if (c == -1) {
perror("couldn't read from source file");
if (close(sourcef) == -1) {
perror("couldn't close source file after reading has failed");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("couldn't close dest file after reading has failed");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
c = write(destf, buffer, buffer_size);
if (c == -1) {
perror("couldn't write to source file");
if (close(sourcef) == -1) {
perror("couldn't close source file after writing has failed");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("couldn't close dest file after writing has failed");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
}
free(buffer);
if (close(sourcef) == -1) {
perror("couldn't close source file");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("couldn't close dest file");
exit(EXIT_FAILURE);
}
printf("File %s was copied to %s\n", source_file, dest_file);
exit(EXIT_SUCCESS);
}
void parse_arguments (
int argc, char **argv,
char **source_file, char **dest_file, int *buffer_size, int *force_flag) {
/*
* parses command line arguments and set the arguments required for copy_file
*/
int option_character;
opterr = 0; /* Prevent getopt() from printing an error message to stderr */
while ((option_character = getopt(argc, argv, "f")) != -1) {
switch (option_character) {
case 'f':
*force_flag = 1;
break;
default: /* '?' */
exit_with_usage("Unknown option specified");
}
}
if (argc - optind != 3) {
exit_with_usage("Invalid number of arguments");
} else {
*source_file = argv[argc - 2];
*dest_file = argv[argc - 1];
*buffer_size = atoi(argv[argc - 3]);
if (strlen(*source_file) == 0 || strlen(*dest_file) == 0) {
exit_with_usage("Invalid source / destination file name");
} else if (*buffer_size < 1 || *buffer_size > MAX_BUFFER_SIZE) {
exit_with_usage("Invalid buffer size");
}
}
}
int main(int argc, char **argv) {
int force_flag = 0; /* force flag default: false */
char *source_file = NULL;
char *dest_file = NULL;
int buffer_size = MAX_BUFFER_SIZE;
parse_arguments(argc, argv, &source_file, &dest_file, &buffer_size, &force_flag);
copy_file(source_file, dest_file, buffer_size, force_flag);
return EXIT_SUCCESS;
}
Can anybody see where my mistake is?
c = write(destf, buffer, buffer_size); does not use the correct size: you should write c bytes and store the written count into a separate variable nwritten and keep trying to write more bytes until c bytes have been written or write return 0 or -1.
Here is a modified version of the copying loop:
while ((c = read(sourcef, buffer, buffer_size)) != 0) {
if (c == -1) {
perror("Unable to read from source file");
if (close(sourcef) == -1) {
perror("Unable to close source file");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("Unable to close destination file");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
int towrite = c;
int pos = 0;
while (towrite > 0) {
int nwritten = write(destf, buffer + pos, towrite);
if (nwritten <= 0) {
perror("Unable to write to destination file");
if (close(sourcef) == -1) {
perror("Unable to close source file");
exit(EXIT_FAILURE);
}
if (close(destf) == -1) {
perror("Unable to close destination file");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
pos += nwritten;
towrite -= nwritten;
}
}
Also note that the other error messages are different from the specification.
I created two programs, which will communicate via named pipe, one will be reading from it and another one will be writing to it. It works pretty fine now, except for the fact, that it opens and writes to the same fifo exactly 3 times. It's my first time with C and pipes, and I don't understand why is this writing three times. Can you see why is this writing three times?
writing.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void writing(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("writing to %s\n",s);
if ( (fd = open(s, O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, sizeof buf -1) ) > 0) {
buf[n-1] = '\0';
printf("Received: %s\n", buf);
if ( write(fd, buf, n) != n) {
err("write");
}
if(strcmp(buf,"END")==0){
printf("%s","exit");
break;
}
}
close(fd);
}
char* concat(const char *s1, const char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
int file_stat(char *argv){
int isfifo = 0;
struct stat sb;
printf("%s",argv);
if (stat(argv, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
if (sb.st_mode & S_IFMT == S_IFIFO) {
printf("FIFO/pipe\n");
isfifo = 1;
}
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
//exit(EXIT_SUCCESS);
return isfifo;
}
int main(int argc, char *argv[])
{
// READ ALL FILES IN DIRECTORY
if (argc != 2) {
fprintf(stderr, "Usage: %s /<pathname>/\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *d;
struct dirent *dir;
if ((d = opendir (argv[1])) != NULL) {
/* print all the files and directories within directory */
while ((dir = readdir (d)) != NULL) {
printf ("%s\n", dir->d_name);
char* s = concat(argv[1], dir->d_name);
if (file_stat(s) == 1) {
writing(s);
}
else {
mkfifo("fifo_x", 0666);
writing("fifo_x");
}
free(s);
}
closedir (d);
}
else {
/* could not open directory */
perror ("error: ");
return EXIT_FAILURE;
}
}
reading file is the same except for "reading" function and call to reading()
reading
void reading(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("%s",s);
if ( (fd = open(s, O_RDONLY)) < 0)
err("open");
while( (n = read(fd, buf, sizeof buf - 1) ) > 0) {
buf[n-1] = '\0';
if(strcmp(buf,"END")==0){
printf("%s\n", "exit");
break;
}
buf[n-1] = '\n';
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
the output
/home/..File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exitola
/home/olaFile type: Ownership: UID=1001 GID=1001
writing to fifo_x
END
Received: END
exit.
/home/.File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exit
You have three files in the directory with whose pathname you called your program. All three files are not fifo's so for each you write to fifo_x.
The file names are
.
..
olaFile
Maybe you should explicitly exclude the files
.
..
which happen to be in every directory in linux and represent the current directory . and the parent directory ...
The last Code I just posted now works. That is, it is able to copy all files from one directory to another. But now, I wanted to update it in such a way that it copies also directories including it contents be it files or folders.
Here is what I did so far, but this has been unable to accomplish my dream.
I really don't know what is wrong with the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define Max 8192
int copy_files(char *src, char *dest);
int copy_dir(char *srcpath, char *destpath);
int copy_dir(char *srcpath, char *destpath)
{
DIR *sdp = NULL;
DIR *ddp = NULL;
struct dirent *entry;
struct stat sb;
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
strcat(srcpath, "/");
strcat(destpath, "/");
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
if( (sdp = opendir(srcpath)) == NULL )
{
printf ("%s is not an existing directory\n", srcpath);
return 0;
}
else
{
while( (entry = readdir(sdp)) )
{
stat(entry->d_name, &sb);
// printf("Cannot open directory\n");
// exit(EXIT_FAILURE);
switch (sb.st_mode & S_IFMT)
{
case S_IFREG:
{
strcat(tempdest, entry->d_name);
strcat(tempsrc, entry->d_name);
copy_files(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
case S_IFDIR:
{
strcat(tempsrc, entry->d_name);
strcat(tempdest, entry->d_name);
mkdir(tempdest, 0777);
ddp = opendir(tempdest);
copy_dir(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
}
}
closedir(sdp);
closedir(ddp);
return 1;
}
}
int copy_files(char *src, char *dest)
{
int sfd, dfd, ret_in, ret_out;
char buff[Max];
if ( (sfd = open(src, O_RDONLY)) == -1 )
{
printf("Error while reading %s\n", src);
perror(src);
exit(1);
}
if ( (dfd = creat(dest, 0644)) == -1 )
{
printf("Error while creating %s\n", dest);
perror(dest);
exit(1);
}
while( (ret_in = read(sfd, &buff, Max)) > 0 )
{
ret_out = write (dfd, &buff, ret_in);
if (ret_out != ret_in)
{
printf("write error to %s", dest);
perror(dest);
exit(1);
}
if (ret_in == -1)
{
printf("read error from %s", src);
perror(src);
exit(1);
}
}
close(sfd);
close(dfd);
return 1;
}
int main(int argc, char *argv[])
{
int i;
if (argc != 3)
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
char *srcp = argv[1];
char *destp = argv[2];
if (srcp[0] == '/' && destp[0] == '/')
{
for (i = 1; i <= strlen(destp); i++)
destp[(i-1)] = destp[i];
for (i = 1; i <= strlen(srcp); i++)
srcp[(i-1)] = srcp[i];
copy_dir(srcp, destp);
}
else if (srcp[0] != '/' && destp[0] == '/') //./ass1 test /t2
{
for (i = 1; i <= strlen(destp); i++)
destp[i-1] = destp[i];
strcat(destp, "/");
strcat(destp, srcp);
copy_files(srcp, destp);
}
else
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
}
You are indefinitely adding /. to the temporary source and destination paths when the directory entry . is read, which is present in all directories. Instead, you should skip the . and .. entries.
Another error is the dimensioning of the temporary paths:
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
The arrays are made just long enough to hold the original paths, though sub-directory names are then appended, overflowing the arrays. Better:
char tempsrc[PATH_MAX];
char tempdest[PATH_MAX];
I am using JaetBrains' Clion with MinGW 3.2.1 on windows. and I'm trying to build a project in c.
I keep getting the following linkage error:
undefined reference to `printf'
any Idea How to solve it?
this is my code:
#include <fcntl.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <libintl.h>
#define BUFFERSIZE 1
int main(int argc, char** argv) {
assert(argc == 3);
char* inputDirPath = argv[0];
char* keyFilePath = argv[1];
char* outputDirPath = argv[2];
// open key file
int key_fd = open(keyFilePath, O_RDONLY);
if (key_fd < 0) {
printf("Failed opening Key file %s. Error: %s\n", keyFilePath, strerror(errno));
return errno;
}
// making sure the file is not empty
char keyFirstChar;
if (read(key_fd, (void*)keyFirstChar, 1) == 0)
{
printf("Error. Key file is empty %s.", keyFilePath);
return errno;
}
else {
// go back to the begining of the file.
assert(!close(key_fd));
key_fd = open(keyFilePath, O_RDONLY);
if (key_fd < 0) {
printf("Failed opening Key file %s. Error: %s\n", keyFilePath,
strerror(errno)
);
return errno;
}
}
// Temp file name
char inputFilepath[200] ;
struct dirent *dirEntity;
DIR *inputDir_dfd;
// open directory stream
assert((inputDir_dfd = opendir(inputDirPath)) != NULL);
while ((dirEntity = readdir(inputDir_dfd)) != NULL)
{
// full path to input file
sprintf(inputFilepath, "%s/%s",inputDirPath, dirEntity->d_name) ;
// call stat to get file metadata
struct stat statbuf ;
assert( stat(inputFilepath,&statbuf ) != -1 );
// skip directories
if ( ( statbuf.st_mode & S_IFMT ) == S_IFDIR )
{
continue;
}
// open input file
int inputFile_fd = open(inputFilepath, O_RDONLY);
if (inputFile_fd < 0) {
printf("Failed opening file in input directory, %s. Error: %s\n", inputFilepath, strerror(errno));
return errno;
}
// Temp file name
char outputFilePath[200] ;
// full path to file
sprintf(outputFilePath, "%s/%s",outputDirPath, dirEntity->d_name) ;
// open input file
int outputFile_fd = open(outputFilePath, O_WRONLY | O_CREAT | O_TRUNC);
if (outputFile_fd < 0) {
printf("Failed opening file in output directory, %s. Error: %s\n", outputFilePath, strerror(errno));
return errno;
}
char inputFileBuf[BUFFERSIZE];
while (read(inputFile_fd, inputFileBuf, BUFFERSIZE) == BUFFERSIZE){
char keyFileBuf[BUFFERSIZE];
if (read(key_fd, keyFileBuf, BUFFERSIZE) == 0) {
assert(!close(key_fd));
key_fd = open(keyFilePath, O_RDONLY);
if (key_fd < 0) {
printf("Failed opening Key file %s. Error: %s\n", keyFilePath, strerror(errno));
return errno;
}
read(key_fd,keyFileBuf, BUFFERSIZE);
}
char outputToWrite[BUFFERSIZE];
int i;
for(i = 0; i < BUFFERSIZE; i++){
outputToWrite[i] = keyFileBuf[i] ^ inputFileBuf[1];
}
if( write(outputFile_fd, outputToWrite, BUFFERSIZE) == -1){
printf("Failed writing to output file, %s. Error: %s\n", outputFilePath, strerror(errno));
return errno;
};
}
if(close(inputFile_fd) ); // close key file
}
closedir(inputDir_dfd); // close Dir
assert(!close(key_fd)); // close key file
}
thanks.
I want to get the following details for all the NICs attached to my computer:
1) Interface name (eg. eth0)
2) Interface Number (like in Windows) if such a thing exists in Linux
3) NIC bandwidth capacity and mode (eg. 1Gb/s full duplex)
You can use getifaddrs()/freeifaddrs() to obtain a linked list of all interfaces, then ioctl(fd, SIOCGIFINDEX, struct ifreq *) to obtain the interface index for each. Since the interfaces are consecutive and always listed (regardless of whether or they are up (active) or not), I choose to enumerate them with a loop using ioctl(fd, SIOCGIFNAME, struct ifreq *) instead. In all cases fd is an AF_INET socket.
To obtain the duplex and speed of the interface, you need to use the ioctl(fd, SIOCETHTOOL, struct ifreq *) with the ifr_data pointing to a struct ethtool_cmd having cmd = ETHTOOL_GSET.
The ioctls should return -1 if they fail, and a nonnegative value (zero, I believe) if success.
Here is an example program:
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct interface {
int index;
int flags; /* IFF_UP etc. */
long speed; /* Mbps; -1 is unknown */
int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */
char name[IF_NAMESIZE + 1];
};
static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info)
{
struct ethtool_cmd cmd;
int result;
/* Interface flags. */
if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1)
info->flags = 0;
else
info->flags = ifr->ifr_flags;
ifr->ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET; /* "Get settings" */
if (ioctl(fd, SIOCETHTOOL, ifr) == -1) {
/* Unknown */
info->speed = -1L;
info->duplex = DUPLEX_UNKNOWN;
} else {
info->speed = ethtool_cmd_speed(&cmd);
info->duplex = cmd.duplex;
}
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1)
return errno;
return 0;
}
int get_interface_by_index(const int index, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (index < 1 || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
ifr.ifr_ifindex = index;
if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = index;
strncpy(info->name, ifr.ifr_name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int get_interface_by_name(const char *const name, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (!name || !*name || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = ifr.ifr_ifindex;
strncpy(info->name, name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int main(int argc, char *argv[])
{
struct interface iface;
int arg;
int status = 0;
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]);
fprintf(stderr, " %s\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (argc > 1) {
for (arg = 1; arg < argc; arg++) {
if (get_interface_by_name(argv[arg], &iface) != 0) {
fprintf(stderr, "%s: No such interface.\n", argv[arg]);
status = 1;
continue;
}
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
} else {
for (arg = 1; ; arg++) {
if (get_interface_by_index(arg, &iface) != 0)
break;
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
}
return status;
}
If you save the above as iflist.c, you can compile it using
gcc -W -Wall -O3 iflist.c -o iflist
To see the usage, run iflist -h. To list all interfaces, run it without parameters:
./iflist
The above will use the enumeration method I described. To list only specific interfaces, run it naming the interfaces:
./iflist eth0 lo
Duplex and speed is only listed for ethernet interfaces, of course.
Edited to add:
If the above program does not supply the bandwidth and mode for an interface, here is a simplified version which reports the exact reason (errors). This one takes the interface names as commandline parameters; it does not enumerate interfaces.
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int ethernet_interface(const char *const name,
int *const index, int *const speed, int *const duplex)
{
struct ifreq ifr;
struct ethtool_cmd cmd;
int fd, result;
if (!name || !*name) {
fprintf(stderr, "Error: NULL interface name.\n");
fflush(stderr);
return errno = EINVAL;
}
if (index) *index = -1;
if (speed) *speed = -1;
if (duplex) *duplex = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
const int err = errno;
fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err));
fflush(stderr);
return errno = err;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
const int err = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err));
return errno = err;
}
if (speed)
*speed = ethtool_cmd_speed(&cmd);
if (duplex)
switch (cmd.duplex) {
case DUPLEX_HALF: *duplex = 0; break;
case DUPLEX_FULL: *duplex = 1; break;
default:
fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex);
fflush(stderr);
*duplex = -1;
}
if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0)
*index = ifr.ifr_ifindex;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err));
return errno = err;
}
return 0;
}
int main(int argc, char *argv[])
{
int arg, speed, index, duplex;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 0;
}
for (arg = 1; arg < argc; arg++) {
if (ethernet_interface(argv[arg], &index, &speed, &duplex))
return 1;
if (index == -1)
printf("%s: (no interface index)", argv[arg]);
else
printf("%s: interface %d", argv[arg], index);
if (speed == -1)
printf(", unknown bandwidth");
else
printf(", %d Mbps bandwidth", speed);
if (duplex == 0)
printf(", half duplex.\n");
else if (duplex == 1)
printf(", full duplex.\n");
else
printf(", unknown mode.\n");
}
return 0;
}
Questions?
(1) getifaddrs()
(2) if_indextoname(), if_nameindex(), if_nametoindex()
(3) I'm not sure about this one but you might be able to get at it through ioctl() and one of the SIOCGIF* parameters or from /proc.
the following link well explain the getifaddrs function with a working example
getifaddrs()
ethtool eth1
this command will list all the details about eth1 including speed, duplex, port...
you can use popen() to get the output and map it.
POPEN(3) Linux Programmer's Manual
POPEN(3)
NAME
popen, pclose - pipe stream to or from a process
SYNOPSIS
#include
FILE *popen(const char *command, const char *type);