Ответ 1
Мне кажется, что это просто сделать с помощью объекта POSIX shared memory:
Объекты разделяемой памяти POSIX имеют стойкость ядра: разделяемая память объект будет существовать до тех пор, пока система не будет выключена, или пока все процессы отменили объект, и он был удален с помощью shm_unlink
Всякий раз, когда ваша программа запускает его, можно shm_open
создать новый объект с некоторым согласованным именем и установить для владельца значение root
. Объект не должен содержать никакого конкретного значения. POSIX требует, чтобы все объекты общей памяти сохранялись до перезагрузки, если они не были уничтожены вручную (что может сделать только его владелец или создатель), который в этом случае является пользователем root.
Всякий раз, когда ваша программа запускает его, он сначала проверяет, существует ли такой объект общей памяти с правами root. Поскольку только root может создать такой объект, и только root или перезагрузка могут его уничтожить, вы можете точно знать, была ли запущена ваша программа с момента последней перезагрузки, сохранить единственное возможное обходное обращение, которое пользователь root вызывает shm_unlink
on объект вручную.
Я написал тестовую функцию ниже того, что должен делать именно то, что вам нужно. И он работает, за исключением настроек/обнаружения владельца: по какой-то неизвестной причине оба вызова shmctl
не работают в моей системе, говоря "недопустимый аргумент". На странице man
для shmctl
говорится, что ошибка EINVAL
указывает либо неверный идентификатор объекта памяти, либо недопустимую команду. Но команды IPC_SET
и IPC_STAT
, безусловно, действительны, и вы можете посмотреть выход программы, чтобы увидеть действительный идентификатор объекта, который создается и/или открыт каждый раз.
#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;
}
Если у кого есть какие-то подсказки, я в тупике. Некоторая информация и примеры для общей памяти POSIX здесь.