Root-SUID C wrapper debugging - c

I am new to C and this is a simple wrapper I wrote to run execute scripts as different user. I understand I can do visudo in etc/sudoers but, I already did this and I don't want it to go to waste, also it will help me improve writing in C. I seem to ha The problem is I am having errors when I compile it. My operating system is Ubuntu 12.04.03 LTS. Can someone help me fix these errors?
rootsuidwrapper.c: In function ‘trusted’:
rootsuidwrapper.c:60:15: warning: assignment makes pointer from integer without a cast [enabled by default]
rootsuidwrapper.c: In function ‘main’:
rootsuidwrapper.c:116:48: error: too many arguments to function ‘stat’
/usr/include/x86_64-linux-gnu/sys/stat.h:211:12: note: declared here
It would be nice if someone could fix these errors and give me the working code. Also, I would like to know what I did wrong.
* This program must be run as root to work.
*/
#if !defined(lint) && !defined(SABER) || defined(RCS_HDRS)
#endif /* !lint && !SABER || RCS_HDRS */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/stat.h>
#define TRUSTED_GROUP "trusted"
typedef enum { false = 0, true } bool;
#ifdef __STDC__
bool trusted(char *whoami)
#else
bool trusted(whoami)
char *whoami;
#endif /* __STDC__ */
{
char *user;
char host[BUFSIZ + 1];
char domain[BUFSIZ + 1];
struct hostent *hp;
/*
* Figure out whether this user on this host in this domain is
* trusted.
*/
/*
* Determine our domain name
*/
(void) memset(domain, '\0', sizeof(domain));
getdomainname(domain, sizeof(domain) - 1);
/*
* Figure out our fully canonicalized hostname
*/
(void) memset(host, '\0', sizeof(host));
gethostname(host, sizeof(host) - 1);
if ((hp = gethostbyname(host)) == NULL) {
strcat(host, ".");
strcat(host, domain);
fprintf(stderr,
"%s: WARNING: can't canonlicalize hostname; assuming %s.\n",
whoami, host);
}
else {
strcpy(host, hp->h_name);
}
/*
* Get login name of current user
*/
if ((user = cuserid(NULL)) == NULL) {
fprintf(stderr, " %s: You do not seem to be in the passwd file!\n",
whoami);
return(false);
}
/*
* Look this triple up in the trusted netgroup
*/
return ((innetgr(TRUSTED_GROUP, host, user, domain) == 1) ? true : false);
}
#ifdef __STDC__
main(int argc, char *argv[])
#else
main(argc, argv)
int argc;
char *argv[];
#endif /* __STDC__ */
{
char *whoami;
int ouruid; /* uid we set to run chown and chmod */
int proguid; /* uid we are chowning program to */
char *filename;
struct stat statbuf;
int error = 0;
if (whoami = strrchr(argv[0], '/'))
whoami ++;
else
whoami = argv[0];
if (argc == 3)
proguid = atoi(argv[2]);
else if (argc == 2)
proguid = 0;
else {
fprintf(stderr, "usage: %s filename [proguid]\n", whoami);
exit(1);
}
filename = argv[1];
if (trusted(whoami))
ouruid = 0;
else
ouruid = getuid();
if (setuid(ouruid) == -1) {
fprintf(stderr, "%s: Warning: setuid(%d) failed: ", whoami, ouruid);
perror(NULL);
exit(1);
}
if (stat(filename, &statbuf, sizeof(struct stat)) == -1) {
fprintf(stderr, "%s: failure statting %s: ", whoami, filename);
perror(NULL);
exit(1);
}
if (chown(filename, proguid, -1) == -1) {
error++;
fprintf(stderr, "%s: chown %d %s failed: ", whoami, proguid, filename);
perror(NULL);
fprintf(stderr, "continuing...\n");
}
if (chmod(filename, statbuf.st_mode | S_ISUID)) {
error++;
fprintf(stderr, "%s: chmod u+s %s failed: ", whoami, filename);
perror(NULL);
}
return(error);
}
Help is appreciated,

NAME
stat, fstat, lstat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *path, struct stat *buf);
Remove your third parameter in the call to stat(). Your code should then be:
if (stat(filename, &statbuf) == -1) {
There is no need to tell stat() the size of the buffer because stat() expects a struct stat * which has a fixed size.

For the compiler warning:
cuserid() returns a pointer to a character (char*). When any function returns a pointer, and you want to place the return value into a buffer, then you have to put the return value into a specific place in the buffer, usually the beginning. Specifically, you should use:
*user = cuserid(NULL);
if(user == NULL)
Remember, cuserid() returns a pointer to a single character. Therefore, the return value of the function should go into a single character - that is, *user or user[0]. When the above code is used, the compiler shouldn't complain. Then you place the result of cuserid(NULL) into user, from the first byte to the rest of the memory allocated.

Related

How to check if entries in a directory are files or subdirectories?

I am using Raspbian and this is a part of an exercise for my advanced C programming in Linux environments. I have to open a directory and list its content, checking if entries are subdirectories or files.
Here is what I did:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
//declarations
int main(int argc, char ** argv){
if(argc != 2){
fprintf(stderr, "Wrong number of arguments\n");
exit(EXIT_FAILURE);
}
DIR *dir;
dir = opendir(argv[1]);
if(!dir){
fprintf(stderr, "Error: unable to open directory\n");
exit(EXIT_FAILURE);
}
struct dirent * entry;
struct stat filestat;
while((entry = readdir(dir))){
if(!(strcmp(entry->d_name, ".") == 0) && !(strcmp(entry->d_name,"..") == 0)){
stat(entry->d_name, &filestat);
//printf("S_ISREG(%s) value is:%d\n", entry->d_name, S_ISREG(filestat.st_mode));
//printf("S_ISDIR(%s) value is:%d\n", entry->d_name, S_ISDIR(filestat.st_mode));
if(S_ISDIR(filestat.st_mode) == 0){
printf("Dir: %s\n", entry->d_name);
} else {
printf("File: %s\n", entry->d_name);
}
}
}
closedir(dir);
printf("END\n");
return EXIT_SUCCESS;
}
Now, it works if I am working with relative paths. If I am working on absolute paths, S_ISREG and S_ISDIR macros always return 0. What am I doing wrong?
It seems by doing stat(entry -> d_name, &filestat) you're giving as directory path just the name of the folder you're looking at, which should work if it belongs to the directory from which the file is being executed but might not work with absolute paths
Also, you are not checking if stat is producing any error, which might also be an issue here - or at least provide some insight to the real problem
you might want to try concatenating your path to entry->d_name and use that when you call stat instead, e.g.
char fullPath[MAX_LEN];
while((entry = readdir(dir))){
if(!(strcmp(entry->d_name, ".") == 0) && !(strcmp(entry->d_name,"..") == 0)){
sprintf(fullPath, "%s/%s", argv[1], entry->dname);
if(stat(fullPath, &filestat) < 0){
//handle error
}
if(S_ISDIR(filestat.st_mode) == 0){
printf("Dir: %s\n", entry->d_name);
} else {
printf("File: %s\n", entry->d_name);
}
}
}
where MAX_LEN is some predefined constant
Use
if (fstatat(dirfd(dir), entry->d_name, &filestat, AT_SYMLINK_NOFOLLOW) == -1) {
fprintf(stderr, "Cannot stat %s/%s: %s.\n",
argv[1], entry->d_name, strerror(errno));
/* Optionally, exit(EXIT_FAILURE); */
} else {
/* Directory entry information in filestat */
}
As explained in the man 3 readdir manual page, if entry->d_type == DT_UNKNOWN, you need to do the above fstatat() to obtain the type.
This is because some filesystems do not provide the information in the directory entries, and return d_type == DT_UNKNOWN for all directory entries. All applications are required to handle DT_UNKNOWN correctly.
Note that you need
#define _POSIX_C_SOURCE 200809L
#define _ATFILE_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
at the beginning of your file, to tell the C library to expose the functions (fstatat() and strerror()).
However, opendir()/readdir()/closedir() is the wrong way to check directory contents, because the contents may change during your traversal. You would be better off using [scandir()](https://man7.org/linux/man-pages/man3/scandir.3.html9, glob() (if searching for files matching a pattern), or nftw() (if traversing entire trees) which are all POSIX.1 standard functions provided by POSIXy C libraries (basically all except Windows).
An exercise claiming to show how to list files in a directory and using opendir()/readdir()/closedir() is at best misleading, because it leaves all the complexity – handling changes to the directory contents, like renamed files – to you the writer, without telling you such work is necessary! Yes, two decades ago filesystems were typically so simple that opendir()/readdir()/closedir() worked without issues, but that is not the case anymore. The other functions listed above are supposed to handle such cases gracefully, so you the programmer shouldn't need to do it yourself.
Here is one way to properly implement the directory scan in Linux:
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <ftw.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
static int report_entry(const char *path,
const struct stat *info,
int typeflag,
struct FTW *ftwbuf)
{
/* If you need it, entry name is (path + ftwbuf->base). */
switch (typeflag) {
case FTW_D: /* Directory */
printf("%s is a directory\n", path);
/* If this is the path given to nftw(), recurse into it: */
if (ftwbuf->level == 0)
return FTW_CONTINUE;
/* Do not recurse into any other directories. */
return FTW_SKIP_SUBTREE;
case FTW_DNR: /* Directory, but no access to contents */
printf("%s is a directory but there is no read access\n", path);
return FTW_CONTINUE;
case FTW_DP: /* Directory that was already mentioned */
return FTW_CONTINUE;
case FTW_F: /* Regular file */
printf("%s is a file\n", path);
return FTW_CONTINUE;
case FTW_SL: /* Symlink, and FTW_PHYS was set for nftw() */
printf("%s is a symbolic link\n", path);
return FTW_CONTINUE;
case FTW_SLN: /* Symlink to a nonexistent file */
/* This will NOT be reported if FTW_PHYS is set in the nftw() call. */
printf("%s is a symbolic link to a nonexistent file\n", path);
return FTW_CONTINUE;
case FTW_NS: /* stat() failed */
printf("%s is unknown, and cannot be stat()'d\n", path);
return FTW_CONTINUE;
default: /* Should never occur */
printf("%s is of unknown an unexpected type (%d)\n", path, typeflag);
return FTW_STOP;
}
}
/* Number of file descriptors nftw() is allowed to use.
It mostly matters to applications that use many file descriptors,
like service daemons (servers). If nftw() runs out, it slows down,
but does not fail. In Linux, processes usually have at least
a thousand file descriptors available, so 64 is very conservative. */
#ifndef NFTW_FDS
#define NFTW_FDS 64
#endif
int report_directory(const char *path)
{
int result;
if (!path || !*path) {
/* No path specified; invalid parameter */
errno = EINVAL;
return -1;
}
result = nftw(path, report_entry, NFTW_FDS, FTW_ACTIONRETVAL | FTW_PHYS);
if (result == -1) {
/* nftw() error, errno set. */
return -1;
} else
if (result == FTW_STOP) {
/* report_entry() returned FTW_STOP. We assume error was already printed. */
errno = 0;
return -1;
} else
if (result != 0) {
/* Unexpected error */
errno = EIO;
return -1;
}
/* Done successfully. */
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *thisname = (argc >= 1 && argv && argv[0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", thisname);
fprintf(stderr, " %s DIRECTORY-OR-FILE\n", thisname);
fprintf(stderr, "\n");
return (argc == 2) ? EXIT_SUCCESS : EXIT_FAILURE;
}
if (report_directory(argv[1]) != 0) {
if (errno) {
fprintf(stderr, "Error: %s: %s.\n", argv[1], strerror(errno));
}
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Try this:
while((entry = readdir(dir))){
if(!(strcmp(entry->d_name, ".") == 0) && !(strcmp(entry->d_name,"..") == 0)){
if(entry->d_type == DT_DIR){
printf("Dir: %s\n", entry->d_name);
} else {
printf("File: %s\n", entry->d_name);
}
}
}
It might not work on your platform though, read the readdir documentation for more information.

How to pass argument values in the program implementing the shell

SOURCE::
#include <stdio.h> // printf()
#include <stdlib.h> // exit()
#include <string.h> // string
#include <dirent.h> // microsoft base compiler. _chdir, _getcwd
#include <unistd.h> // unix base complier. getcwd, chdir
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FILE_SIZE 1024
#define MAX 255
#define ERROR (-1)
void cmd_mkdir(int argc, char *argv);
void cmd_ls()
{
char * cwd = (char *)malloc(sizeof(char) * 1024);
DIR * dir = NULL;
struct dirent * entry = NULL;
getcwd(cwd, 1024);
if( (dir = opendir(cwd)) == NULL)
{
printf("current directory error\n");
exit(1);
}
while( (entry = readdir(dir)) != NULL)
{
printf("%s\n", entry->d_name);
}
free(cwd);
closedir(dir);
}
void cmd_pwd() {
char buf[MAX];
getcwd(buf, MAX);
printf("%s\n", buf);
}
int main(int argc, char *argv[])
{
char cBuf[MAX];
char *arg;
while(1) {
printf(">> ");
arg = fgets(cBuf, MAX, stdin);
if(argc < 2){
// printf("1111\n"); -- check
if(strncmp(arg, "ls", 2) == 0)
cmd_ls();
else if(strncmp(arg, "pwd", 3) == 0)
cmd_pwd();
else if(strncmp(arg, "exit", 4) == 0)
break;
} // if END
else {
// printf("2222\n"); -- check
if(strcmp(arg, "mkdir") == 0){
if (argc != 2)
fprintf(stderr, "Usage : jmkdir dirname\n");
if(mkdir(argv[1], 0755))
perror("mkdir error");
}
}// else END
} // while END
} // main END
Desired result::
How to get two input values (mkdir, mini_maked) as parameters after executing ./minishell (executable file implementing the shell)
$ ./minishell
>> mkdir mini_maked
Currently implemented ls, pwd, exit can be implemented because it can be used without options, but a command that requires a "command filename" such as mkdir is not implemented.
If the program itself functions as mkdir, it is solved using the values of argc and argv.
However, since the ./myshell program itself implements the shell program, when you run the program and receive mkdir mini_maked as an input, you are having a hard time executing the command.
If we get two inputs (mkdir, mini_maked) after program execution, how do we get these as parameters?

C: implicit declaration of function ‘getpwnam_r’

While retrieving the broken-out fields of the record in the password database (e.g., the local password file /etc/passwd, NIS, and LDAP) that matches a provided username name, I am using the getpwnam_r (http://linux.die.net/man/3/getpwnam_r) function.
#define __USE_BSD
#define _BSD_SOURCE
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
struct passwd pwd;
struct passwd *result;
char *buf;
size_t bufsize;
int s;
if (argc != 2) {
fprintf(stderr, "Usage: %s username\n", argv[0]);
exit(EXIT_FAILURE);
}
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1) /* Value was indeterminate */
bufsize = 16384; /* Should be more than enough */
buf = malloc(bufsize);
if (buf == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
s = getpwnam_r(argv[1], &pwd, buf, bufsize, &result);
if (result == NULL) {
if (s == 0)
printf("Not found\n");
else {
errno = s;
perror("getpwnam_r");
}
exit(EXIT_FAILURE);
}
printf("Name: %s; UID: %ld\n", pwd.pw_gecos, (long) pwd.pw_uid);
exit(EXIT_SUCCESS);
}
The code works fine, but Eclipse shows me a warning as follows:
warning: implicit declaration of function ‘getpwnam_r’ [-Wimplicit-function-declaration]
How could I fix it?
Note that I'm currently using Ubuntu 14.04 LTS.
To use this function you need two includes :
#include <sys/types.h>
#include <pwd.h>
Add them and it should not complain anymore.
You can see that by running man getpwnam_r.
You also need to define either __USE_MISC or __USE_SVID since it a POSIX only function.

Why do I get a Segmentation fault? I'm using stat, mmap, nftw, and memcmp, among other things

Here is my code. I'm assuming this has something to do with improper use of pointers or maybe I'm not mapping and unmapping my memory correctly.
Could anyone please provide me with some insight into the issue?
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <ftw.h>
#include <sys/stat.h>
#include <string.h>
int size;
int map1, map2;
void *tar, *temp;
int callback(const char *filename,
const struct stat *sb2,
int filetype,
struct FTW *ftw)
{
printf("test");
if(sb2->st_size == sb1->st_size){
temp = mmap(NULL, sb2->st_size, PROT_NONE, 0, map2, 0);
int cmp = memcmp(tar, temp, sb2->st_size);
printf("%d\n", cmp);
if(cmp == 0){
printf("%s\n", filename);
}
if(munmap(temp,sb2->st_size) == -1){
fprintf(stderr, "Error in unmapping in callback function");
exit(EXIT_FAILURE);
}
}
return 0; //continue to walk the tree
}
int main(int argc, char *argv[])
{
//check for correct arguments
if (argc == 1 || argc > 3) {
fprintf(stderr, "Syntax: %s filename dirname\n", argv[0]);
exit(EXIT_FAILURE);
}
//use stat to get size of filename
struct stat sb1;
if(stat(argv[1],&sb1) != 0){
fprintf(stderr, "Error in stat().");
exit(EXIT_FAILURE);
}
size = sb1.st_size;
//fd = mmap filename
tar = mmap(NULL,sb1->st_size, PROT_WRITE, MAP_SHARED, map1, 0);
if(tar == 0){
fprintf(stderr, "Main() mmap failed");
exit(EXIT_FAILURE);
}
//walk through the directory with callback function
nftw(argv[2], callback, 20, 0);
// use munmap to clear fd
if (munmap(tar,sb1->st_size) == -1) {
fprintf(stderr, "Error in unmapping");
exit(EXIT_FAILURE);
}
}
EDIT
I now declare my struct stat sb1 right before I use the stat function. After doing that I receieved a segmentation error again. I then commented out my nftw() call and and printed out the size variable (which has a reasonable number so I believe that's working). The new error is:
Error in unmapping.
You declare:
struct stat *sb1;
You use:
stat(argv[1],sb1);
You crash and burn because sb1 is a null pointer (since the variable is defined at file scope, it is initialized with 0).
You need to declare (at file scope):
struct stat sb1;
And then in main() you can use:
if (stat(argv[1], &sb1) != 0)
...oops...
You'll have to review all uses of sb1 to fix the status change from pointer to object, adding an & where necessary, and changing -> to . where necessary.
mmap() by example
This is a mildly edited version of a function I wrote that uses mmap() to map a file into memory:
/* Map named file into memory and validate that it is a MSG file */
static int msg_mapfile(const char *file)
{
int fd;
void *vp;
struct stat sb;
if (file == 0)
return(MSG_NOMSGFILE);
if ((fd = open(file, O_RDONLY, 0)) < 0)
return(MSG_OPENFAIL);
if (fstat(fd, &sb) != 0)
{
close(fd);
return(MSG_STATFAIL);
}
vp = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (vp == MAP_FAILED)
return(MSG_MMAPFAIL);
The MSG_xxxx constants are distinct error numbers applicable to the program it came from. It was only needing to read the file, hence the PROT_READ; I think you may be OK with that too.
if (argc == 1 || argc > 3) {
fprintf(stderr, "Syntax: %s filename dirname\n", argv[0]);
exit(EXIT_FAILURE);
}
/* ... */
nftw(argv[2], callback, 20, 0);
I see a possibility for argv[2] to be NULL. Perhaps you meant:
if (argc != 3) {
fprintf(stderr, "Syntax: %s filename dirname\n", argv[0]);
exit(EXIT_FAILURE);
}
Which book are you reading?

Listing directories in Linux from C

I am trying to simulate linux command ls using linux api from c. Looking at the code it does make sense, but when I run it I get "stat error: No such file or directory". I have checked that opendir is working ok. I think the problem is in stat, which is returning -1 even though I think it should return 0.
What am I missing?
Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
if (stat(direntp->d_name, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
It's because you aren't stating the actual file. It's in a different directory. If you want the real filename, combine argv[1] and direntp->d_name with a '/' between them.
Also, hungarian naming is icky, even the minor bit like 'p' on the end. If you have so many variables you need to keep track of their types in their names you're doing something wrong.
Here is a revised version of your program:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
char fullpath[MAXPATHLEN + 1];
size_t dirnamelen;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
fullpath[MAXPATHLEN - 1] = '\0';
dirnamelen = strlen(fullpath);
if (strlen(argv[1]) > dirnamelen) {
fprintf( stderr, "Directory name is too long: %s", argv[1] );
exit(2);
}
fullpath[dirnamelen++] = '/';
fullpath[dirnamelen] = '\0';
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
fullpath[dirnamelen] = '\0';
if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
continue;
} else {
/* strncpy is mild overkill because the if statement has verified that
there's enough space. */
strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
fullpath[MAXPATHLEN] = '\0';
}
if (stat(fullpath, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
Note that I use MAXPATHLEN (from <limits.h>) and carefully check to make sure there aren't any buffer overflows. You should do the same in your code.
Edit: Changed code to use strn family functions for added safety.
Add
#include <unistd.h>
...
chdir(argv[1]);
or call stat with the full pathname like this
...
char fullpath[MAXPATHLEN];
snprintf(fullpath, sizeof(fullpath), "%s/%s", argv[1], direntp->d_name);
if (stat(fullpath, &stat_buf) == -1)
...
Others have suggested building a full path for stat(), or using chdir(). Both those will work (although they are subject to a race condition, if the directory is renamed while you are in the middle of reading it).
An alternative, which is not subject to the race condition, and is therefore arguably more "correct", is to use fstatat(). Just replace your existing stat() call with:
fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)
(The chdir() method can be made race-condition-free too: either by using fchdir(dirfd(dirp)) instead of chdir(), or by changing directory to argv[1] and then opening "." with opendir(). The pathname construction method can't be made race-condition-free).
Why dont you try this? Just give the path to argv[1] like this /home/sabri/Desktop/Test
int main(int argc, char *argv[])
{
struct dirent *direntp;
DIR *dirp;
if (argc != 2)
{
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
if ((dirp = opendir(argv[1])) == NULL)
{
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
printf("%s\n", direntp->d_name);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
If you are using on unix, then you may use the system command.
system("ls -ltr | grep -d");

Resources