加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
print-the-process-status-to-console-when-shutdown.patch 43.45 KB
一键复制 编辑 原始数据 按行查看 历史
胡宇彪 提交于 2024-01-08 19:20 . update systemd to v255
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
From 5966f7a3b90ee25f23182e9320621a8477a40a51 Mon Sep 17 00:00:00 2001
From: jiangchuangang <jiangchuangang@huawei.com>
Date: Thu, 2 Sep 2021 12:14:19 +0800
Subject: [PATCH] print process status to console when shutdown
---
src/basic/getopt-defs.h | 6 +-
src/basic/process-util.c | 58 ++++
src/basic/process-util.h | 2 +
src/core/fuser.c | 506 +++++++++++++++++++++++++++++++++
src/core/fuser.h | 55 ++++
src/core/job.c | 36 +++
src/core/main.c | 10 +-
src/core/manager.c | 4 +
src/core/manager.h | 2 +
src/core/meson.build | 1 +
src/core/system.conf.in | 1 +
src/shutdown/meson.build | 13 +
src/shutdown/process-status.c | 143 ++++++++++
src/shutdown/process-status.h | 24 ++
src/shutdown/shutdown.c | 43 +++
src/shutdown/umount.c | 5 +
src/test/meson.build | 25 ++
src/test/test-fuser.c | 14 +
src/test/test-process-status.c | 10 +
19 files changed, 953 insertions(+), 5 deletions(-)
create mode 100644 src/core/fuser.c
create mode 100644 src/core/fuser.h
create mode 100644 src/shutdown/process-status.c
create mode 100644 src/shutdown/process-status.h
create mode 100644 src/test/test-fuser.c
create mode 100644 src/test/test-process-status.c
diff --git a/src/basic/getopt-defs.h b/src/basic/getopt-defs.h
index 3efeb6d..dfd17b5 100644
--- a/src/basic/getopt-defs.h
+++ b/src/basic/getopt-defs.h
@@ -37,7 +37,8 @@
#define SHUTDOWN_GETOPT_ARGS \
ARG_EXIT_CODE, \
- ARG_TIMEOUT
+ ARG_TIMEOUT, \
+ ARG_DFX_REBOOT
#define COMMON_GETOPT_OPTIONS \
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL }, \
@@ -72,4 +73,5 @@
#define SHUTDOWN_GETOPT_OPTIONS \
{ "exit-code", required_argument, NULL, ARG_EXIT_CODE }, \
- { "timeout", required_argument, NULL, ARG_TIMEOUT }
+ { "timeout", required_argument, NULL, ARG_TIMEOUT }, \
+ { "dfx-reboot", required_argument, NULL, ARG_DFX_REBOOT }
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 201c559..4e93c9b 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -2060,3 +2060,61 @@ static const char* const sched_policy_table[] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
+
+unsigned int read_cmdline(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep) {
+ char path[PATH_MAX];
+ _cleanup_close_ int fd = 0;
+ int len = 0;
+ unsigned n = 0;
+
+ if (sz <= 0)
+ return 0;
+
+ if (sz >= INT_MAX)
+ sz = INT_MAX-1;
+
+ dst[0] = '\0';
+
+ len = snprintf(path, sizeof(path), "%s/%s", whom, what);
+ if (len <= 0 || (size_t)len >= sizeof(path))
+ return 0;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return 0;
+
+ for (;;) {
+ ssize_t r = read(fd, dst+n, sz-n);
+
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+
+ if (r <= 0)
+ break;
+ n += r;
+
+ if (n == sz) {
+ --n;
+ break;
+ }
+ }
+
+ if (n) {
+ unsigned i = n;
+
+ while (i && dst[i-1] == '\0')
+ --i;
+
+ while (i--)
+ if (dst[i] == '\n' || dst[i] == '\0') dst[i] = sep;
+
+ if (dst[n-1] == ' ')
+ dst[n-1] = '\0';
+ }
+
+ dst[n] = '\0';
+ return n;
+}
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index af6cba1..060c0c2 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -218,6 +218,8 @@ int setpriority_closest(int priority);
_noreturn_ void freeze(void);
+unsigned int read_cmdline(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep);
+
int get_process_threads(pid_t pid);
int is_reaper_process(void);
diff --git a/src/core/fuser.c b/src/core/fuser.c
new file mode 100644
index 0000000..e943469
--- /dev/null
+++ b/src/core/fuser.c
@@ -0,0 +1,506 @@
+#include "fuser.h"
+#include "process-util.h"
+
+static int parse_dir(struct name *this_name, struct inode *match_inode) {
+ if ((this_name == NULL) || (match_inode == NULL)) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't parse dir.");
+ return -1;
+ }
+
+ if (stat(this_name->filename, &this_name->st) != 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't stat dir %s.", this_name->filename);
+ return -1;
+ }
+
+ match_inode->name = this_name;
+ match_inode->device = this_name->st.st_dev;
+ match_inode->inode = this_name->st.st_ino;
+
+ return 0;
+}
+
+static int parse_mounts(struct name *this_name, struct device *match_device) {
+ if ((this_name == NULL) && (match_device == NULL)) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't parse mounts.");
+ return -1;
+ }
+
+ match_device->name = this_name;
+
+ if (S_ISBLK(this_name->st.st_mode))
+ match_device->device = this_name->st.st_rdev;
+ else
+ match_device->device = this_name->st.st_dev;
+
+ return 0;
+}
+
+static uid_t getpiduid(const pid_t pid) {
+ char pathname[PATH_MAX];
+ struct stat st;
+ int r = 0;
+
+ r = snprintf(pathname, sizeof(pathname), "/proc/%d", pid);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Snprintf run failed in getpiduid.");
+ return 0;
+ }
+
+ if (stat(pathname, &st) != 0)
+ return 0;
+
+ return st.st_uid;
+}
+
+static struct stat *get_pidstat(const pid_t pid) {
+ char pathname[PATH_MAX];
+ struct stat *st = NULL;
+ int r = 0;
+
+ st = (struct stat *)malloc(sizeof(struct stat));
+ if (st == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Malloc failed in get_pidstat.");
+ return NULL;
+ }
+
+ r = snprintf(pathname, sizeof(pathname), "/proc/%d/cwd", pid);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Snprintf run failed in get_pidstat.");
+ return NULL;
+ }
+
+ if (stat(pathname, st) != 0) {
+ free(st);
+ return NULL;
+ }
+
+ return st;
+}
+
+static void add_matched_proc(struct name *name, const pid_t pid, const uid_t uid) {
+ struct procs *pptr = NULL;
+ struct procs *last_proc = NULL;
+ char pathname[PATH_MAX];
+ char cmdname[CMD_NAME_LEN + 1];
+ char *cptr = NULL;
+ int cmdlen = 0;
+ FILE *fp = NULL;
+
+ if (name == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Name should not be NULL.");
+ return;
+ }
+
+ //find out wheather the pid already in pptr->pid
+ for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) {
+ last_proc = pptr;
+
+ if (pptr->pid == pid)
+ return;
+ }
+
+ pptr = (struct procs *)malloc(sizeof(struct procs));
+ if (pptr == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't malloc in add_matched_proc.");
+ return;
+ }
+
+ pptr->pid = pid;
+ pptr->uid = uid;
+ pptr->username = NULL;
+ pptr->next = NULL;
+ pptr->command = NULL;
+
+ if ((snprintf(pathname, sizeof(pathname), "/proc/%d/stat", pid) > 0) &&
+ ((fp = fopen(pathname, "r")) != NULL) && (fscanf(fp, "%*d (%100[^)]", cmdname) == 1)) {
+ pptr->command = (char *)malloc(COMM_LEN + 1);
+
+ if (pptr->command != NULL) {
+ cmdlen = 0;
+
+ for (cptr = cmdname; cmdlen < COMM_LEN && *cptr; cptr++) {
+ if (isprint(*cptr)) {
+ pptr->command[cmdlen++] = *cptr;
+ } else if (cmdlen < (COMM_LEN - 4)) {
+ cmdlen += sprintf(&(pptr->command[cmdlen]), "\\%03o", (unsigned int)*cptr);
+ }
+ }
+
+ pptr->command[cmdlen] = '\0';
+ }
+ }
+
+ if (last_proc == NULL)
+ name->matched_procs = pptr;
+ else
+ last_proc->next = pptr;
+
+ if (fp)
+ fclose(fp);
+}
+
+static void check_dir(const pid_t pid, const char *dirname, const struct device *dev,
+ const struct inode *ino, const uid_t uid) {
+ DIR *dirp = NULL;
+ dev_t thedev;
+ struct dirent *direntry = NULL;
+ struct stat st;
+ char dirpath[PATH_MAX];
+ char filepath[PATH_MAX];
+ int r = 0;
+
+ if (dirname == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Dirname is NULL.");
+ return;
+ }
+
+ r = snprintf(dirpath, sizeof(dirpath), "/proc/%d/%s", pid, dirname);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Snprintf run failed in check_dir.");
+ return;
+ }
+
+ dirp = opendir(dirpath);
+ if (dirp == NULL)
+ return;
+
+ while ((direntry = readdir(dirp)) != NULL) {
+ if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
+ continue;
+
+ snprintf(filepath, sizeof(filepath), "/proc/%d/%s/%s",
+ pid, dirname, direntry->d_name);
+
+ if (stat(filepath, &st) != 0)
+ continue;
+
+ thedev = st.st_dev;
+
+ if ((dev != NULL) && (thedev == dev->device)) {
+ add_matched_proc(dev->name, pid, uid);
+ }
+
+ if ((ino != NULL) && (thedev == ino->device)) {
+ if (st.st_ino == ino->inode) {
+ add_matched_proc(ino->name, pid, uid);
+ }
+ }
+ } //end while
+
+ closedir(dirp);
+}
+
+static int scan_procs(const struct name *name, const struct inode *ino, const struct device *dev) {
+ DIR *topproc_dir = NULL;
+ struct dirent *topproc_dent = NULL;
+ pid_t pid;
+ pid_t my_pid;
+ uid_t uid;
+
+ if (name == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Name should not be null in scan_procs.");
+ return -1;
+ }
+
+ if ((ino == NULL) && (dev == NULL)) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Ino and dev should not be NULL in scan_procs.");
+ return -1;
+ }
+
+ topproc_dir = opendir("/proc");
+ if (topproc_dir == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't open dir proc.");
+ return -1;
+ }
+
+ my_pid = getpid();
+
+ while ((topproc_dent = readdir(topproc_dir)) != NULL) {
+ dev_t scan_dev;
+ struct stat *st = NULL;
+
+ /* Not a process */
+ if ((topproc_dent->d_name[0] < '0') || (topproc_dent->d_name[0] > '9'))
+ continue;
+
+ pid = atoi(topproc_dent->d_name);
+ if (pid == my_pid)
+ continue;
+
+ uid = getpiduid(pid);
+
+ st = get_pidstat(pid);
+ scan_dev = st ? st->st_dev : 0;
+
+ if ((dev != NULL) && (scan_dev == dev->device))
+ add_matched_proc(dev->name, pid, uid);
+
+ if ((ino != NULL) && (scan_dev == ino->device)) {
+ if (!st)
+ st = get_pidstat(pid);
+
+ if (st && (st->st_dev == ino->device) && (st->st_ino == ino->inode))
+ add_matched_proc(ino->name, pid, uid);
+ }
+
+ if (st)
+ free(st);
+
+ check_dir(pid, "fd", dev, ino, uid);
+ } // end while
+
+ closedir(topproc_dir);
+ return 0;
+}
+
+static void add_special_proc(struct name *name, const uid_t uid, const char *command) {
+ struct procs *pptr = NULL;
+
+ if (name == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Name should not be null in add_special_proc.");
+ return;
+ }
+
+ for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) {
+ if (pptr->command != NULL && strcmp(pptr->command, command) == 0)
+ return;
+ }
+
+ if ((pptr = malloc(sizeof(struct procs))) == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't allocate memory for add_special_proc() proc");
+ return;
+ }
+
+ pptr->pid = 0;
+ pptr->uid = uid;
+ pptr->next = name->matched_procs;
+ pptr->command = strdup(command);
+
+ name->matched_procs = pptr;
+}
+
+static void scan_mounts_and_swaps(const struct name *name, const struct inode *ino,
+ const struct device *dev, const char *file) {
+ FILE *fp = NULL;
+ char line[PATH_MAX];
+ char *find_mountp = NULL;
+ char *find_space_mounts = NULL;
+ char *find_space_swaps = NULL;
+ struct stat st;
+
+ if (name == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Name should not be null in scan_mounts_and_swaps.");
+ return;
+ }
+
+ if ((ino == NULL) && (dev == NULL)) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Ino and dev should not be null in scan_mounts_and_swaps.");
+ return;
+ }
+
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't open file %s", file);
+ return;
+ }
+
+ while (fgets(line, PATH_MAX, fp) != NULL) {
+ if (strcmp(file, PROC_MOUNTS) == 0) {
+ if ((find_mountp = strchr(line, ' ')) == NULL)
+ continue;
+
+ find_mountp++;
+
+ find_space_mounts = strchr(find_mountp, ' ');
+ if (find_space_mounts == NULL)
+ continue;
+
+ *find_space_mounts = '\0';
+
+ if (stat(find_mountp, &st) != 0)
+ continue;
+ } else {
+ find_space_swaps = strchr(line, ' ');
+ if (find_space_swaps == NULL)
+ continue;
+
+ *find_space_swaps = '\0';
+ find_space_swaps++;
+
+ while (*find_space_swaps == ' ') {
+ find_space_swaps++;
+
+ if (*find_space_swaps == '\0')
+ continue;
+ }
+
+ if (stat(line, &st) != 0) {
+ continue;
+ }
+ }
+
+ if ((dev != NULL) && (st.st_dev == dev->device)) {
+ if (strcmp(file, PROC_MOUNTS) == 0)
+ add_special_proc(dev->name, 0, find_mountp);
+
+ if (strcmp(file, PROC_SWAPS) == 0)
+ add_special_proc(dev->name, 0, line);
+ }
+
+ if ((ino != NULL) && (st.st_dev == ino->device) && (st.st_ino == ino->inode)) {
+ if (strcmp(file, PROC_MOUNTS) == 0)
+ add_special_proc(ino->name, 0, find_mountp);
+
+ if (strcmp(file, PROC_SWAPS) == 0)
+ add_special_proc(ino->name, 0, line);
+ }
+ } // end while
+
+ fclose(fp);
+}
+
+static void print_matches(const struct name *name) {
+ struct procs *pptr = NULL;
+ struct passwd *pwent = NULL;
+ static char P_cmd_long[MAX_COMM_LEN];
+ char cmd_path[PATH_MAX];
+ int r = 0;
+
+ if (name == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Name should not be null in print_matches.");
+ return;
+ }
+
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "\t\tUSER\t\tPID\tCOMMAND");
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "%s:", name->filename);
+
+ for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) {
+ if (pwent == NULL || pwent->pw_uid != pptr->uid)
+ pwent = getpwuid(pptr->uid); //get username
+
+ r = snprintf(cmd_path, sizeof(cmd_path), "/proc/%d", pptr->pid);
+ if (r <= 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't snprintf /proc/%d.", pptr->pid);
+ return;
+ }
+
+ read_cmdline(P_cmd_long, sizeof(P_cmd_long), cmd_path, "cmdline", ' ');
+
+ if (strlen(P_cmd_long) != 0){
+ free(pptr->command);
+ pptr->command = strdup(P_cmd_long);
+ }
+
+ if (pptr->command == NULL)
+ continue;
+
+ if (pwent != NULL) {
+ if (pptr->pid != 0)
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "\t\t%-s\t\t%-d\t%-s", pwent->pw_name, pptr->pid, pptr->command);
+ else
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "\t\t%-s\t\t%-s\t%-s", pwent->pw_name, "kernel", pptr->command);
+ } else {
+ if (pptr->pid != 0)
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "\t\t%-u\t\t%-d\t%-s", pptr->uid, pptr->pid, pptr->command);
+ else
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "\t\t%-u\t\t%-s\t%-s", pptr->uid, "kernel", pptr->command);
+ }
+ }
+}
+
+static void free_matched_procs(struct procs *matched_procs) {
+ struct procs *procs_tmp = NULL;
+ struct procs *procs_next = NULL;
+
+ procs_tmp = matched_procs;
+
+ while (procs_tmp != NULL) {
+ procs_next = procs_tmp->next;
+
+ if (procs_tmp->command)
+ free(procs_tmp->command);
+
+ free(procs_tmp);
+
+ procs_tmp = procs_next;
+ }
+}
+
+int fuser(const char *dir) {
+ struct name this_name;
+ struct inode match_inode;
+ struct device match_device;
+ int r = 0;
+
+ if (dir == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Dir should not be NULL.");
+ return -1;
+ }
+
+ this_name.matched_procs = NULL;
+
+ this_name.filename = strdup(dir); //need to free
+ if (this_name.filename == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't allocate memory for fuser() this_name->filename.");
+ return -1;
+ }
+
+ r = parse_dir(&this_name, &match_inode);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "%s", "Failed to parse file.");
+ free(this_name.filename);
+ return -1;
+ }
+
+ r = parse_mounts(&this_name, &match_device);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "%s", "Failed to parse mounts.");
+ free(this_name.filename);
+ return -1;
+ }
+
+ r = scan_procs(&this_name, &match_inode, &match_device);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "%s", "Failed to scan_procs.");
+ free(this_name.filename);
+ return -1;
+ }
+
+ scan_mounts_and_swaps(&this_name, &match_inode, &match_device, PROC_MOUNTS);
+ scan_mounts_and_swaps(&this_name, &match_inode, &match_device, PROC_SWAPS);
+ print_matches(&this_name);
+
+ free_matched_procs(this_name.matched_procs);
+ free(this_name.filename);
+ return 0;
+}
diff --git a/src/core/fuser.h b/src/core/fuser.h
new file mode 100644
index 0000000..b74b879
--- /dev/null
+++ b/src/core/fuser.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "manager.h"
+
+struct procs {
+ pid_t pid;
+ uid_t uid;
+ char *username;
+ char *command;
+ struct procs *next;
+};
+
+struct name {
+ char *filename;
+ struct stat st;
+ struct procs *matched_procs;
+};
+
+struct inode {
+ struct name *name;
+ dev_t device;
+ ino_t inode;
+};
+
+struct device {
+ struct name *name;
+ dev_t device;
+};
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif /* PATH_MAX */
+
+#define CMD_NAME_LEN 100
+#define COMM_LEN 64
+#define MAX_COMM_LEN 1024
+#define PROC_MOUNTS "/proc/mounts"
+#define PROC_SWAPS "/proc/swaps"
+
+int fuser(const char *dir);
diff --git a/src/core/job.c b/src/core/job.c
index e7d1f65..b86aadd 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -27,6 +27,9 @@
#include "terminal-util.h"
#include "unit.h"
#include "virt.h"
+#include "fuser.h"
+#include "mount.h"
+#include "process-util.h"
Job* job_new_raw(Unit *unit) {
Job *j;
@@ -729,6 +732,8 @@ static const char* job_done_mid(JobType type, JobResult result) {
static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult result) {
_cleanup_free_ char *free_ident = NULL;
const char *ident, *format;
+ int r = 0;
+ pid_t pid;
assert(u);
assert(t >= 0);
@@ -825,6 +830,37 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult
"See 'systemctl status %s' for details.", quoted);
}
}
+
+ if (FLAGS_SET(manager_state(u->manager), MANAGER_STOPPING) && u->manager->defaults.dfx_reboot &&
+ ((u->type == UNIT_MOUNT || u->type == UNIT_AUTOMOUNT) && t == JOB_STOP && result == JOB_FAILED)) {
+
+ Mount *m = MOUNT(u);
+
+ r = safe_fork("(fuser-shutdown)", FORK_RESET_SIGNALS, &pid);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Failed to fork for fuser!");
+ return;
+ }
+ if (r == 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "-------------fuser -mv %s----------------", m->where);
+
+ r = fuser(m->where);
+ if (r < 0)
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't run fuser.");
+
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "%s","----------------------------------------------------------------------");
+ _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+
+ r = wait_for_terminate_with_timeout(pid, 3 * USEC_PER_SEC);
+ if (r == -ETIMEDOUT) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Timeout to run (fuser-shutdown).");
+ (void) kill(pid, SIGKILL);
+ }
+ }
}
static int job_perform_on_unit(Job **j) {
diff --git a/src/core/main.c b/src/core/main.c
index 96b0a11..ddbabaa 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -622,6 +622,7 @@ static int parse_config_file(void) {
{ "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, &arg_crash_chvt },
{ "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
{ "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
+ { "Manager", "DefaultDFXReboot", config_parse_bool, 0, &arg_defaults.dfx_reboot },
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
{ "Manager", "StatusUnitFormat", config_parse_status_unit_format, 0, &arg_status_unit_format },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity },
@@ -1471,7 +1472,8 @@ static int become_shutdown(int objective, int retval) {
char log_level[STRLEN("--log-level=") + DECIMAL_STR_MAX(int)],
timeout[STRLEN("--timeout=") + DECIMAL_STR_MAX(usec_t) + STRLEN("us")],
- exit_code[STRLEN("--exit-code=") + DECIMAL_STR_MAX(uint8_t)];
+ exit_code[STRLEN("--exit-code=") + DECIMAL_STR_MAX(uint8_t)],
+ dfx_reboot[STRLEN("--dfx-reboot=") + DECIMAL_STR_MAX(bool)];
_cleanup_strv_free_ char **env_block = NULL;
usec_t watchdog_timer = 0;
@@ -1482,15 +1484,17 @@ static int become_shutdown(int objective, int retval) {
xsprintf(log_level, "--log-level=%d", log_get_max_level());
xsprintf(timeout, "--timeout=%" PRI_USEC "us", arg_defaults.timeout_stop_usec);
+ xsprintf(dfx_reboot, "--dfx-reboot=%d", arg_defaults.dfx_reboot);
- const char* command_line[10] = {
+ const char* command_line[11] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
table[objective],
log_level,
timeout,
+ dfx_reboot,
/* Note that the last position is a terminator and must contain NULL. */
};
- size_t pos = 4;
+ size_t pos = 5;
assert(command_line[pos-1]);
assert(!command_line[pos]);
diff --git a/src/core/manager.c b/src/core/manager.c
index b29d4e1..53fd07d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -4206,6 +4206,8 @@ int manager_set_unit_defaults(Manager *m, const UnitDefaults *defaults) {
m->defaults.oom_score_adjust = defaults->oom_score_adjust;
m->defaults.oom_score_adjust_set = defaults->oom_score_adjust_set;
+ m->defaults.dfx_reboot = defaults->dfx_reboot;
+
m->defaults.memory_pressure_watch = defaults->memory_pressure_watch;
m->defaults.memory_pressure_threshold_usec = defaults->memory_pressure_threshold_usec;
@@ -4978,6 +4980,8 @@ void unit_defaults_init(UnitDefaults *defaults, RuntimeScope scope) {
.oom_policy = OOM_STOP,
.oom_score_adjust_set = false,
+
+ .dfx_reboot = false,
};
}
diff --git a/src/core/manager.h b/src/core/manager.h
index 93e9d2a..19fb33b 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -177,6 +177,8 @@ typedef struct UnitDefaults {
int oom_score_adjust;
bool oom_score_adjust_set;
+ bool dfx_reboot;
+
CGroupPressureWatch memory_pressure_watch;
usec_t memory_pressure_threshold_usec;
diff --git a/src/core/meson.build b/src/core/meson.build
index 7701d3d..83103ef 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -68,6 +68,7 @@ libcore_sources = files(
'unit-printf.c',
'unit-serialize.c',
'unit.c',
+ 'fuser.c',
)
if conf.get('BPF_FRAMEWORK') == 1
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index dbdc47c..3495b8e 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -80,6 +80,7 @@ DefaultLimitMEMLOCK=64M
#DefaultMemoryPressureThresholdSec=200ms
#DefaultMemoryPressureWatch=auto
#DefaultOOMPolicy=stop
+#DefaultDFXReboot=no
#DefaultSmackProcessLabel=
#ReloadLimitIntervalSec=
#ReloadLimitBurst=
diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build
index 219f9fd..c932e28 100644
--- a/src/shutdown/meson.build
+++ b/src/shutdown/meson.build
@@ -1,5 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
+shutdown_includes = [includes, include_directories('.')]
+
systemd_shutdown_sources = files(
'detach-dm.c',
'detach-loopback.c',
@@ -7,12 +9,18 @@ systemd_shutdown_sources = files(
'detach-swap.c',
'shutdown.c',
'umount.c',
+ 'process-status.c',
)
executables += [
libexec_template + {
'name' : 'systemd-shutdown',
'sources' : systemd_shutdown_sources,
+ 'include_directories' : core_includes,
+ 'link_with' : [
+ libcore,
+ libshared
+ ],
'dependencies' : libmount,
},
libexec_template + {
@@ -34,6 +42,11 @@ executables += [
'detach-swap.c',
'umount.c',
),
+ 'include_directories' : core_includes,
+ 'link_with' : [
+ libcore,
+ libshared
+ ],
'dependencies' : libmount,
},
]
diff --git a/src/shutdown/process-status.c b/src/shutdown/process-status.c
new file mode 100644
index 0000000..11837a2
--- /dev/null
+++ b/src/shutdown/process-status.c
@@ -0,0 +1,143 @@
+#include "process-status.h"
+#include "process-util.h"
+
+static uid_t P_uid;
+static int P_pid;
+static int P_ppid;
+static char P_stat[COMM_LEN];
+static char P_cmd_short[COMM_LEN];
+static char P_user[COMM_LEN];
+static char P_cmd_long[COMM_LEN];
+
+static int read_from_stat(int pid) {
+ char buf[PATH_MAX];
+ char cmd_path[PATH_MAX];
+ char pathname[PATH_MAX];
+ int fd = 0;
+ struct stat st;
+ int r = 0;
+
+ memset(buf, 0, sizeof(buf));
+ memset(cmd_path, 0, sizeof(cmd_path));
+ memset(pathname, 0, sizeof(pathname));
+
+ r = snprintf(pathname, sizeof(pathname), "/proc/%d", pid);
+ if (r <= 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't snprintf /proc/%d.", pid);
+ return -1;
+ }
+
+ if (stat(pathname, &st) != 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't stat %s.", pathname);
+ return -1;
+ }
+
+ P_uid = st.st_uid;
+
+ r = snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+ if (r <= 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't snprintf /proc/%d/stat.", pid);
+ return -1;
+ }
+
+ fd = open(buf, O_RDONLY, 0);
+ if (fd == -1) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't open %s.", buf);
+ return -1;
+ }
+
+ r = read(fd, buf, sizeof(buf) - 1);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't read /proc/%d/stat.", pid);
+ close(fd);
+ return -1;
+ }
+
+ r = sscanf(buf, "%d %s %s %d", &P_pid, P_cmd_short, P_stat, &P_ppid);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Can't run sscanf.");
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ if(P_pid != pid)
+ return -1;
+
+ r = snprintf(cmd_path, sizeof(cmd_path), "/proc/%d", pid);
+ if (r <= 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't snprintf /proc/%d.", pid);
+ return -1;
+ }
+
+ /* read from /proc/$pid/cmdline */
+ read_cmdline(P_cmd_long, sizeof(P_cmd_long), cmd_path, "cmdline", ' ');
+
+ return 0;
+}
+
+static void do_user(void) {
+ struct passwd *p = NULL;
+
+ p = getpwuid(P_uid);
+ if (p) {
+ snprintf(P_user, sizeof(P_user), "%s", p->pw_name);
+ } else {
+ snprintf(P_user, sizeof(P_user), "%u", P_uid);
+ }
+}
+
+static void print_proc(void) {
+ if ((P_ppid != KTHREADD) && (strcmp(P_cmd_short, "(kthreadd)") != 0)) {
+ if (strlen(P_cmd_long) != 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown",
+ "%-s\t%-d\t%-d\t%-s", P_user, P_pid, P_ppid, P_cmd_long);
+ } else {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown",
+ "%-s\t%-d\t%-d\t%-s", P_user, P_pid, P_ppid, P_cmd_short);
+ }
+ }
+}
+
+int process_status(void) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown",
+ "%s", "-----------------------------------------------------------------");
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown",
+ "%s", "USER\tPID\tPPID\tCMD");
+
+ struct dirent *ent = NULL;
+ DIR *dir = NULL;
+
+ dir = opendir("/proc");
+ if (dir == NULL) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown",
+ "%s", "can't open /proc");
+ return -1;
+ }
+
+ while((ent = readdir(dir))){
+ if (*ent->d_name < '0' || *ent->d_name > '9')
+ continue;
+
+ if (read_from_stat(atoi(ent->d_name)) != 0)
+ continue;
+
+ do_user();
+
+ print_proc();
+ }
+
+ closedir(dir);
+
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown",
+ "%s", "------------------------------------------------------------------");
+
+ return 0;
+}
diff --git a/src/shutdown/process-status.h b/src/shutdown/process-status.h
new file mode 100644
index 0000000..2f4333d
--- /dev/null
+++ b/src/shutdown/process-status.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <string.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "manager.h"
+
+#define COMM_LEN 512
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#define KTHREADD 2
+
+int process_status(void);
diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c
index b976b7d..d6beb2d 100644
--- a/src/shutdown/shutdown.c
+++ b/src/shutdown/shutdown.c
@@ -48,13 +48,17 @@
#include "umount.h"
#include "virt.h"
#include "watchdog.h"
+#include "process-status.h"
#define SYNC_PROGRESS_ATTEMPTS 3
#define SYNC_TIMEOUT_USEC (10*USEC_PER_SEC)
+#define SHUTDOWN_TIMEOUT_MIN (0*USEC_PER_SEC)
+#define SHUTDOWN_TIMEOUT_INTERVAL (30*USEC_PER_SEC)
static char* arg_verb;
static uint8_t arg_exit_code;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
+static bool dfx_reboot = false;
static int parse_argv(int argc, char *argv[]) {
enum {
@@ -82,6 +86,13 @@ static int parse_argv(int argc, char *argv[]) {
while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
switch (c) {
+ case ARG_DFX_REBOOT:
+ if (streq(optarg, "1")) {
+ dfx_reboot = true;
+ }
+
+ break;
+
case ARG_LOG_LEVEL:
r = log_set_max_level_from_string(optarg);
if (r < 0)
@@ -341,6 +352,9 @@ int main(int argc, char *argv[]) {
_cleanup_free_ char *cgroup = NULL;
char *arguments[3];
int cmd, r;
+ usec_t now_time, time_interval;
+ pid_t pid;
+ bool fork_failed = false;
/* Close random fds we might have get passed, just for paranoia, before we open any new fds, for
* example for logging. After all this tool's purpose is about detaching any pinned resources, and
@@ -432,8 +446,37 @@ int main(int argc, char *argv[]) {
need_dm_detach = !in_container, need_md_detach = !in_container, can_initrd, last_try = false;
can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0;
+ now_time = now(CLOCK_MONOTONIC);
+ time_interval = SHUTDOWN_TIMEOUT_MIN;
/* Unmount all mountpoints, swaps, and loopback devices */
for (;;) {
+ if (dfx_reboot && (now(CLOCK_MONOTONIC) >= now_time + time_interval)) {
+ r = safe_fork("(process_status)", FORK_RESET_SIGNALS, &pid);
+ if (r < 0) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL,
+ "Failed to fork for process_status!");
+ fork_failed = true;
+ }
+ if (r == 0) {
+ r = process_status();
+ if (r < 0)
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't run ps.");
+
+ _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+
+ now_time = now(CLOCK_MONOTONIC);
+ time_interval = SHUTDOWN_TIMEOUT_INTERVAL;
+
+ if (!fork_failed) {
+ r = wait_for_terminate_with_timeout(pid, 3 * USEC_PER_SEC);
+ if (r == -ETIMEDOUT) {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Timeout to run (process_status).");
+ (void) kill(pid, SIGKILL);
+ }
+ }
+ }
+
bool changed = false;
(void) watchdog_ping();
diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c
index 1a9b99d..220ae2e 100644
--- a/src/shutdown/umount.c
+++ b/src/shutdown/umount.c
@@ -28,6 +28,7 @@
#include "signal-util.h"
#include "umount.h"
#include "virt.h"
+#include "manager.h"
static void mount_point_free(MountPoint **head, MountPoint *m) {
assert(head);
@@ -321,6 +322,7 @@ static int umount_with_timeout(MountPoint *m, bool last_try) {
pfd[0] = safe_close(pfd[0]);
log_info("Unmounting '%s'.", m->path);
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Unmounting '%s'.", m->path);
/* Start the mount operation here in the child Using MNT_FORCE causes some filesystems
* (e.g. FUSE and NFS and other network filesystems) to abort any pending requests and return
@@ -332,9 +334,12 @@ static int umount_with_timeout(MountPoint *m, bool last_try) {
(m->umount_lazily ? MNT_DETACH : MNT_FORCE)));
if (r < 0) {
log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Failed to unmount %s: %m", m->path);
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Failed to unmount '%s'.", m->path);
if (r == -EBUSY && last_try)
log_umount_blockers(m->path);
+ } else {
+ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Unmounted '%s'.", m->path);
}
(void) write(pfd[1], &r, sizeof(r)); /* try to send errno up */
diff --git a/src/test/meson.build b/src/test/meson.build
index a7ca76e..f9e1974 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -596,4 +596,29 @@ executables += [
libudev_basic,
],
},
+ test_template + {
+ 'sources' : files(
+ 'test-process-status.c',
+ '../shutdown/process-status.c'
+ ),
+ 'link_with' : [
+ libcore,
+ libshared,
+ ],
+ 'include_directories' : [
+ shutdown_includes,
+ core_includes,
+ ]
+ },
+ test_template + {
+ 'sources' : files(
+ 'test-fuser.c',
+ '../core/fuser.c'
+ ),
+ 'link_with' : [
+ libcore,
+ libshared,
+ ],
+ 'include_directories' : core_includes,
+ },
]
diff --git a/src/test/test-fuser.c b/src/test/test-fuser.c
new file mode 100644
index 0000000..1527b5b
--- /dev/null
+++ b/src/test/test-fuser.c
@@ -0,0 +1,14 @@
+#include "fuser.h"
+#include "tests.h"
+
+int main(int argc, char *argv[]){
+ test_setup_logging(LOG_DEBUG);
+
+ assert_se(fuser("/") == 0);
+ assert_se(fuser(NULL) < 0);
+ assert_se(fuser("/dev") == 0);
+ assert_se(fuser("/dev/empty/mountpoint") < 0);
+ assert_se(fuser("") < 0);
+
+ return 0;
+}
diff --git a/src/test/test-process-status.c b/src/test/test-process-status.c
new file mode 100644
index 0000000..4a4c3da
--- /dev/null
+++ b/src/test/test-process-status.c
@@ -0,0 +1,10 @@
+#include "process-status.h"
+#include "tests.h"
+
+int main(int argc, char *argv[]){
+
+ assert_se(process_status() == 0);
+
+ return 0;
+
+}
--
2.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化