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)

将环境参数删除即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值