Загрузка данных
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#define STATS_FILE "/tmp/chown_stats.txt"
// Функция загрузки статистики из временного файла сессии
void load_statistics(int *success, int *failed) {
*success = 0;
*failed = 0;
FILE *f = fopen(STATS_FILE, "r");
if (f) {
if (fscanf(f, "%d %d", success, failed) != 2) {
*success = 0;
*failed = 0;
}
fclose(f);
}
}
// Функция сохранения статистики во временный файл сессии
void save_statistics(int success, int failed) {
FILE *f = fopen(STATS_FILE, "w");
if (f) {
fprintf(f, "%d %d", success, failed);
fclose(f);
}
}
// Функция сброса статистики
void reset_statistics(void) {
FILE *f = fopen(STATS_FILE, "w");
if (f) {
fprintf(f, "0 0");
fclose(f);
}
}
// Проверка имени пользователя или группы по POSIX и правилам ТЗ
bool is_valid_name(const char *name) {
if (!name || strlen(name) == 0) return false;
// Имя не должно начинаться с цифры или дефиса
if (isdigit((unsigned char)name[0]) || name[0] == '-') return false;
for (int i = 0; name[i] != '\0'; i++) {
char c = name[i];
if (!isalnum((unsigned char)c) && c != '_' && c != '-') {
return false;
}
}
return true;
}
// Валидация токена OWNER[:GROUP] или OWNER[.GROUP]
bool validate_owner_group(const char *token) {
if (!token || strlen(token) == 0) return false;
int colons = 0, dots = 0;
for (int i = 0; token[i] != '\0'; i++) {
if (token[i] == ':') colons++;
if (token[i] == '.') dots++;
}
// Конфликт разделителей или избыточное количество
if ((colons > 0 && dots > 0) || colons > 1 || dots > 1) return false;
if (colons == 1) {
if (strcmp(token, ":") == 0) return false;
if (token[strlen(token) - 1] == ':') return false; // Запрет висящего двоеточия (root:)
char *dup = strdup(token);
char *colon_ptr = strchr(dup, ':');
*colon_ptr = '\0';
char *owner = dup;
char *group = colon_ptr + 1;
bool ok = true;
if (strlen(owner) > 0) ok = ok && is_valid_name(owner);
if (strlen(group) > 0) ok = ok && is_valid_name(group);
free(dup);
return ok;
}
if (dots == 1) {
if (token[0] == '.' || token[strlen(token) - 1] == '.') return false;
char *dup = strdup(token);
char *dot_ptr = strchr(dup, '.');
*dot_ptr = '\0';
char *owner = dup;
char *group = dot_ptr + 1;
bool ok = is_valid_name(owner) && is_valid_name(group);
free(dup);
return ok;
}
return is_valid_name(token);
}
// Главная функция синтаксического анализа строки вызова
bool validate_chown(const char *cmd_line) {
char *line_dup = strdup(cmd_line);
char *tokens[256];
int token_count = 0;
char *tok = strtok(line_dup, " \t");
while (tok && token_count < 256) {
tokens[token_count++] = tok;
tok = strtok(NULL, " \t");
}
if (token_count == 0 || strcmp(tokens[0], "chown") != 0) {
free(line_dup);
return false;
}
bool parsing_flags = true;
char *owner_group = NULL;
int file_count = 0;
for (int i = 1; i < token_count; i++) {
char *t = tokens[i];
if (parsing_flags && t[0] == '-') {
if (strcmp(t, "-") == 0 || strncmp(t, "--", 2) == 0) {
free(line_dup);
return false; // Длинные флаги не поддерживаются в этой версии модулей
}
for (int j = 1; t[j] != '\0'; j++) {
if (t[j] != 'R' && t[j] != 'v' && t[j] != 'c' && t[j] != 'f') {
free(line_dup);
return false; // Неизвестный короткий флаг
}
}
} else {
if (owner_group == NULL) {
owner_group = t;
parsing_flags = false;
} else {
file_count++;
}
}
}
if (!owner_group || file_count == 0) {
free(line_dup);
return false;
}
bool res = validate_owner_group(owner_group);
free(line_dup);
return res;
}
int main(void) {
char line[1024];
int success_count = 0, failed_count = 0;
while (fgets(line, sizeof(line), stdin)) {
// Удаление символа перевода строки
line[strcspn(line, "\r\n")] = '\0';
// Пропуск пустых строк ввода
if (strlen(line) == 0) continue;
load_statistics(&success_count, &failed_count);
if (strcmp(line, "getsuccess") == 0) {
printf("%d\n", success_count);
} else if (strcmp(line, "getfailed") == 0) {
printf("%d\n", failed_count);
} else if (strcmp(line, "getstats") == 0) {
printf("%d %d %d\n", success_count, failed_count, success_count + failed_count);
} else if (strcmp(line, "resetstats") == 0) {
reset_statistics();
printf("\n");
} else {
// Обычная строка вызова утилиты для проверки синтаксиса
if (validate_chown(line)) {
success_count++;
save_statistics(success_count, failed_count);
printf("True\n");
} else {
failed_count++;
save_statistics(success_count, failed_count);
printf("False\n");
}
}
fflush(stdout);
}
return 0;
}