java调用shell脚本,不能操作/tmp目录下文件

一、系统/平台

系统:openEuler-22.03

硬件平台:aarch64

二、问题

有个系统升级的需求,java端负责OTA升级包的下载,和版本维护,C端完成系统升级的后续操作,这时候就需要java端在下载完OTA升级包并校验通过之后,通知C端去完成系统升级。其中有三种方式可以完成这种进程间通讯:
1. 本地sock(UNIX Domain Socket)(最终选择的方式)

2. 读文件的方式:inotify 机制来读取

3. UDP网络通讯

备注:问题就是,
1. 通过本地socket的方式在/tmp目录下创建的domain socket文件,或通过读文件的方式在/tmp目录下创建一个.txt文件,在系统命令下调用都正常,但是通过systemd的service来调用就失败,最后的解决方案是,domain文件或.txt文件放到了/run目录下。(具体原因未找到)。

三、最终代码

ota.c (部分代码)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

#define UNIX_DOMAIN_FILE    "/run/OTA_SOCKET.domain"


int listen_socket_create() {
	int fd = 0;
	int b_reuse = 1;
	struct sockaddr_un sun;

	if((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
		printf("socket\n");
		exit(-1);
	}
 
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int)); 

	bzero(&sun, sizeof(struct sockaddr_un));
	sun.sun_family = AF_LOCAL;
	
	if(!access(UNIX_DOMAIN_FILE, F_OK)) {
		unlink(UNIX_DOMAIN_FILE);//删除该文件	
	}

	strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));

	if(bind(fd, (struct sockaddr *)&sun, sizeof(sun))) {
		printf("bind\n");
	}

	if(listen(fd, 2) < 0) {
		printf("listen\n");
	}

	return fd;
}

void *ota_listen_pro(void *argv) {
	int newfd = -1;
	int read_len = 0;
	struct sockaddr_un cun;
	char buffer[15] = {0};
	const char *ota_msg = "ota_notice";
	socklen_t cun_addr_len = sizeof(cun);
	int listen_fd = listen_socket_create();

	while(1) {
		if((newfd = accept(listen_fd, (struct sockaddr *)&cun, &cun_addr_len)) < 0) {
			printf("accept error\n");
		}

		read_len = read(newfd, buffer, sizeof(buffer));
		if(!strncmp(ota_msg, buffer, strlen(ota_msg))) {
			printf("Enter OTA update\n");
			//enter_ota();
	}

	}

	return NULL;
}

void init_ota_listen() {
	pthread_t ota_listen_tid;

	pthread_create(&ota_listen_tid, NULL, ota_listen_pro, NULL);
	pthread_detach(ota_listen_tid);
	return;
}

int main()
{
     init_ota_listen();
}

ota_notice.c

#include 
#include  
#include 
#include 
#include "./rst_key.h"
#include 
#include 
#include 
#include 

#define UNIX_DOMAIN_FILE    "/run/OTA_SOCKET.domain"


int main(int argc, const char *argv[])
{
    int timeout = 5;
	int fd;
    struct sockaddr_un sun;
    const char buffer[] = "ota_notice";

	if((fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		exit(-1);
	}

	bzero(&sun, sizeof(sun));
	sun.sun_family = AF_LOCAL;

    while((access(UNIX_DOMAIN_FILE, F_OK|W_OK) < 0)) {
		sleep(1);
		if(!timeout--) {
			exit(-1);
		}
    }

	strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));

	if(connect(fd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
		perror("connect");
    }

    write(fd, buffer, sizeof(buffer));

    return 0;
}

/etc/systemd/system/ota_notice.service

[Unit]
Description=OTA notice Service
After=rc-local.service

[Service]
Type=simple
#ExecStart=/root/test.sh
WorkingDirectory=/root
ExecStart=/usr/soft/jdk1.8.0_201/bin/java JavaExecuteShell
PrivateTmp=true

[Install]
WantedBy=multi-user.target

/root/test.sh

#!/bin/bash

echo "execute......" > /root/test.log
/root/ota_notice

echo "done" >> /root/test.log

JavaExecuteShell.java

/**
 * java程序调用shell脚本
 */
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
import java.io.IOException;


public class JavaExecuteShell {
    public static void main(String[] args) {
        try {
            //String cmd = "sh /root/test.sh "+args[0] +" "+args[1];
            String cmd = "sh /root/test.sh ";
            System.out.println("cmd = "+cmd);
            Process exec = Runtime.getRuntime().exec(cmd);
            String line;
            //要执行的程序可能输出较多,而运行窗口的缓冲区有限,会造成waitFor阻塞,利用这种方式可以在waitFor命令之前读掉输出缓冲区的内容
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(exec.getInputStream()));
            while ((line = bufferedReader.readLine())!=null){
                System.out.println("result======="+line);
            }
            bufferedReader.close();
            //等待脚本执行完成
            exec.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

四、部署/运行

  

部署:
cp ota ota_notice JavaExecuteShell.class test.sh /root 
cp ota_notice.service /etc/systemd/system/ota_notice.service

运行:
/root/ota &
sleep1
systemctl start ota_notice
sleep 1
systemctl status ota_notice

你可能感兴趣的:(java,开发语言,c)