Dường như với tôi đây là đơn giản để làm sử dụng một đối tượng POSIX shared memory:
POSIX chia sẻ đối tượng bộ nhớ có kiên trì hạt nhân: a chia sẻ bộ nhớ đối tượng sẽ tồn tại cho đến khi hệ thống được tắt, hoặc cho đến khi tất cả quá trình có unmapped đối tượng và nó đã bị xóa với shm_unlink
Bất cứ khi nào chương trình của bạn khởi động nó có thể shm_open
một đối tượng mới với một số tên phù hợp và thiết lập các chủ sở hữu đến root
. Đối tượng không cần chứa bất kỳ giá trị cụ thể nào. POSIX yêu cầu tất cả các đối tượng bộ nhớ chia sẻ tồn tại cho đến khi khởi động lại trừ khi bị hủy thủ công (chỉ chủ sở hữu hoặc người tạo của nó mới có thể thực hiện ... trong trường hợp này là người dùng root).
Bất cứ khi nào chương trình của bạn khởi chạy chương trình trước tiên sẽ kiểm tra xem đối tượng bộ nhớ dùng chung đã tồn tại có gốc với tư cách chủ sở hữu chưa. Vì chỉ root mới có thể tạo ra một đối tượng như vậy, và chỉ root hoặc khởi động lại mới có thể phá hủy nó, bạn có thể biết chắc chắn chương trình của bạn đã được khởi động từ lần khởi động gần đây hay chưa. bằng tay.
Tôi đã viết một hàm thử và đặt dưới đây nên thực hiện chính xác những gì bạn cần. Và nó hoạt động ngoại trừ thiết lập quyền sở hữu/phát hiện: vì một số lý do không rõ, cả hai cuộc gọi đến shmctl
đều không thành công trên hệ thống của tôi, nói "đối số không hợp lệ". Trang man
cho shmctl
cho biết lỗi EINVAL
cho biết số nhận dạng đối tượng bộ nhớ không hợp lệ hoặc lệnh không hợp lệ. Nhưng các lệnh IPC_SET
và IPC_STAT
chắc chắn là hợp lệ và bạn có thể xem đầu ra của chương trình để xem số nhận dạng đối tượng hợp lệ đang được tạo và/hoặc mở mỗi lần.
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
int rebooted_test_and_set() {
int err;
int rebooted;
struct shmid_ds shmst;
// create object if nonexistent, returning failure if already exists
int shmid = shm_open("/bootcheck", O_CREAT | O_EXCL);
if (shmid != -1) {
fprintf(stderr, "bootcheck object did not exist, so created: %d\n", shmid);
// object did not exist, so system has been rebooted
rebooted = 1;
// set owner to root, and no permissions for anyone
shmst.shm_perm.uid = 0;
shmst.shm_perm.gid = 0;
shmst.shm_perm.mode = 0;
if ((err = shmctl(shmid, IPC_SET, &shmst)) == -1) {
perror("shmctl: shmctl failed to set owner and permissions for bootcheck object");
exit(1);
}
} else {
// object already exists, so reopen with read access and verify that the owner is root
shmid = shm_open("/bootcheck", O_RDONLY);
if (shmid == -1) {
perror("shm_open: failed, perhaps due to insufficient privileges");
exit(1);
}
fprintf(stderr, "bootcheck object (%d) exists, so checking ownership\n", shmid);
if ((err = shmctl(shmid, IPC_STAT, &shmst)) == -1) {
perror("shmctl: shmctl failed");
exit(1);
}
if (shmst.shm_perm.uid == 0) {
// yes, the bootcheck owner is root,
// so we are confident the system has NOT been rebooted since last launch
rebooted = 0;
} else {
// uh oh, looks like someone created the object illegitimately.
// since that is only possible if the root-owned object did not exist,
// therefore we know that it never did exist since the last reboot
rebooted = 1;
}
}
return rebooted;
}
// for debugging purposes ONLY, so I don't have to keep rebooting to clear the object:
void rebooted_clear() {
if (shm_unlink("/bootcheck") == -1) {
perror("shm_unlink: failed, probably due to insufficient privileges or object nonexistent");
exit(1);
}
}
int main() {
int rebooted = rebooted_test_and_set();
printf("rebooted since last launch: %d\n", rebooted);
return 0;
}
Nếu có bất kỳ manh mối nào, tôi bị bối rối. Một số thông tin và ví dụ về bộ nhớ chia sẻ POSIX here.
Đối với những người không cần đảm bảo tính tương thích POSIX: '/ proc/sys/kernel/random/boot_id' có lẽ là những gì bạn đang tìm kiếm. @BenBurns: Bạn có thể tạo tệp ở một số vị trí "được bảo đảm tạm thời" nếu có, nếu tệp không có, hệ thống đã được khởi động lại. Nếu không, nếu bạn có một quá trình chạy vĩnh viễn, giả sử hệ thống không được khởi động lại trong khi quá trình của bạn đang chạy và giả sử hệ thống có thể đã được khởi động lại nếu quá trình của bạn mới bắt đầu. –
Bạn không thể sử dụng kết hợp thời gian hệ thống và 'CLOCK_MONOTONIC' để phát hiện lệch đồng hồ và/hoặc khởi động lại hệ thống và buộc xác thực lại trong một trong các trường hợp đó? – mpontillo
Một ý tưởng khác có thể là chia rẽ một quá trình lâu dài (tương tự như cách tác nhân ssh-agent) và làm IPC với nó. – mpontillo