前言
linux中,如果用C库函数不容易完成的任务,可以用linux命令组合做,将命令结果重定向到文件中, 分析文件的行内容,得到想要的结果。
但是使用临时文件, 可能面临多线程临时文件名冲突的问题.
也可能面临临时文件落地,引起的安全性问题.
前天看到一段代码, 使用了popen来执行命令,读命令结果的操作,都是针对管道完成。
经过比较 : 使用管道的操作,比使用临时文件简洁多了.
前几天写了一个demo, 取当前tty用户信息, 使用了分析临时结果文件的方法。
改了一版, 用管道操作来完成。改动量小,代码清晰度上升了。
试验
运行效果
[root@localhost src]# ./test
info->tty_name = pts/0
info->user_name = root
info->login_time = 2018-06-18 04:54
info->ip = 192.168.180.1
demo下载点
src_test_get_curent_tty_info.7z
demo预览
// @file main.cpp
// @note on fedora22 view syslog use 'journalctl -f'
// 'tail -f /var/log/message' is invalid
#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
// info for crrent tty info
typedef struct _tag_who_info {
char user_name[64];
char tty_name[64];
char login_time[64];
char ip[64];
}TAG_WHO_INFO;
void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test();
bool fn_get_current_tty_info(TAG_WHO_INFO* tty_info);
void fn_show_TAG_WHO_INFO(TAG_WHO_INFO* info);
bool fn_parse_cmd_result_file_who(FILE* fpipe, const char* tty_name, int len_ttyname, TAG_WHO_INFO* /*OUT*/ info);
bool fn_parse_cmd_result_file_tty(FILE* fpipe, char* ttyname, int len_ttyname);
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()
{
TAG_WHO_INFO tty_info;
MYLOG_D(">> fn_test()");
memset(&tty_info, 0, sizeof(TAG_WHO_INFO));
if (fn_get_current_tty_info(&tty_info)) {
fn_show_TAG_WHO_INFO(&tty_info);
} else {
MYLOG_D("can't get current tty info");
}
return 0;
}
bool fn_get_current_tty_info(TAG_WHO_INFO* tty_info)
{
bool rc = false;
char sz_tty_name[64] = {'\0'};
char sz_tty_name_for_who[64] = {'\0'};
char * pfind = NULL;
FILE* fpipe1 = NULL;
FILE* fpipe2 = NULL;
do {
if (NULL == tty_info) {
break;
}
// exec 'tty'
fpipe1 = popen("tty", "r");
if (NULL == fpipe1) {
break;
}
if (!fn_parse_cmd_result_file_tty(fpipe1, sz_tty_name, sizeof(sz_tty_name))) {
break;
}
// printf("current tty name is [%s]\n", sz_tty_name); // current tty name is [/dev/pts/1]
// printf( "Controlling terminal is %s\n", ctermid( NULL ) ); // Controlling terminal is /dev/tty
// get tty name for cmd 'who'
pfind = strstr(sz_tty_name, "/dev/");
if (NULL == pfind) {
strcpy(sz_tty_name_for_who, sz_tty_name);
} else {
strcpy(sz_tty_name_for_who, sz_tty_name + strlen("/dev/"));
}
// exec 'who'
fpipe2 = popen("who", "r");
if (NULL == fpipe2) {
break;
}
// sz_tty_name_for_who is [pts/1]
// printf("sz_tty_name_for_who is [%s]\n", sz_tty_name_for_who);
if (!fn_parse_cmd_result_file_who(fpipe2, sz_tty_name_for_who, strlen(sz_tty_name_for_who), tty_info)) {
break;
}
rc = true;
} while (0);
if (NULL != fpipe1) {
pclose(fpipe1);
fpipe1 = NULL;
}
if (NULL != fpipe2) {
pclose(fpipe2);
fpipe2 = NULL;
}
return rc;
}
bool fn_parse_cmd_result_file_tty(FILE* fpipe, char* ttyname, int len_ttyname)
{
bool rc = false;
char sz_buf[4096] = {'\0'};
int len_read_back = 0;
do {
if ((NULL == fpipe) || (NULL == ttyname)) {
break;
}
memset(sz_buf, 0, sizeof(sz_buf));
if (NULL != fgets(sz_buf, sizeof(sz_buf), fpipe)) {
len_read_back = strlen(sz_buf);
if (len_read_back <= 0) {
break;
}
if (('\r' == sz_buf[len_read_back - 1])
|| ('\n' == sz_buf[len_read_back - 1]))
{
sz_buf[len_read_back - 1] = '\0';
}
}
if ((len_ttyname - 1) < len_read_back) {
break;
}
strcpy(ttyname, sz_buf);
rc = true;
} while (0);
return rc;
}
bool fn_parse_cmd_result_file_who(FILE* fpipe, const char* tty_name, int len_ttyname, TAG_WHO_INFO* /*OUT*/ info)
{
bool rc = false;
char sz_buf[4096] = {'\0'};
int len_read_back = 0;
char* p = NULL;
char* buffer = NULL;
const char* delims = " ";
int pos = 0;
int len = 0;
bool first = true;
bool find_tty_info = false;
do {
if ((NULL == fpipe) || (NULL == tty_name) || (NULL == info)) {
break;
}
memset(info, 0, sizeof(TAG_WHO_INFO));
memset(sz_buf, 0, sizeof(sz_buf));
while (NULL != fgets(sz_buf, sizeof(sz_buf), fpipe)) {
len_read_back = strlen(sz_buf);
if (len_read_back <= 0) {
continue;
}
if (('\r' == sz_buf[len_read_back - 1])
|| ('\n' == sz_buf[len_read_back - 1]))
{
sz_buf[len_read_back - 1] = '\0';
}
/*
[root@localhost src]# who
root tty1 2018-06-15 20:06
root pts/0 2018-06-15 20:09 (192.168.154.1)
root pts/1 2018-06-15 20:35 (192.168.154.1)
root pts/2 2018-06-15 20:40 (192.168.154.1)
root pts/3 2018-06-15 20:49 (192.168.154.1)
root pts/4 2018-06-15 21:13 (192.168.154.1)
*/
first = true;
pos = 0;
buffer = strdup(sz_buf);
if (NULL != buffer) {
do {
if (first) {
p = strtok(buffer, delims);
first = false;
} else {
p = strtok(NULL, delims);
}
if (NULL == p) {
break;
}
switch (pos) {
case 0:
strcpy(info->user_name, p);
break;
case 1:
strcpy(info->tty_name, p);
break;
case 2:
strcpy(info->login_time, p);
strcat(info->login_time, " ");
break;
case 3:
strcat(info->login_time, p);
break;
case 4:
len = strlen(p);
if (len > 0) {
if (p[0] == '(') {
len = strlen(p);
strncpy(info->ip, p + 1, len - 2);
} else {
strcpy(info->ip, p);
}
} else {
strcpy(info->ip, "127.0.0.1");
}
break;
default:
break;
}
pos++;
if (pos > 4) {
break;
}
} while (1);
free(buffer);
buffer = NULL;
}
if (0 == strcmp(info->tty_name, tty_name)) {
find_tty_info = true;
break; // find tty_name info
} else {
memset(info, 0, sizeof(TAG_WHO_INFO));
}
}
rc = find_tty_info;
} while (0);
return rc;
}
void fn_show_TAG_WHO_INFO(TAG_WHO_INFO* info)
{
do {
if (NULL == info) {
break;
}
printf("info->tty_name = %s\n", info->tty_name);
printf("info->user_name = %s\n", info->user_name);
printf("info->login_time = %s\n", info->login_time);
printf("info->ip = %s\n", info->ip);
} while (0);
}
#!/bin/bash
# ==============================================================================
# @file build_all_project.sh
# ==============================================================================
make BIN_NAME="test" rebuild
# ==============================================================================
# @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