前言
用到realpath来将相对路径转成绝对路径。
但是有个问题,如果这个路径是一个不存在的路径(e.g. mkdir psz_new_path), realpath是没法将不存在的路径或文件转成全路径的。
然后就想到要去看看realpath的实现。
realpath的实现在 gnu coreutils 工程中,具体的实现是 src\realpath.c.
gnu coreutils 编译完,可以生成 realpath这个磁盘命令可执行文件.
我就去看看realpath的帮助,一看,人家已经考虑到了将不存在的文件转成全路径的问题。
只需要在realpath后加参数 -m, 就可以将不存在的路径转成绝对路径。
这样,我只需要调用realpath可执行文件,用管道来取转换后的结果就行,不用去理解参考修改realpath的实现了.
demo下载点
test_realpath_2019_0508_1435.7z
运行效果
将一个复杂的,相对的,不存在路径,转成了绝对的全路径
root@localhost:/home/dev/test_realpath/src# ./test
ok : [~dev/coreutils-8.24/../bash-4.4/doc/../../../../../../../var/log/new_dir/] convert to realpath[/var/log/new_dir]
实现
// @file main.cpp
//
// @note
//
// on fedora22 view syslog use 'journalctl -f'
// 'tail -f /var/log/message' is invalid
//
// on fedora23, can use 'tail -f /var/log/message' to view syslog
// also use 'journalctl -f' to view syslog too
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#ifndef MYLOG_D
#define MYLOG_D(fmt, ...) \
do { \
syslog(LOG_INFO, "[%s : %s.%d : %s()] : " fmt, "LS_LOG", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
} while (0);
#endif // #ifndef MYLOG_D
void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test();
char* realpath_ex(const char* psz_path_in);
int main(int argc, char** argv)
{
char sz_buf[1024] = {'\0'};
#ifdef MAKE_FILE_MACRO__BIN_NAME
sprintf(sz_buf, "%s", MAKE_FILE_MACRO__BIN_NAME);
init(sz_buf);
MYLOG_D("MAKE_FILE_MACRO__BIN_NAME = [%s]", MAKE_FILE_MACRO__BIN_NAME);
#else
init(NULL);
#endif // #ifdef MAKE_FILE_MACRO__BIN_NAME
fn_test();
uninit();
MYLOG_D("THE END");
return EXIT_SUCCESS;
}
void init(const char* psz_log_owner_name)
{
int i = 0;
// daemon(0, 0);
openlog(((NULL != psz_log_owner_name) ? psz_log_owner_name : "my_syslog"), LOG_NOWAIT | LOG_PID, LOG_LOCAL1);
// clear screen (print 25 empty line)
for (i = 0; i < 25; i++) {
MYLOG_D("");
}
signal(SIGTERM, proc_sig_term);
}
void uninit()
{
closelog();
}
void proc_sig_term(int num)
{
MYLOG_D("SIGTERM = %d, num = %d", SIGTERM, num);
MYLOG_D("maybe can do some clean task before quit");
exit(1);
}
int fn_test()
{
MYLOG_D(">> fn_test()");
// 构造一个复杂的, 不存在的相对路径作为测试用例
const char* psz_path_in = "~dev/coreutils-8.24/../bash-4.4/doc/../../../../../../../var/log/new_dir/";
char* psz_realpath = NULL;
psz_realpath = realpath_ex(psz_path_in);
if (NULL == psz_realpath) {
printf("error : can't convert [%s] to realpath\r\n", psz_path_in);
} else {
printf("ok : [%s] convert to realpath[%s]\r\n", psz_path_in, psz_realpath);
free(psz_realpath);
psz_realpath = NULL;
}
return 0;
}
char* realpath_ex(const char* psz_path_in)
{
char* psz_realpath = NULL;
char sz_buf[0x1000] = {'\0'};
const char* psz_cmd_realpath = "realpath -m";
FILE* fp = NULL;
int i_len = 0;
do {
if ((NULL == psz_path_in)
|| ((int)strlen(psz_path_in) >= (int)(sizeof(sz_buf) - strlen(psz_cmd_realpath) - 2) )
) {
break;
}
// realpath是磁盘命令, debian8.8和fedora23都有这个磁盘命令
// 如果真没有realpath磁盘命令, 可以用gnu coreutils工程自己先编译一个出来, 放到/bin或/usr/bin中
// /usr/bin/realpath
// -m, --canonicalize-missing no components of the path need exist
// realpath带上 -m 参数就可以将任意一个路径(包括相对路径,不存在的路径)转成绝对路径
// 将不存在的相对路径转成绝对路径有实际意义. e.g. 用mkdir 在任意位置 建立一个绝对路径的文件夹, 而不需要依赖当前路径
sprintf(sz_buf, "%s %s%c", psz_cmd_realpath, psz_path_in, '\0');
fp = popen(sz_buf, "r");
if (NULL == fp) {
break;
}
memset(sz_buf, 0, sizeof(sz_buf));
if (NULL != fgets(sz_buf, sizeof(sz_buf), fp)) {
i_len = strlen(sz_buf);
if (i_len <= 0) {
break;
}
if (('\r' == sz_buf[i_len - 1])
|| ('\n' == sz_buf[i_len - 1])
) {
sz_buf[i_len - 1] = '\0';
}
psz_realpath = strdup(sz_buf);
}
} while (0);
if (NULL != fp) {
pclose(fp);
fp = NULL;
}
return psz_realpath;
}
# ==============================================================================
# @file makefile
# ==============================================================================
# @note
# howto build project
# make BIN_NAME="bin_name_by_you_want" rebuild
MY_MAKE_FILE_PATH_NAME = $(MAKEFILE_LIST)
# macro from Makefile command line
# BIN_NAME
# macro to C project
MAKE_FILE_MACRO__BIN_NAME="make_file_macro__bin_name"
# var define on Makefile
BIN = output_not_give_bin_name
IS_BUILD_TYPE_VALID = 0
ifdef BIN_NAME
IS_BUILD_TYPE_VALID = 1
BIN = $(BIN_NAME)
MAKE_FILE_MACRO__BIN_NAME=$(BIN_NAME)
else
IS_BUILD_TYPE_VALID = 0
endif
LINE80 = --------------------------------------------------------------------------------
CC = g++ -std=c++98
# -Werror is "warning as error"
CFLAGS = -Wall -Werror -g
INC = -I.
LIBPATH = -L/usr/lib/ -L/usr/local/lib/
ifeq (1, $(IS_BUILD_TYPE_VALID))
LIBS =
else
LIBS =
endif
DEPEND_CODE_DIR = ./empty_dir \
DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)
ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)
SUB_CODE_DIR = ./socket_easy
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)
.PHONY: help
help:
clear
@echo "usage:"
@echo
@echo "build project by given bin name"
@echo "make BIN_NAME=\"bin_name_by_you_want\" rebuild"
@echo
.PHONY: clean
clean:
clear
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo
@echo "make clean begin"
@echo $(LINE80)
@echo "@file $(MY_MAKE_FILE_PATH_NAME)"
@echo "IS_BUILD_TYPE_VALID = $(IS_BUILD_TYPE_VALID)"
@echo "BIN = $(BIN)"
@echo $(LINE80)
rm -f $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
ifeq (1, $(IS_BUILD_TYPE_VALID))
rm -f ./$(BIN)
endif
@echo "make clean over"
.PHONY: all
all:$(BIN)
@echo $(LINE80)
@echo make all
chmod 777 ./$(BIN)
find . -name "$(BIN)"
$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(SHLIBS) $(INC) $(LIBPATH) $(LIBS)
.cpp.o:
$(CC) -c $(CFLAGS) -DMAKE_FILE_MACRO__BIN_NAME="\"$(MAKE_FILE_MACRO__BIN_NAME)\"" $^ -o $@ $(INC) $(LIBPATH) $(LIBS)
.PHONY: rebuild
rebuild:
make -f $(MY_MAKE_FILE_PATH_NAME) clean
ifeq (1, $(IS_BUILD_TYPE_VALID))
@echo $(LINE80)
make -f $(MY_MAKE_FILE_PATH_NAME) all
chmod 775 ./$(BIN)
ldd ./$(BIN)
else
@echo $(LINE80)
@echo "error : Makefile command line input error, please see help"
@echo "please run => make help"
@echo $(LINE80)
endif
#!/bin/bash
# ==============================================================================
# @file build_all_project.sh
# ==============================================================================
make BIN_NAME="test" rebuild