linux_C_fork函数/execv/execl的使用_数据类型pid_t/getpid/sleep /warning: missing sentinel in function call

linux_C_fork函数的使用

references

code

主程序

使用到的函数的解释如下

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "prints.h"
/* NAME
fork - create a child process
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
RETURN VALUE
On success, the PID of the child process is returned in the parent
(即,fork()成功时,子进程的pid被返回给父进程), and 0 is returned in the child.(而被fork出来的进程去检查进程中的相应变量时会是0)
On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
*/
/*
SLEEP(3) Linux Programmer's Manual SLEEP(3)
NAME
sleep - sleep for a specified number of seconds
SYNOPSIS
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
DESCRIPTION
sleep() causes the calling thread to sleep either until the number of real-time seconds specified in seconds have elapsed or until a signal arrives which is not ignored.
RETURN VALUE
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
*/
int main()
{
pid_t fpid; // fpid表示fork函数返回的值
fpid = fork();
dprint(fpid);
int time_sec=30;
// 判断fork()是否成创建子进程
if (fpid < 0)
printf("error in fork!");
/* 如果成功创建子进程,则父子进程将执行相同的代码
为了区分父子进程的后续执行,在下方进一步对进程id做判断
其中,我们使用了getpid(),用来获取当前进程的ID */
/* 如果运行这段代码是子进程,那么就会进入到判断会是true(因为,fork返回给子进程中fpid变量的值是0),从而执行else if{}块中的操作
而如果是父进程(fork()的调用者进程执行以下代码时,fpid不会是0,会跳到else块中执行*/
else if (fpid == 0)
{
printf("child process: id is %d\n", getpid());
dprint(fpid);
int i = time_sec;
while (i--)
{
sleep(1);
dprint(i);
printf("child process is running____");
}
}
else
{
printf("parent process, my process id is %d\n", getpid());
dprint(fpid);
int j = time_sec;
while (j--)
{
sleep(1);
dprint(j);
printf("parent process is running!!!!");
}
}
return 0;
}

调试宏头文件

// 数值调试宏
#ifndef CXXU
#define CXXU 1
#define dprint(expr) printf(#expr " = %d\n", expr)
#define gprint(expr) printf(#expr " = %g\n", expr)
#define fprint(expr) printf(#expr " = %f\n", expr)
#define sprint(expr) printf(#expr " = %s\n", expr)
#define sprintln(expr) printf(expr "\n")
#endif

编译程序

  • gcc testFork.c -o testFork

image-20220424085925618

execve example

/* execve.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "prints.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
/* execve */
/*
NAME
execve - execute program
SYNOPSIS
#include <unistd.h>
int execve(const char *pathname, char *const argv[],
char *const envp[]);
DESCRIPTION
execve() executes the program referred to by pathname. This causes the program
that is currently being run by the calling process to be replaced with a new pro‐
gram, with newly initialized stack, heap, and (initialized and uninitialized)
data segments.
pathname must be either a binary executable, or a script starting with a line of the form:
#!interpreter [optional-arg]
For details of the latter case, see "Interpreter scripts" below.
argv is an array of pointers to strings passed to the new program as its command-line arguments. By conven‐
tion, the first of these strings (i.e., argv[0]) should contain the filename associated with the file being
executed. The argv array must be terminated by a NULL pointer. (Thus, in the new program, argv[argc] will be
NULL.)
envp is an array of pointers to strings, conventionally of the form key=value, which are passed as the envi‐
ronment of the new program. The envp array must be terminated by a NULL pointer.
The argument vector and environment can be accessed by the new program's main function, when it is defined as:
int main(int argc, char *argv[], char *envp[])
Note, however, that the use of a third argument to the main function is not specified in POSIX.1; according to
POSIX.1, the environment should be accessed via the external variable environ(7).
*/
/* exec()family */
/*
The exec() family of functions replaces the current process image with a new process image. The functions described in this manual page are layered on top of execve(2). (See the manual page for execve(2) for further details about the replacement of the current process image.)
The initial argument for these functions is the name of a file that is to be executed.
The functions can be grouped based on the letters following the "exec" prefix.
*/
/* execl() family */
// int execl(const char *pathname, const char *arg, ...
// /* (char *) NULL */);
// int execlp(const char *file, const char *arg, ...
// /* (char *) NULL */);
// int execle(const char *pathname, const char *arg, ...
// /*, (char *) NULL, char *const envp[] */);
/*
l - execl(), execlp(), execle()
The const char *arg and subsequent ellipses can be thought of as arg0, arg1, ..., argn.
Together they describe a list of one or more pointers to null-terminated strings that represent the argument list available to the executed program.
The first argument, by convention, should point to the filename associated with the file being executed.
The list of arguments must be terminated by a null pointer,
and, since these are variadic(可变参数的) functions, this pointer must be cast (char *) NULL.
By contrast with the 'l' functions, the 'v' functions (below) specify the command-line arguments of the executed program as a vector. */
/* execv() family */
/* int execv(const char *pathname, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]); */
/* v - execv(), execvp(), execvpe()
The `char *const argv[]` argument is an array of pointers to `null - terminated strings` (char arrays) that represent `the argument list` available to the new program.
The first argument, by convention, should point to the filename associated with the file being executed.
The array of pointers must be terminated by a null pointer. */
/* RETURN VALUE (execve) */
/*
On success, execve() does not return,
on error -1 is returned, and errno is set appropriately. */
/* Note (execve()) */
/* All that execve() does is arrange for an existing process (the calling process) to execute a new program.
One sometimes sees execve() (and the related functions described in exec(3)) described as "executing a new
process" (or similar).
This is a highly misleading description: there is no new process;
many attributes of the calling process remain unchanged (in particular, its PID).*/
/*
//execve() does not return on success,
and the text, initialized data, uninitialized data (bss), and stack of
the calling process are `overwritten `according to the contents of the newly loaded program.
If the current program is being ptraced, a SIGTRAP signal is sent to it after a successful execve().
If the set-user-ID bit is set on the program file referred to by pathname, then the effective user ID of the
calling process is changed to that of the owner of the program file. Similarly, if the set-group-ID bit is
set on the program file, then the effective group ID of the calling process is set to the group of the program
file.
*/
int main(int argc, char *argv[])
{
/* 参数列表在启动者中指定 */
char *newargv[] = {NULL, "hello", "world", NULL};
// char *newargv[] = {"hello", "world", NULL};//wrong!
// char *newargv[] = {argv[1],"hello", "world", NULL};//Ok,the most convinent pattern.
// char **pn = newargv;
// char **pn;
// pn = {"",NULL};
// pn = {"hello", "world", NULL};
// char* newargv[]={"abc","def"}
char *newenviron[] = {NULL};
// if (argc != 2)
// {
// fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
// exit(EXIT_FAILURE);
// }
// newargv[0] = argv[1];
// 调用其他程序,修改进程镜像(由这里的被调用程序的参数由前面定义的newargv指针数组来提供(null-terminated))
// argv[1]:the second item in the command line (the programe name passed to execve to lanunch)
/* as we known,the argv vector of command line program has features:
argv[0] will be the consider as the very command line program name (itself),
so,actually,the first argument of the cli program will be the argv[1],and so on,
in this case,we just need place our actual arguments from the argv[1](the argv[0] could be assigned with NULL) */
char *program = argv[1];
program = argv[1];
char *argv2[] = {program, "../","-li", NULL};
char **newargvs = argv2;
// pn = {NULL,"",NULL};//花括号不可以用来赋值,只可以用来初始化!
// pn = argv2;
sprint(program);
sprint(argv[0]);
sprint(argv[1]);
// traversepp(pn, 2);
execve(program, newargvs, newenviron);
// execve(program, argv2, newenviron);
/* Print a message describing the meaning of the value of errno.
*/
perror("execve"); /* execve() only returns on error */
exit(EXIT_FAILURE);
}
/*
We can use the second program to exec the first as follows:
$ cc myecho.c -o myecho
$ cc execve.c -o execve
//运行时,需要完整的相对路径或者绝对路径(无法通过别名来启动程序,但是符号链接时可以的!)
$ */
/* 测试 */
/*
./execve /usr/local/bin/exa
*/
/*
// ./execve myecho #//失败,不完整的路径参数
./execve ./myecho #//成功
argv[0]: ./myecho
argv[1]: hello
argv[2]: world
*/
/*
└─[1] <git:(master 479de41✱) > gcc execve.c -o execve
┌─[cxxu@cxxuAli] - [~/cppCodes] - [2022-04-26 08:37:37]
└─[0] <git:(master 479de41✱✈) > ./execve ./myecho
argv[0]: ./myecho
argv[1]: hello
argv[2]: world
*/

execl example

#include "prints.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "common_fun.c"
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
int main(int argc, char const *argv[])
{
// 执行/bin目录下的ls, 第一参数为程序名ls, 第二个参数为"-al", 第三个参数为"/etc/passwd"
// execl(
// "/usr/bin/head", "head", "-n", "5",
// "/etc/passwd",NULL);
sprintln("start new program with execl");
if (
execl(
"/bin/ls", "ls", "-al",
"/home", (char *)NULL) < 0)
{
sprintln("error!");
}
else
{
sprintln("success!");
}
return 0;
}

warning: missing sentinel in function call [-Wformat=]

// int execl(const char *pathname, const char *arg, ...
// /* (char *) NULL */);

// char *newp = {NULL};

warning: missing sentinel in function call [-Wformat=] "/home/", (char *)NULL, newp) < 0)

将环境参数删除即可

posted @   xuchaoxin1375  阅读(16)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示