Find Argv[i] in /bin and /sbin

Hello all, I am currently working on a package manager in C and am at the point where I am trying to check to see if the package is already installed. To do this I am taking the package name(s) as an argument using argv. The working code for doing this as follows:

#include <stdio.h>
#include <sys/stat.h>

#include<dirent.h>

int main(int argc, char *argv[])
{
        short i;
        struct stat program;

        for (i = 1; i < argc; i++) {

                if (stat(argv, &program) == 0)
                        return 0;

                else
                        return 1;
        }
}

This works, I have tested it with prints and everything. The issue with this is that it does not check /bin and /sbin, but rather checks the directory it is being run from. So I did some research and wrote a separate .c file to list /bin which is as follows:

#include <stdio.h>
#include <dirent.h>

short open(char *directory)
{
        struct dirent *de;
        DIR *dr = opendir(directory); /* directory to open */

        if (dr == NULL) {
                printf("directory could not be opened");
                return 0;
        }

        while ((de = readdir(dr)) != NULL) /* print entries in dr */
                printf("%s\n", de->d_name);

        closedir(dr);
        return 0;
}

int main()
{
        open("/bin");
}

this also works. The issue I am having is I can't figure out how to

A) List both /bin and /sbin

B) Check for the program in those directories (this one is the one I really need help with).

Now for checking both I figure I can say basically

if argv isn't found in /bin check /sbin (if more than one is given then check for all of them and if any were found say which were)

If I can get B solved than A should be pretty easy. I just can't for the life of me figure it out, I would love some advice. Thank you for reading.

Edit:

Progress! Oh sweet sweet progress on this issue I have been stuck on for weeks, so after thinking with a clear head I realized my first function checks for the file and my second opens the directory. All I needed to do was combine them, so I did so and got this:

#include <stdio.h>
#include <sys/stat.h>

#include <dirent.h>

int main(int argc, char *argv[])
{
        struct dirent *de;
        DIR *dr = opendir("/bin"); /* directory to open */

        short i;
        struct stat program;

        if (dr == NULL) {
                printf("directory could not be opened");
                return 0;
        }

        while ((de = readdir(dr)) != NULL) {
                for (i = 1; i < argc; i++) {

                        if (stat(argv, &program) == 0) {
                                printf("found\n");
                                closedir(dr);
                        }

                        else {
                                printf("not found\n");
                                closedir(dr);
                        }
                }
        }

        return 0;
}

Now this always prints not found, I am still working on this but am having a hard time debugging it.

First off /bin and /sbin may be and often are symbolic links to /usr/bin or /usr/sbin . There are links for library directories as well.

So I am not sure where your confusion arises.

One solution is the realpath() function. It resolves the problem of reading and resolving links. You can use lstat to check if /bin or whatever is a symlink, too. lstat only returns information about links, not regular files or directories.

Read man page on realpath and lstat

I was unaware of these functions and will definitely take a look at those manpages, thank you so much

Edit:

Oh, I apologize but there seems to be some confusion. What this does is it checks /bin and /sbin to see if the program(s) given are found. So say I run

check echo

it will look in /bin and /sbin to see if echo is found. If found it will say "found" otherwise it will say "not found". Now my current code has an issue that I can't find a solution for

#include <stdio.h>
#include <sys/stat.h>

#include <dirent.h>

int main(int argc, char *argv[])
{
        struct dirent *de;
        DIR *dr = opendir("/bin"); /* directory to open */

        short i;
        struct stat program;

        if (dr == NULL) {
                printf("directory could not be opened");
                return 0;
        }

        while ((de = readdir(dr)) != NULL) {
                for (i = 1; i < argc; i++) {

                        if (stat(argv, &program) == 0) {
                                printf("found\n");
                                closedir(dr);
                        }

                        else {
                                printf("not found\n");
                                closedir(dr);
                        }
                }
        }
}

stat is checking the current working directory and not /bin, how do I have it look at /bin?

I am also trying with strcmp() and I can't seem to get that working either:

#include <stdio.h>
#include <sys/stat.h>

#include <string.h>
#include <dirent.h>

int main(int argc, char *argv[])
{
        struct dirent *de;
        DIR *dr = opendir("/bin"); /* directory to open */

        short i;
        struct stat program;

        if (dr == NULL) {
                printf("directory could not be opened");
                return 0;
        }

        while ((de = readdir(dr)) != NULL) {
                for (i = 1; i < argc; i++) {

                        if (strcmp(de->d_name, argv) == 0) {
                                printf("found\n");
                                closedir(dr);
                        }

                        else {
                                printf("not found\n");
                                closedir(dr);
                        }
                }
        }
}

What you want is the equivalent of the which command - it uses the PATH variable to decide where to look.

#!/bin/bash
# usage: ./check executable_name_goes_here
# 
export PATH=/bin:/usr/bin:/usr/sbin

/usr/bin/which  "$1" 

exit

change whatever you need to make this work for you.
You do NOT want to duplicate a correct which command, it is a lot of work. If you want to learn instead: download Linux coreutils - google for your UNIX flavor. Then read the source. PS: realpath () is the heart of the which command.

I can't find any source code for which command anywhere, maybe because it's so late I don't know. I was able to implement realpath the issue is I can't figure out how to do basically

if realpath == 0 (as in found)


return 0


else (as in not found)


return 1

So I got this

#include <stdio.h>
#include <stdlib.h>

#include <dirent.h>

int main(int argc, char *argv[])
{
        struct dirent *de = calloc(1, sizeof(struct dirent));
        DIR *dr = opendir("/bin"); /* directory to open */

        short i;
        char *res = realpath(argv, NULL);

        if (dr == NULL) {
                printf("directory could not be opened");
                return 0;
        }

        while ((de = readdir(dr)) != NULL) {
                for (i = 1; i < argc; i++) {

                        if (res == NULL) {
                                printf("found\n");
                                closedir(dr);
                        }

                        else {
                                printf("not found\n");
                                closedir(dr);
                        }
                }
        }
}

and based on the man page it should be working. I have tried

./a.out echo //echo is in /bin


// returns not found and 



./a.out ifjie4hfirhghrighih //not in /bin


// returns not found

I am very confused as to why this doesn't work as it seems it should be.

On my home debian linux system, 'which' is a shell script.
So looking at the source is just using cat against it.

Quite short script as well.

Regards
Peasant.