How can I implement chmod command on file by using exec? I would appreciate if anyone can provide me a code.
I'm not going to show you a working model, but execve() works like this:
char *args[] = {"foo", "argument1", "argument2", (char *)NULL};
... handle forking ....
res = execve("/sbin/foo", args, (char *)NULL);
... handle execve() failing ....
The third argument to execve() is left as an exercise for the reader to research, NULL may or may not be suitable for your assignment. Additionally, its up to you to determine what type res should be and what it should equal on success. Notice casting NULL.
The single UNIX specification is usually a good place to start.
From C code, directly calling chmod(2) will almost certainly be a better choice than going through the whole hassle of fork()ing and exec()ing.
Admittedly, most of that hassle is the fork() part, and if your program does not need to do anything else after the exec() call, then just running one of the exec() family functions without forking is reasonably fine (for an exercise in using exec(), that is).
try this: http://support.sas.com/documentation/onlinedoc/sasc/doc/lr2/execve.htm
also see: http://linux.about.com/library/cmd/blcmdl3_execvp.htm
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
main()
{
pid_t pid;
char *parmList[] = {"/bin/chmod", "0700", "/home/op/biaoaai/bead",NULL};
if ((pid = fork()) ==-1) //fork failed
perror("fork error");
else if (pid == 0) { //child (pid==0 if child)
execvp("chmod", parmList);
printf("Return not expected. Must be an execve error.n");
} else { //parent (pid==child process)
//parent specific code goes here
}
}
Edit: I never actually compiled... updated with users working paramList.
Related
Within the child process, is there any way that it determine whether it was launched as a fork with overlay memory, or a vfork with shared memory?
Basically, our logging engine needs to be much more careful (and not log some classes of activity) in vfork. In fork it needs to cooperate with the parent process in ways that it doesn't in vfork. We know how to do those two things, but not how to decide.
I know I could probably intercept the fork/vfork/clone calls, and store the fork/vfork/mapping status as a flag, but it would make life somewhat simpler if there was an API call the child could make to determine its own state.
Extra marks: Ideally I also need to pick up any places in libraries that have done a fork or vfork and then called back into our code. And how that can happen? At least one of the libraries we have offers a popen-like API where a client call-back is called from the fork child before the exec. Clearly the utility of that call-back is significantly restricted in vfork.
All code not specifically designed to work under vfork() doesn't work under vfork().
Technically, you can check if you're in a vfork() child by calling mmap() and checking if the memory mapping was inherited by the parent process under /proc. Do not write this code. It's a really bad idea and nobody should be using it. Really, the best way to tell if you're in a vfork() child or not is to be passed that information. But here comes the punchline. What are you going to do with it?
The things you can't do as a vfork() child include calling fprintf(), puts(), fopen(), or any other standard I/O function, nor malloc() for that matter. Unless the code is very carefully designed, you're best off not calling into your logging framework at all, and if it is carefully designed you don't need to know. A better design would most likely be log your intent before calling vfork() in the first place.
You ask in comments about a library calling fork() and then back into your code. That's already kind of bad. But no library should ever ever call vfork() and back into your code without being explicitly documented as doing so. vfork() is a constrained environment and calling things not expected to be in that environment really should not happen.
A simple solution could use pthread_atfork(). The callbacks registered with this service are triggered only upon fork(). So, the 3rd parameter of the function, which is called in the child process right after the fork, could update a global variable. The child can check the variable and if it is modified, then it has been forked:
/*
Simple program which demonstrates a solution to
make the child process know if it has been forked or vforked
*/
#include <pthread.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t forked;
void child_hdl(void)
{
forked = getpid();
}
int main(void)
{
pid_t pid;
pthread_atfork(0, 0, child_hdl);
pid = fork();
if (pid == 0) {
if (forked != 0) {
printf("1. It is a fork()\n");
}
exit(0);
}
// Father continues here
wait(NULL);
pid = vfork();
if (pid == 0) {
if (forked != 0) {
printf("2. It is a fork()\n");
}
_exit(0);
}
// Father continues here
wait(NULL);
return 0;
}
Build/execution:
$ gcc fork_or_vfork.c
$ ./a.out
1. It is a fork()
I came across kcmp today, which looks like it can answer the basic question - i.e. do two tids or pids share the same VM. If you know they represent forked parent/child pids, this can perhaps tell you if they are vfork()ed.
Of course if they are tids in the same process group then they will by definition share VM.
https://man7.org/linux/man-pages/man2/kcmp.2.html
int syscall(SYS_kcmp, pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
KCMP_VM
Check whether the processes share the same address space.
The arguments idx1 and idx2 are ignored. See the
discussion of the CLONE_VM flag in clone(2).
If you were created by vfork, your parent will be waiting for you to terminate. Otherwise, it's still running. Here's some very ugly code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
void doCheck()
{
char buf[512];
sprintf(buf, "/proc/%d/wchan", (int) getppid());
int j = open(buf, O_RDONLY);
if (j < 0) printf("No open!\n");
int k = read(j, buf, 500);
if (k <= 0) printf("k=%d\n", k);
close(j);
buf[k] = 0;
char *ptr = strstr(buf, "vfork");
if (ptr != NULL)
printf("I am the vfork child!\n");
else
printf("I am the fork child!\n");
}
int main()
{
if (fork() == 0)
{
doCheck();
_exit(0);
}
sleep(1);
if (vfork() == 0)
{
doCheck();
_exit(0);
}
sleep(1);
}
This is not perfect, the parent might be waiting for a subsequent vfork call to complete.
I'm trying to write a C program that restarts itself once. My approach was to fork and in the child process call execve. I thought I would see Hello twice printed. This here prints main twice, but even so if I comment out execve, so I assume I'm not correctly using execve here. The binary is called "restartOnce".
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main(int argc, char *argv[]) {
pid_t pid = fork();
printf("Main.\n");
if (pid == 0) {
char *argv = "hello"; // To silence gcc compiler warning.
char *env = "world"; // To silence gcc compiler warning.
execve("restartOnce", &argv, &env);
} else {
wait(NULL);
printf("Done.\n");
}
return 0;
}
I'm not completely sure what you're trying to accomplish, but I see two things to attend to. We have to get the execve() call right, plus we have to avoid a fork bomb, and this code should do it.
There are lots of ways to avoid a fork bomb, but I chose to set something in the environment, and when the child sees this environment variable, it will know not to continue.
So execve() requires its own argv, which is an array of pointers to individual strings (with a NULL pointer at the end), and it's entirely legit to pass the same parameter you got from main.
The third parameter is like argv, but it's a list of environment variables instead of command line arguments. It has things like TERM=vt100, PATH=/bin/..., and many others. Though you can fetch environment variables individually with getenv("PATH"), Unix/Linux systems provide an argv-like variable environ.
This variable is declared in <unistd.h> but requires the _GNU_SOURCE macro to be defined to expose it.
This done, you can call safely call execve this way:
#define _GNU_SOURCE
#include <unistd.h>
...
execve("restartOnce", argv, environ);
To avoid a fork bomb, one of the first thing the program does is look for the environment variable FORKBOMB - if this is set, we're in the child process and should stop forking other children, perhaps doing something else instead (the real work of the program?)
But if we're in the parent - no variable seen - we actively set the variable by putting it in our own environment that's seen by the child processes: putenv("FORKBOMB=no");
A minor addition: the very first thing the program does is report that it's started up, and it provides its own process ID just so you know what it's doing.
Maybe I misunderstand the problem, but this is how I'd solve what I imagine you're asking:
#define _GNU_SOURCE // for "environ"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main(int argc, char *argv[])
{
printf("Main in pid %d.\n", getpid() );
if (getenv("FORKBOMB") != 0)
{
printf("**We're in the second child, no more forking\n");
exit(0);
}
putenv("FORKBOMB=no");
pid_t pid = fork();
if (pid == 0) {
execve("restartOnce", argv, environ);
} else {
wait(NULL);
printf("Done.\n");
}
return 0;
}
There are quite a few other ways to avoid the fork bomb, but this is as good as any to get the idea across, and others might chime in with their favorites.
EDIT But as I think about this, I'm pretty sure this should not be necessary no matter what you're trying to accomplish unless this is just a learning exercise.
The two things I can imagine are:
1) You need to detach from the parent process so you can run in the background, like a daemon process. In that case, you don't have to exec, just do the daemon work in the child process.
2) If the program has altered itself - perhaps downloaded an updated version of itself, then it does have to call exec to get the new executable, but a fork() would not be required.
So I'm not sure we (or at least I) know what you're trying to accomplish.
I'm not familiar with C at all.
How do I start a child process? This child process is going to execute the specified command with a call to execve(). It will try to search among the file directory specified in the environment variable PATH after the command can be
found as executable file.
I've done this so far:
//Do commands
pid_t childId;
// Fork the child process
child_id = safefork.c(); //can't use fork();
safefork.c
Code provided by the tutor; do not damn the messenger!
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/errno.h>
extern int errno;
#define MAX_PROCESSES 6
static int n_processes(void)
{
return system("exit `/bin/ps | /store/bin/wc -l`")/256;
}
pid_t safefork(void)
{
static int n_initial = -1;
if (n_initial == -1) /* Første gang funksjonen kalles: */
n_initial = n_processes();
else if (n_processes() >= n_initial+MAX_PROCESSES) {
sleep(2);
errno = EAGAIN;
return (pid_t)-1;
}
return fork();
}
Fixing your code
In your code, get the name of the variable spelled consistently (child_id is not the same as childId).
pid_t child_id = simplefork();
if (child_id < 0)
{
...handle error...
}
else if (child_id == 0)
{
...do childish code - execve() etc...
}
else
{
...do parental code - waitpid() etc...
}
Note that the fork() call within the simplefork() function that you're given to use is responsible for creating the new process. That's all it takes; that's the way it's done for all processes except the very first process.
Why not fork()?
What do you mean by "can't use fork()"? The main alternative mechanism is vfork(), which is a very restricted variant of fork() (do not use it); or maybe you could use posix_spawn() or posix_spawnp() — which are incredibly complex alternatives. I don't think there are any other options.
After forking, you might be able to use execvp() instead of execve() — it will do the path search for you. Unless, of course, the purpose of the exercise is to implement execvp() in terms of execve().
Your code uses the notation safefork.c(), but that is not usually correct in C; I could devise a structure type that would make it work, but it probably isn't what you meant.
We got another file called safefork.c — we are not allowed to use fork, only safefork which is already given.
[…before the code was posted]
OK; that's very curious. Presumably, you got a header safefork.h which declares whatever function you're supposed to use (perhaps extern pid_t safefork(void);), and the file safefork.c which does something to wrap around fork(). 'Tis odd: I don't think fork() is a dangerous function. I'd be curious to see what the 'safe fork' does, but I'm sceptical that it is significantly safer than the standard fork function. (I suppose it could does some things like fflush(0) before invoking fork(), or do an error exit if the fork() fails, but that's pushing the envelope.)
[…after the code was posted]
A critique of the code for safefork(), which I fully recognize is not your own code but code that is given to you to use.
The code for safefork() is an abomination. It runs a shell via system() which runs ps and wc to find out how many processes you currently have running, and goes to sleep for 2 seconds if you can't do the fork() because there are too many processes running (more than 6, maybe including the 3 that the safefork() is running!) and then returns "I failed". Someone needs their head seeing to (and no, that isn't you; it is the author of the code).
Oh, and extern int errno; is incorrect; the only safe way to declare errno is by #include <errno.h>. Negative marks to the teacher for that blunder. It is not a good idea to #include <sys/errno.h>; #include <sys/types.h> is not often needed in modern POSIX — from POSIX 2008 onwards at any rate; it may have been unnecessary before that). In the context of the safefork.h header, making it self-contained does require #include <sys/types.h>.
Even assuming that safefork() is a good idea (it isn't), it should be implemented as shown below.
safefork.h
#ifndef SAFEFORK_H_INCLUDED
#define SAFEFORK_H_INCLUDED
#include <sys/types.h> // pid_t
extern pid_t safefork(void);
#endif
safefork.c
#include "safefork.h"
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_PROCESSES 6
static int n_processes(void)
{
return system("exit `/bin/ps | /store/bin/wc -l`") / 256;
}
pid_t safefork(void)
{
static int n_initial = -1;
if (n_initial == -1)
n_initial = n_processes();
else if (n_processes() >= n_initial+MAX_PROCESSES)
{
errno = EAGAIN;
return (pid_t)-1;
}
return fork();
}
I want to open a process from C code, and be able to read its standard output and standard error, while being able to write to its standard input.
The closest I get to achieving this is using popen(), but this does not allow you to read the standard error stream. You could add "2>&1" to the command, but this will not make it possible to distinguish between the standard output and error data. Being able to seperate both streams is required for my application.
Python has popen3 and Ruby has Open3 to do these kind of things, but I can't seem to find a way to do it in C. Any help?
#include <unistd.h>
#include <stdio.h>
...
int pipe_err[2], pipe_out[2], pipe_in[2];
if (pipe(pipe_err) || pipe(pipe_out) || pipe(pipe_in)) { // abbreviated error detection
perror("pipe");
scream_and_run_around_frantically();
exit(BAD);
}
pid_t pid = fork();
if (!pid) { // in child
dup2(pipe_err[1], 2);
dup2(pipe_out[1], 1);
dup2(pipe_in[0], 0);
close(pipe_err[0]);
close(pipe_err[1]);
close(pipe_out[0]);
close(pipe_out[1]);
close(pipe_in[0]);
close(pipe_in[1]);
// close any other files that you don't want the new program
// to get access to here unless you know that they have the
// O_CLOEXE bit set
execl(program_path, program_name, arg1, arg2, arg3);
/* only gets here if there is an error executing the program */
} else { // in the parent
if (pid < 0) {
perror("fork");
error_death_plague_stubbed_toe();
exit(BAD);
}
child_err = pipe_err[0];
close(pipe_err[1]);
child_out = pipe_out[0];
close(pipe_out[1]);
child_in = pipe_in[1];
close(pipe_in[0]);
...
You will probably want to have a look at
man 3 exec
This has lots of functions that turn the current program into a new program. They all have different interfaces, but use execve under the hood.
man 2 execve
Also:
man 2 fork
and
man 2 pipe
You may want to consider using execl(). This is what is used internally by popen().
If you're forking the child process, you can duplicate the handle of stderr and use it in the child.
How can I call awk or sed inside a c program? I know I could use exec(), but I don't want to deal with fork() and all that other nastiness.
Would popen work? It spawns the process, then you read/write with a FILE* handle
Then your choice is system(), or using some library that wraps process spawning for you. The latter, or the hard-core way you wanted to avoid, is recommended if you want fine control over errors, pipes, and so on.
system() is easy enough.
But you should try not to do this if you can. Scripts work best when they are on top of things, not underneath. If you're in UNIX, it's often way better to break up the work and write a top level script to call all of the pieces.
I remember watching a programmer add a huge number of system calls into his C code in order to avoid having to learn the Bourne shell. He figured it was a clever and quick way to get it going, however when it failed, it failed badly. He wasted huge amounts of time debugging the mess. It would have been way faster to just learn a few simple shell commands...
Paul.
libc has functions system and popen, which work kinda like this:
int system(cont char *command) {
const char *argv[4] = {"/bin/sh", "-c", command};
int status;
pid_t child = fork();
if (child == 0) {
execve(argv[0], argv, NULL);
exit(-1);
}
waitpid(child, &status, 0);
return status;
}
FILE *popen(const char *command, const char *type) {
int fds[2];
const char *argv[4] = {"/bin/sh", "-c", command};
pipe(fds);
if (fork() == 0) {
close(fds[0]);
dup2(type[0] == 'r' ? 0 : 1, fds[1]);
close(fds[1]);
execve(argv[0], argv, NULL);
exit(-1);
}
close(fds[1]);
return fdopen(fds[0], type);
}
(except with more error checking and stuff)
If you want finer control over argument handling (instead of going through sh), or you want control over more than one of {stdin, stdout, stderr}, you'll have to write it yourself or find a library. But the standard library covers most use cases.
You can do it via the system() call This Thread is a good example