//应用层程序apptool.c
#include ....
#define SYMLINK_DIR "/var/run"
#define DOORPATH_FMT "/var/run/%s.upcall" //门文件
//app给kernel提供的服务类型,目前只写了一个服务函数
typedef enum kmod_opcode {
/* Service calls type*/
KMOD_OP,
......
} kmod_opcode_t;
/* make sure cleanup 完成了*/
#pragma fini(local_cleanup)
static int error(char *format, ...);
static int create_call_door();
static void call_handler(void *cookie, char *argp, size_t arg_size,
door_desc_t *dp, uint_t n_desc);
static void handle_op(char *argp, size_t arg_size);
static int make_symlink(const char *mod, const char *moddir_suffix,
char *fullbuf, char *symlinkbuf);
static void local_cleanup();
static char kmodpath[PATH_MAX + 1] = "";
static char symlinkpath[PATH_MAX + 1] = "";
#ifdef MODDIR_SUFFIX_64
//64bit的symbolink实现
static char kmodpath64[PATH_MAX + 1] = "";
static char symlinkpath64[PATH_MAX + 1] = "";
#endif
//门调用文件
static char *upcall_file = NULL;
//门调用句柄
static int upcall_dfd = -1;
static int kmod_id = -1;
static mutex_t kmod_init_mutex = DEFAULTMUTEX;
static cond_t kmod_init_cv = DEFAULTCV;
static int kmod_init = 0;
//主函数等待
void main_server_provider() {
/* simple service provider, loop and pause */
for ( ; ; )
pause();
}
//创建一个符号连接
int make_symlink(const char *mod, const char *moddir_suffix,
char *fullbuf, char *symlinkbuf)
{
char temp[PATH_MAX + 1];
char *modname, *lastslash;
int pid_ndigits;
int symlink_len, name_len;
char dummy[1];
if (moddir_suffix == NULL)
moddir_suffix = "";
//得到 mod path string
if (lastslash = strrchr(mod, '/')) {
strlcpy(temp, mod, (lastslash - mod + 2));
strcat(temp, moddir_suffix);
strcat(temp, lastslash + 1);
} else {
sprintf(temp, "%s%s", moddir_suffix, mod);
}
//对symbolink的名字是装载的module
if (realpath(temp, fullbuf) == NULL) {
error("ERROR: make_symlink: realpath(%s, fullbuf): %s\n",
temp, strerror(errno));
return (-1);
}
modname = strrchr(fullbuf, '/') + 1;
//计算PID长度
pid_ndigits = snprintf(dummy, sizeof (dummy), "%d", getpid());
//在SYMLINK_DIR里面创建符号连接
name_len = (MODMAXNAMELEN - 1) - (pid_ndigits + 1);
symlink_len = sprintf(symlinkbuf, "%s/%s%.*s.%d",
SYMLINK_DIR, moddir_suffix, name_len, modname, getpid());
if (symlink_len >= MOD_MAXPATH) {
error("ERROR: make_symlink: symlink name length (%d) >= "
"MOD_MAXPATH (%d)\n", symlink_len, MOD_MAXPATH);
return (-1);
}
sprintf(temp, "%s/%s", SYMLINK_DIR, moddir_suffix);
if (mkdir(temp, 0755) < 0 && errno != EEXIST) {
error("ERROR: make_symlink: mkdir %s: %s\n",
temp, strerror(errno));
return (-1);
}
if (symlink(fullbuf, symlinkbuf) < 0) {
error("ERROR: make_symlink: symlink %s %s: %s\n",
fullbuf, symlinkbuf, strerror(errno));
return (-1);
}
return (0);
}
int main(int argc, char *argv[])
{
if (argc < 2) {
error("ERROR: wrong number of arguments\n");
return (1);
}
//创建门
if (make_symlink(argv[1], "", kmodpath, symlinkpath) < 0)
return (1);
#ifdef MODDIR_SUFFIX_64
if (make_symlink(argv[1], MODDIR_SUFFIX_64, kmodpath64,
symlinkpath64) < 0)
return (1);
#endif /* MODDIR_SUFFIX_64 */
if (create_call_door() < 0)
goto cleanup;
//成为主service提供者
main_server_provider();
/* NOTREACHED */
cleanup:
local_cleanup();
return (1);
}
//清除环境
void local_cleanup()
{
struct stat mystat;
int error;
if (upcall_dfd >= 0) {
door_revoke(upcall_dfd);
upcall_dfd = -1;
}
if (upcall_file != NULL) {
fdetach(upcall_file);
unlink(upcall_file);
upcall_file = NULL;
}
if (lstat(symlinkpath, &mystat) == 0 && S_ISLNK(mystat.st_mode))
unlink(symlinkpath);
#ifdef MODDIR_SUFFIX_64
if (lstat(symlinkpath64, &mystat) == 0 && S_ISLNK(mystat.st_mode))
unlink(symlinkpath64);
#endif /* MODDIR_SUFFIX_64 */
}
//错误处理函数
int error(char *format, ...)
{
va_list ap;
int ret1 = 0, ret2 = 0;
va_start(ap, format);
ret2 = vfprintf(stderr, format, ap);
va_end(ap);
if (ret1 < 0 || ret2 < 0)
return (-1);
else
return (ret2);
}
//创建service door
int create_call_door()
{
const char *kmodname;
char dummy[1];
int len_needed, fd;
if ((upcall_dfd = door_create(call_handler, NULL, 0)) < 0) {
error("ERROR: create_call_door: door_create: %s\n",
strerror(errno));
return (-1);
}
if (kmodname = strrchr(symlinkpath, '/'))
++kmodname;
else
kmodname = symlinkpath;
len_needed = snprintf(dummy, sizeof (dummy), DOORPATH_FMT, kmodname);
upcall_file = malloc(len_needed + 1);
if (upcall_file == NULL) {
error("ERROR: create_call_door: malloc: %s\n",
strerror(errno));
return (-1);
}
sprintf(upcall_file, DOORPATH_FMT, kmodname);
//创建door file
fd = open(upcall_file, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
if (fd < 0) {
error("ERROR: create_upcall_door: %s: %s\n",
upcall_file, strerror(errno));
return (-1);
}
close(fd);
//bind "door file" 和服务提供函数
if (fattach(upcall_dfd, upcall_file) < 0) {
error("ERROR: create_upcall_door: fattach: %s\n",
strerror(errno));
unlink(upcall_file);
return (-1);
}
return (0);
}
//服务提供的handler.利用下面的handle_op提供
void call_handler(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
uint_t n_desc)
{
kmod_opcode_t opcode;
if (arg_size == 0 || argp == NULL) {
error("ERROR: upcall_handler: no argument\n");
door_return(NULL, 0, NULL, 0);
error("ERROR: upcall_handler: door_return: %s\n",
strerror(errno));
return;
}
handle_op(argp, arg_size);
}
//真正的服务提供者
void handle_op(char *argp, size_t arg_size)
{
//在用户空间里面的实际服务功能完成函数,在这里我只让他输出我一个字符串,
//当然,提供的服务可以更复杂!
printf("We provide service!!\n");
door_return(NULL, 0, NULL, 0);
error("ERROR: handle_op: door_return: %s\n", strerror(errno));
}
|