How to find your directory manually in Linux? - c

I am about to write a command that shows the current directory in linux. I know I can use the "pwd" command, but that's what I need to implement myself!... in other words, when entering the so called "findme" command, I want to return back the directory that I am in at the moment. I have managed to create the my "findme" command (which is very simple,I know), but how am I supposed to know where in I am after executing the command, in order to show the whole directory?

It seems a rather odd requirement: 'implement pwd' (this isn't homework, is it?). Can you give a little more context?
Probably relevant bits of information are:
the directory .. is linked to the parent directory, and . to the current one; so...
changing directory to .. goes up one level in the filesystem (unless you're at the top); plus
every directory will have an 'inode number', so if you consider a directory foo, then both it and the directory foo/. will have the same inode number.
I don't know how pwd actually does it, but I'd lay money you could reimplement it with this information.

XV6 isn't at all the same as GNU/Linux. pwd was not implemented in UNIX V6, that's why it's a good exercise. You would probably want to implement getcwd() as a syscall.

Related

How to create a file inside the `/etc` folder in Linux with C?

I'm writing a program in C that will have to check a configuration file every time it starts to set some variables.
At the first start of the program I suppose there won't be any configuration file, so I need to create it (with default settings).
I've been said configurations files of program belongs to the folder /etc, more specifically to a particular folder created on purpose for the program itself (i.e. /etc/myprog). Here comes the first question I should have asked: is it true? Why /etc?
In any case I tried to create that file using this:
open("/etc/myprog/myprog.conf", O_WRONLY | O_CREAT, 0644);
the open returns -1 and sets errno global variable to 2 (i.e. folder does not exist).
If I try to create the file straight inside /etc (therefore "/etc/myprog.conf" as first argument of the open) I get instead an errno set to 13 (i.e. permission denied).
Is there a way to grant my program permissions to write in /etc?
EDIT: I see most users are suggesting to use sudo. If possible I would have preferred to avoid this option as this file has to be created just once (at the first start). Maybe I should make 2 different executables? (e.g. myprog_bootstrap and myprog, having to run only the first one with sudo)
You need root privileges to create a file in /etc. Run your executable with sudo in front:
sudo executable_name
Another possibility might be to make your executable setuid. Your program would then call very appropriately the setreuid(2) system call.
However, be very careful. Programs like /bin/login (or /usr/bin/sudo itself) are coded this way, but any subtle error in your program opens a can of worms of security holes. So please be paranoid when writing such a code, and get it reviewed by someone else.
Perhaps a better approach might be to have your installation procedure make /etc/yourfile some symlink (created once at installation time to some writable file elsewhere) ....
BTW, you might create a group for your program, and make -at installation time- the /etc/yourfile writable to the group, and make your program setgid.
Or even, dedicate a user for your program, and have this /etc/yourfile belonging to that user.
Or, at installation time, have the /etc/myprog/ directory created and belonging to the appropriate user (or group) and being writable to that user (or group).
PS. Read also Advanced Linux Programming, capabilities(7), credentials(7) and execve(2)

Copying a directory using sockets

I'm writing a program in C that sends files across the network using sockets. This works fine for files - they are read into a buffer and then written onto the socket. They are picked up at the other end by reversing this process.
However, how can this apply to directories? I also want to copy directories, keeping the permissions the same (so I don't think mkdir will work). At the moment when I try to run this on a directory, it says the size is -1. How is a directory represented?
To be clear, for example, if I want my program to copy /tmp across the network, it will do this:
/tmp/1.txt - OK
/tmp/2.txt - OK
/tmp/dir/ - Skip
/tmp/dir/3.txt - Can't write to path
There are several possibilities. It would fit fairly will with what you have already to tar the directory to transfer, send the resulting archive across the network, and untar on the other side.
Alternatively, you can walk the directory tree recursively. For each directory you need transfer only the name and whichever attributes you want to preserve, but then you must list the directory contents (probably via readdir()) and transfer each member.
By the way, don't neglect to think about how you're going to handle links, both symbolic ones and hard ones. And if you want your program to be really robust then consider also what to do with special files such as device files and FIFOs.
I guess it is homework, otherwise why not use FTP, scp, rsync, unison etc.
To test if a file path is a plain file, a device, a directory, etc etc... use
stat(2)
To read a directory, use opendir(3) then loop on readdir(3) (then of course closedir). You don't need to know how a directory is represented.
You probably should be interested in nftw(3) to recursively traverse a file tree.
To make one directory, use mkdir(2)
You should read Advanced Linux Programming
BTW, this answer contains useful information too...

Prevent accessing files outside of given working directory

I am trying to prevent the access on files outside of a given working directory.
My first attempt was to use chdir and chroot, but chroot can only be used by root users.
Is there any other possibility? I have heard something about another one, but I can't remember.
Perhaps a simple function to check if the path is outside of the working directory or second argument.
Some details about the program:
shall be run on Linux
simple shell programm without any interactive elements
takes a directory argument, which is the working directory
Thanks for any advices.
EDIT:
After some research I found different aproachments, but I can't use any of them.
pivot_root
set_fs_root (linux kernel)
Is there any possibility to use that?
Perhaps there is a possibility to open a file which is contained by a given directory. So I call the function with the argument file path and the "root" path where to look.
I'm assuming that you're on a Linux/MacOSX platform. There are a couple of ways. One is to create a special user for your program who owns that directory, but doesn't have write permissions to anything else in the system*. The other option is to use a program like SELinux to only allow certain operations to the program, but that seems like overkill.
*: You must always give the user read permissions. How will your program run without read access to glibc?
You might want to look into a restricted shell; I think most of the common shells have options for a restricted mode that disables cd, prevents changes to certain environment variables, and some other things. For pdksh, it would be /bin/ksh -r. The option differ for other shells, though, so read the appropriate manual page.

How do i use vfs_readdir in linux kernel?

I'm trying to use a system call to display the contents of a directory. I've been pointed in the direction of vfs_readdir, but I have no clue of how to use it or what to pass to it to get the contents of a directory. All I want to do is be able to list files in a directory similar to how ls works. (I eventually intend to store this in some sort of buffer, but for now just being able to print the contents of a dir would be enough).
I think you probably have to open the directory using filp_open.
For the "flags" argument, you proably need to put some combination of the LOOKUP_ flags listed in include/linux/namei.h
You can see what build_open_flags does here: http://lxr.linux.no/#linux+v3.1.5/fs/open.c#L876 to provide flags to filp_open.
As far as I know, filp_open IS the correct way of opening a file in kernel-space. However, doing so is discouraged.
Provided you do so from the context of a "normal" thread belonging to a user process, I think you will be ok.

What can I do if getcwd() and getenv("PWD") don't match?

I have a build system tool that is using getcwd() to get the current working directory. That's great, except that sometimes people have spaces in their paths, which isn't supported by the build system. You'd think that you could just make a symbolic link:
ln -s "Directory With Spaces" DirectoryWithoutSpaces
And then be happy. But unfortunately for me, getcwd() resolves all the symbolic links. I tried to use getenv("PWD"), but it is not pointing at the same path as I get back from getcwd(). I blame make -C for not updating the environment variable, I think. Right now, getcwd() gives me back a path like this:
/Users/carl/Directory With Spaces/Some/Other/Directories
And getenv("PWD") gives me:
/Users/carl/DirectoryWithoutSpaces
So - is there any function like getcwd() that doesn't resolve the symbolic links?
Edit:
I changed
make -C Some/Other/Directories
to
cd Some/Other/Directories ; make
And then getenv("PWD") works.. If there's no other solution, I can use that.
According to the Advanced Programming in the UNIX Environment bible by Stevens, p.112:
Since the kernel must maintain knowledge of the current working directory, we should be able to fetch its current value. Unfortunately, all the kernel maintains for each process is the i-node number and device identification for the current working directory. The kernel does not maintain the full pathname of the directory.
Sorry, looks like you do need to work around this in another way.
There is no way for getcwd() to determine the path you followed via symbolic links. The basic implementation of getcwd() stats the current directory '.', and then opens the parent directory '..' and scans the entries until it finds the directory name with the same inode number as '.' has. It then repeats the process upwards until it finds the root directory, at which point it has the full path. At no point does it ever traverse a symbolic link. So the goal of having getcwd() calculate the path followed via symlinks is impossible, whether it is implemented as a system call or as a library function.
The best resolution is to ensure that the build system handles path names containing spaces. That means quoting pathnames passed through the shell. C programs don't care about the spaces in the name; it is only when a program like the shell interprets the strings that you run into problems. (Compilers implemented as shell scripts that run pre-processors often have problems with pathnames that contain spaces - speaking from experience.)

Resources