Не защищен от ошибок, но если вы можете отслеживать переименования с помощью inotify, то они должны быть "достаточно хорошими", очевидно, с некоторыми условиями гонки (согласно стандарту при работе с чем-либо inotify). Улучшение этого требует stat () для каждого не удаленного файла, на который есть ссылка из / pro c, и, на мой взгляд, не может существенно улучшить решение.
Первый, шаг, учитывая pid и fd (как строки, потому что так мы получаем их из readdir (3), получим режим, для которого он открыт:
static
int getflags(const char* pidn, const char* fdn)
{
char fnamebfr[525];
char bfr[1 << 13];
sprintf(fnamebfr, "/proc/%s/fdinfo/%s", pidn, fdn);
int fd = open(fnamebfr, O_RDONLY);
if (fd < 0) {
if (errno != ENOENT)
perror(fnamebfr);
return 0;
}
int r = read(fd, bfr, sizeof(bfr));
if (r < 0) {
perror(fnamebfr);
r = 0;
} else if (r == sizeof(bfr)) {
r = 0;
fprintf(stderr, "bfr in %s is too small.\n", __FUNCTION__);
} else {
bfr[r] = 0;
r = 0;
char *fb = strstr(bfr, flagsstr);
if (!fb) {
fprintf(stderr, "Error locating '%s' in %s, content:\n%s\n", flagsstr, fnamebfr, bfr);
} else {
char *nptr;
fb += strlen(flagsstr);
r = strtol(fb, &nptr, 8);
if (*nptr != '\n')
fprintf(stderr, "Parse warning for strtol, endp=\n%s\nbfr=%s\n", nptr, bfr);
}
}
close(fd);
return r;
}
Примечание: если файл был закрыт между ходьбой / proc / / fd / мы вернем 0 здесь (O_RDONLY), если дескриптор файла был использован повторно ... тогда мы вернем совершенно неправильные флаги.
Теперь мы можем ходить / proc / искать O_WRONLY или O_RDWR в этих флагах :
static int fileopenforwrite(const char* path)
{
size_t tlen = strlen(path);
DIR *proc, *fd;
struct dirent *procent, *fdent;
int _fd;
proc = opendir("/proc");
if (!proc) {
perror("/proc");
return -1;
}
while ((procent = readdir(proc))) {
char *endptr;
char fdpath[MAXNAMLEN + 10];
strtol(procent->d_name, &endptr, 10);
if (*endptr)
continue; /* not a pid */
sprintf(fdpath, "/proc/%s/fd", procent->d_name);
_fd = open(fdpath, O_RDONLY);
if (_fd < 0) {
if (errno != ENOENT) /* process terminated + waited */
perror(fdpath);
fd = fdopendir(_fd);
if (!fd) {
perror(fdpath);
close(_fd);
continue;
}
while ((fdent = readdir(fd))) {
if (fdent->d_type == DT_DIR)
continue; /* skip . and .. */
char readbuf[MAXNAMLEN + 11];
ssize_t r = readlinkat(_fd, fdent->d_name, readbuf, sizeof(readbuf));
if (r < 0) {
perror(fdpath);
} else if (r >= (int)sizeof(readbuf)) {
fprintf(stderr, "Bufferoverflow in %s (%s).", __FUNCTION__, __FILE__);
} else {
readbuf[r] = 0;
if (strncmp(path, readbuf, tlen) == 0 &&
(!readbuf[tlen] || strcmp(" (deleted)", readbuf + tlen) == 0))
{
/* We have an FD to the file, now we want to know if it's
* open for writing */
int f = getflags(procent->d_name, fdent->d_name);
if (f & (O_RDONLY | O_RDWR)) {
closedir(fd);
closedir(proc);
return 0;
}
}
}
}
closedir(fd); /* implicitly closes _fd */
}
}
closedir(proc);
return 1;
}
Это вернет 0 при да, 1 при ложном, -1 при невозможности открыть /proc.
Если вы используете это, очевидно, очистите его до требования.