Method for passing parameters of Linux applications, shell scripts, and drivers

  In embedded linux application development, you can pass parameters to the main() function, so that the application program can know what the initial control parameters are, and of course you can choose not to pass parameters to the application program. You can also pass parameters to the script when executing the shell script. In driver development, the insmod command will be used to load a driver module. At this time, we can also use the insmod command to pass parameters to the driver module.

1. Pass parameters to Linux applications

1.1. Method of passing parameters

  In Linux applications, the main function is the entry function of the application. There are generally two ways to write the formal parameters of the main function. If the application does not need to pass parameters, it can be written as follows:

int main(void)
{
    
    
 /* 代码 */
}

  If you need to pass parameters to the application when executing the application, write it as follows:

int main(int argc, char **argv)
{
    
    
 /* 代码 */
}

  The argc parameter indicates the number of incoming parameters, including the path and program name of the application itself. For example, run the hello executable file in the current directory and pass in parameters, as follows:

./hello 123

  Then the number of parameters is 2 at this time, and these parameters are passed to the main function as strings:
  argv[0] is equal to "./hello"
  argv[1] is equal to "123"

1.2. Code example

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
    
    
	int fd, retvalue;
	char *filename;
	unsigned char databuf[1];
	if(argc != 3)
	{
    
    
		printf("Error Usage!\r\n");
		return -1;
	}
	filename = argv[1];
	fd = open(filename, O_RDWR);
	if(fd < 0)
	{
    
    
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}
	databuf[0] = atoi(argv[2]);	
	/* 向文件写入数据 */
	retvalue = write(fd, databuf, sizeof(databuf));
	if(retvalue < 0)
	{
    
    
		printf("LED Control Failed!\r\n");
		close(fd);
		return -1;
	}
	retvalue = close(fd); /* 关闭文件 */
	if(retvalue < 0)
	{
    
    
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

  After compiling, the program can be run with the following command

./test /dev/led 1 //打开 LED 灯

2. Pass parameters to the shell script

2.1. Introduction to parameter passing

  We can pass parameters to the script when executing the Shell script, and the format of getting the parameters in the script is: $n. n represents a number, 1 is the first parameter to execute the script, 2 is the second parameter to execute the script, and so on... In the following
  example, we pass three parameters to the script and output them respectively, where $0 is the executed file name:

#!/bin/bash
echo "Shell 传递参数!";
echo "文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

  Set executable permission for the script, and execute the script, the output is as follows:
insert image description here

2.2. Special characters

   Shell scripts also have several special characters for handling arguments

$#	传递到脚本的参数个数
$*	以一个单字符串显示所有向脚本传递的参数。
     如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$	脚本运行的当前进程ID号
$!	后台运行的最后一个进程的ID号
$@	与$*相同,但是使用时加引号,并在引号中返回每个参数。
    如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$-	显示Shell使用的当前选项,与set命令功能相同。
$?	显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

  Example usage:

#!/bin/bash
echo "Shell 传递参数实例!";
echo "第一个参数为:$1";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";

insert image description here

2.3 The difference between $* and $@

  The same point: all parameters are quoted.
  The difference: it is only reflected in double quotation marks. Assuming that three parameters 1, 2, and 3 are written when the script is running, then "*" is equivalent to "1 2 3" (one parameter is passed), and "@" is equivalent to "1" "2" " 3" (three arguments passed).

#!/bin/bash
echo "-- \$* 演示 ---"
for i in "$*"; do
    echo $i
done

echo "-- \$@ 演示 ---"
for i in "$@"; do
    echo $i
done

  Execute the script, the output is as follows:
insert image description here

3. Pass parameters to the driver module program

3.1. Parameter transfer method

  Parameter passing is divided into two types
  of built-in module parameter passing: the module is compiled and built into the kernel image.
  External module parameter transfer: use the kernel module installed in the command such as insmod.
  For parameter transfer of built-in modules, parameters can generally be passed to built-in modules in the bootloader, for example, the module name can be set in bootargs. Parameter name = value to pass parameters to the built-in module; for external modules, when loading the kernel module , we can pass parameters to the module in the form:

insmode(或 modprobe)模块名 参数名=参数值

  If no arguments are passed, the arguments will use the default values ​​defined within the module.

3.2. Parameter passing method

3.2.1. Variable permissions

  To pass parameters to the driver module, you must declare in the driver source code that a certain variable can be passed as a module parameter, and specify the permission of the variable. The common permission parameters are as follows: In the above macro definition, S_I is a public wording, R = read,
insert image description here
  W = write, X = execute, USR = user, GPR = group.
  Of course, you can also look at it this way: you can convert the last three digits of the number into binary: xxx xxx xxx, look from high to low, the first digit is 1, indicating that the file owner is readable, and the second digit is 1, indicating that the file owner is writable , the third digit is 1, which means the file owner can execute; the next three digits represent the permissions of members of the same group as the file owner; the next three digits are user permissions of different groups.

使用'|'(或操作),可以一次设置多个权限。

3.2.2, passing common parameters

  To pass common parameters (such as bool, char, int), use the following macro definitions:

module_param(name,type,perm)

  name: The name of the parameter to be passed in.
  type: The type of parameter to be passed in.
  perm: The read and write permissions of the parameters to be passed in.
  The module_param() macro creates subdirectories under /sys/module. The above code will view the corresponding parameters in /sys/module/:

3.2.3. Passing arrays

  Passing array parameters uses the following macro definitions:

module_param_array(name,type,nump,perm)

  name: The name of the parameter to be passed in.
  type: The type of parameter to be passed in.
  Nump: the number of parameters actually passed in.
  perm: The read and write permissions of the parameters to be passed in.

3.2.4. Callback when parameters change

  You can write parameters to the parameter name under /sys/module/, which means that the value of the parameter will be changed. If you use module_param() and module_param_array(), you cannot know whether the value of the parameter has changed. If we want the system to know the parameter change, and further perform processing according to the parameter change, you need to use module_param_cb() to register the processing function when the parameter value changes. In the kernel, the module_param_cb() macro is used to register a callback, which will be called whenever the parameter (formal parameter) changes:

module_param_cb(name, ops, arg, perm) 

  name: The name of the parameter to be passed in.
  ops: The set and get operations for this parameter.
  arg: The parameter passed to the return function in ops.
  perm: The read and write permissions of the parameters to be passed in.

3.3. Code example

  Write the kernel code as follows:

#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/moduleparam.h>
 
int value, arr_data[4];
char *name;
int callback_date = 0;

//声明模块参数
module_param(value, int, S_IRUSR|S_IWUSR);                      //integer 类型
module_param(name, charp, S_IRUSR|S_IWUSR);                     //String  类型
module_param_array(arr_data, int, NULL, S_IRUSR|S_IWUSR);      //整型数组
 
/*----------------------Module_param_cb()--------------------------------*/
int notify_param(const char *val, const struct kernel_param *kp)
{
    
    
    int res = param_set_int(val, kp); // Use helper for write variable
    
    if(res == 0) 
	{
    
    
        printk(KERN_INFO "Call back function called...\n");
        printk(KERN_INFO "New value of callback_date = %d\n", callback_date);
        return 0;
    }
    return -1;
}
 
const struct kernel_param_ops my_param_ops = 
{
    
    
    .set = notify_param, 
    .get = param_get_int, 
};
 
module_param_cb(callback_date, &my_param_ops, &callback_date, S_IRUGO|S_IWUSR|S_IWGRP );

static int __init test_init(void)
{
    
    
    int i;
    //打印出模块参数
    printk(KERN_INFO "Value = %d  \n", value);
    printk(KERN_INFO "callback_date = %d  \n", callback_date);
    printk(KERN_INFO "Name = %s \n", name);
    for (i = 0; i < (sizeof arr_data / sizeof (int)); i++) 
	{
    
    
        printk(KERN_INFO "arr_data[%d] = %d\n", i, arr_data[i]);
    }
    printk(KERN_INFO "Kernel Module Inserted Successfully...\n");
    return 0;
}


static void __exit test_exit(void)
{
    
    
    printk(KERN_INFO "Kernel Module Removed Successfully...\n");
}
 
module_init(test_init);
module_exit(test_exit);
 
MODULE_LICENSE("GPL");

  The test code runs in the ubuntu virtual machine, refer to https://blog.csdn.net/xxxx123041/article/details/131560875 to write the corresponding makefile as follows:

KERNELDIR :=/usr/src/linux-headers-5.15.0-79-generic
CURRENT_PATH := $(shell pwd)
obj-m := mytest.o
build: kernel_modules
kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean


3.4, load driver test

  Execute the make command to compile, and the compilation result is shown in the figure below:
insert image description here
  use insmod to load the kernel driver module and pass parameters, and
insert image description here
  use the dmesg command to view the print of the kernel, and you can see that the parameters have been passed in.
insert image description here
  There is no mytest driver module in the /sys/module directory before loading the kernel driver. After loading the driver, the mytest driver module appears in the sys/module directory to transfer data to the callback_data parameter in the parameters directory under the module, as shown in the following
insert image description here
insert image description here
  figure
insert image description here
  Use the dmesg command again to view the kernel print, you can see that the callback function has been executed:
insert image description here

Guess you like

Origin blog.csdn.net/xxxx123041/article/details/132305166