int main(int argc, char **argv) { config cfg; memset(&cfg, 0, sizeof(cfg)); proc_args(&cfg, argc, argv); if (0 == strcmp(cfg.in_fname, cfg.out_fname) && (0 != strcmp("-", cfg.in_fname))) { fprintf(stderr, "Refusing to overwrite file '%s' with itself.\n", cfg.in_fname); exit(1); } cfg.in = handle_open(cfg.in_fname, IO_READ, cfg.buffer_size); if (cfg.in == NULL) { die("Failed to open input file for read"); } cfg.out = handle_open(cfg.out_fname, IO_WRITE, cfg.buffer_size); if (cfg.out == NULL) { die("Failed to open output file for write"); } #if _WIN32 /* * On Windows, stdin and stdout default to text mode. Switch them to * binary mode before sending data through them. */ _setmode(STDOUT_FILENO, O_BINARY); _setmode(STDIN_FILENO, O_BINARY); #endif if (cfg.cmd == OP_ENC) { return encode(&cfg); } else if (cfg.cmd == OP_DEC) { return decode(&cfg); } else { usage(); } }
static int handle_socket_msg(struct weston_launch *wl) { char control[CMSG_SPACE(sizeof(int))]; char buf[BUFSIZ]; struct msghdr msg; struct iovec iov; int ret = -1; ssize_t len; struct weston_launcher_message *message; memset(&msg, 0, sizeof(msg)); iov.iov_base = buf; iov.iov_len = sizeof buf; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = control; msg.msg_controllen = sizeof control; do { len = recvmsg(wl->sock[0], &msg, 0); } while (len < 0 && errno == EINTR); if (len < 1) return -1; message = (void *) buf; switch (message->opcode) { case WESTON_LAUNCHER_OPEN: ret = handle_open(wl, &msg, len); break; } return ret; }
static void dispatch(struct pfiled *pfiled, struct io *io) { if (cmdline_verbose) { fprintf(stderr, "io: 0x%p, req: 0x%p, op %u\n", (void *)io, (void *)io->req, io->req->op); } switch (io->req->op) { case X_READ: case X_WRITE: handle_read_write(pfiled, io); break; case X_INFO: handle_info(pfiled, io); break; case X_COPY: handle_copy(pfiled, io); break; case X_DELETE: handle_delete(pfiled, io); break; case X_OPEN: handle_open(pfiled, io); break; case X_CLOSE: handle_close(pfiled, io); break; // case X_SNAPSHOT: case X_SYNC: default: handle_unknown(pfiled, io); } }
extern int mainHeatShrink(const char pCh, const char * const inFName, const char * const outFNamem, const int wSize, const int lSize) { size_t sizeStack = 0; top_of_stack = (size_t) &sizeStack; config cfg; memset(&cfg, 0, sizeof(cfg)); getinputArgs( &cfg, pCh, inFName, outFNamem, wSize, lSize); //proc_args(&cfg, argc, argv); if (0 == strcmp(cfg.in_fname, cfg.out_fname) && (0 != strcmp("-", cfg.in_fname))) { fprintf(stderr, "Refusing to overwrite file '%s' with itself.\n", cfg.in_fname); exit(1); } cfg.in = handle_open(cfg.in_fname, IO_READ, cfg.buffer_size); if (cfg.in == NULL) { die("Failed to open input file for read"); } cfg.out = handle_open(cfg.out_fname, IO_WRITE, cfg.buffer_size); if (cfg.out == NULL) { die("Failed to open output file for write"); } #if _WIN32 /* * On Windows, stdin and stdout default to text mode. Switch them to * binary mode before sending data through them. */ _setmode(STDOUT_FILENO, O_BINARY); _setmode(STDIN_FILENO, O_BINARY); #endif if (cfg.cmd == OP_ENC) { encode(&cfg); } else if (cfg.cmd == OP_DEC) { decode(&cfg); } else { usage(); } sizeStack = SizeOfStack(); return sizeStack; }
int main(int argc, char **argv) { config cfg; memset(&cfg, 0, sizeof(cfg)); proc_args(&cfg, argc, argv); if (0 == strcmp(cfg.in_fname, cfg.out_fname) && (0 != strcmp("-", cfg.in_fname))) { printf("Refusing to overwrite file '%s' with itself.\n", cfg.in_fname); exit(1); } cfg.in = handle_open(cfg.in_fname, IO_READ, cfg.buffer_size); if (cfg.in == NULL) { die("Failed to open input file for read"); } cfg.out = handle_open(cfg.out_fname, IO_WRITE, cfg.buffer_size); if (cfg.out == NULL) { die("Failed to open output file for write"); } if (cfg.cmd == OP_ENC) { return encode(&cfg); } else if (cfg.cmd == OP_DEC) { return decode(&cfg); } else { usage(); } }
int handle_vFile (char *own_buf, int packet_len, int *new_packet_len) { if (strncmp (own_buf, "vFile:open:", 11) == 0) handle_open (own_buf); else if (strncmp (own_buf, "vFile:pread:", 11) == 0) handle_pread (own_buf, new_packet_len); else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0) handle_pwrite (own_buf, packet_len); else if (strncmp (own_buf, "vFile:close:", 12) == 0) handle_close (own_buf); else if (strncmp (own_buf, "vFile:unlink:", 13) == 0) handle_unlink (own_buf); else return 0; return 1; }
void handle_syscall(syscall_req_t* req, syscall_rsp_t* rsp) { switch (req->header.id) { case OPEN_ID: handle_open(req, rsp); break; case CLOSE_ID: handle_close(req, rsp); break; case READ_ID: handle_read(req, rsp); break; case WRITE_ID: handle_write(req, rsp); break; case LINK_ID: handle_link(req, rsp); break; case UNLINK_ID: handle_unlink(req, rsp); break; case LSEEK_ID: handle_lseek(req, rsp); break; case FSTAT_ID: handle_fstat(req, rsp); break; case ISATTY_ID: handle_isatty(req, rsp); break; case STAT_ID: handle_stat(req, rsp); break; default: error(-1, "Illegal syscall, should never be here..."); } rsp->header.return_errno = errno; }
int handle_vFile (char *own_buf, int packet_len, int *new_packet_len) { if (startswith (own_buf, "vFile:open:")) handle_open (own_buf); else if (startswith (own_buf, "vFile:pread:")) handle_pread (own_buf, new_packet_len); else if (startswith (own_buf, "vFile:pwrite:")) handle_pwrite (own_buf, packet_len); else if (startswith (own_buf, "vFile:fstat:")) handle_fstat (own_buf, new_packet_len); else if (startswith (own_buf, "vFile:close:")) handle_close (own_buf); else if (startswith (own_buf, "vFile:unlink:")) handle_unlink (own_buf); else if (startswith (own_buf, "vFile:readlink:")) handle_readlink (own_buf, new_packet_len); else return 0; return 1; }
static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_task* task) { struct snapraid_io* io = worker->io; struct snapraid_state* state = io->state; struct snapraid_handle* handle = worker->handle; struct snapraid_disk* disk = handle->disk; block_off_t blockcur = task->position; unsigned char* buffer = task->buffer; int ret; char esc_buffer[ESC_MAX]; /* if the disk position is not used */ if (!disk) { /* use an empty block */ memset(buffer, 0, state->block_size); task->state = TASK_STATE_DONE; return; } /* get the block */ task->block = fs_par2block_find(disk, blockcur); /* if the block is not used */ if (!block_has_file(task->block)) { /* use an empty block */ memset(buffer, 0, state->block_size); task->state = TASK_STATE_DONE; return; } /* get the file of this block */ task->file = fs_par2file_get(disk, blockcur, &task->file_pos); /* if the file is different than the current one, close it */ if (handle->file != 0 && handle->file != task->file) { /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* report = handle->file; ret = handle_close(handle); if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ if (errno == EIO) { log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno)); log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; return; } log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno)); log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that file '%s' can be accessed.\n", handle->path); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_ERROR; return; /* LCOV_EXCL_STOP */ } } ret = handle_open(handle, task->file, state->file_mode, log_error, 0); if (ret == -1) { if (errno == EIO) { /* LCOV_EXCL_START */ log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno)); log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; return; /* LCOV_EXCL_STOP */ } log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } /* check if the file is changed */ if (handle->st.st_size != task->file->size || handle->st.st_mtime != task->file->mtime_sec || STAT_NSEC(&handle->st) != task->file->mtime_nsec /* don't check the inode to support filesystem without persistent inodes */ ) { /* report that the block and the file are not synced */ task->is_timestamp_different = 1; /* follow */ } /* note that we intentionally don't abort if the file has different attributes */ /* from the last sync, as we are expected to return errors if running */ /* in an unsynced array. This is just like the check command. */ task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0); if (task->read_size == -1) { if (errno == EIO) { log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos); task->state = TASK_STATE_IOERROR_CONTINUE; return; } log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } /* store the path of the opened file */ pathcpy(task->path, sizeof(task->path), handle->path); task->state = TASK_STATE_DONE; }
static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task* task) { struct snapraid_io* io = worker->io; struct snapraid_state* state = io->state; struct snapraid_handle* handle = worker->handle; struct snapraid_disk* disk = handle->disk; block_off_t blockcur = task->position; unsigned char* buffer = task->buffer; int ret; char esc_buffer[ESC_MAX]; /* if the disk position is not used */ if (!disk) { /* use an empty block */ memset(buffer, 0, state->block_size); task->state = TASK_STATE_DONE; return; } /* get the block */ task->block = fs_par2block_find(disk, blockcur); /* if the block is not used */ if (!block_has_file(task->block)) { /* use an empty block */ memset(buffer, 0, state->block_size); task->state = TASK_STATE_DONE; return; } /* get the file of this block */ task->file = fs_par2file_get(disk, blockcur, &task->file_pos); /* if the file is different than the current one, close it */ if (handle->file != 0 && handle->file != task->file) { /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* report = handle->file; ret = handle_close(handle); if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ if (errno == EIO) { log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno)); log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to dry.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; return; } log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc(report->sub, esc_buffer), strerror(errno)); log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to dry.\n"); log_fatal("Ensure that file '%s' can be accessed.\n", handle->path); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_ERROR; return; /* LCOV_EXCL_STOP */ } } ret = handle_open(handle, task->file, state->file_mode, log_error, 0); if (ret == -1) { if (errno == EIO) { /* LCOV_EXCL_START */ log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno)); log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to dry.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path); log_fatal("Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; return; /* LCOV_EXCL_STOP */ } log_tag("error:%u:%s:%s: Open error. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0); if (task->read_size == -1) { if (errno == EIO) { log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos); task->state = TASK_STATE_IOERROR_CONTINUE; return; } log_tag("error:%u:%s:%s: Read error at position %u. %s\n", blockcur, disk->name, esc(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); task->state = TASK_STATE_ERROR_CONTINUE; return; } /* store the path of the opened file */ pathcpy(task->path, sizeof(task->path), handle->path); task->state = TASK_STATE_DONE; }
static int state_scrub_process(struct snapraid_state* state, struct snapraid_parity** parity, block_off_t blockstart, block_off_t blockmax, time_t timelimit, block_off_t countlimit, time_t now) { struct snapraid_handle* handle; void* rehandle_alloc; struct snapraid_rehash* rehandle; unsigned diskmax; block_off_t i; unsigned j; void* buffer_alloc; void** buffer; unsigned buffermax; data_off_t countsize; block_off_t countpos; block_off_t countmax; block_off_t recountmax; block_off_t autosavedone; block_off_t autosavelimit; block_off_t autosavemissing; int ret; unsigned error; unsigned silent_error; unsigned l; /* maps the disks to handles */ handle = handle_map(state, &diskmax); /* rehash buffers */ rehandle = malloc_nofail_align(diskmax * sizeof(struct snapraid_rehash), &rehandle_alloc); /* we need disk + 2 for each parity level buffers */ buffermax = diskmax + state->level * 2; buffer = malloc_nofail_vector_align(diskmax, buffermax, state->block_size, &buffer_alloc); if (!state->opt.skip_self) mtest_vector(buffermax, state->block_size, buffer); error = 0; silent_error = 0; /* first count the number of blocks to process */ countmax = 0; for(i=blockstart;i<blockmax;++i) { time_t blocktime; snapraid_info info; /* if it's unused */ info = info_get(&state->infoarr, i); if (info == 0) { /* skip it */ continue; } /* blocks marked as bad are always checked */ if (!info_get_bad(info)) { /* if it's too new */ blocktime = info_get_time(info); if (blocktime > timelimit) { /* skip it */ continue; } /* skip odd blocks, used only for testing */ if (state->opt.force_scrub_even && (i % 2) != 0) { /* skip it */ continue; } /* if the time is less than the limit, always include */ /* otherwise, check if we reached the max count */ if (blocktime == timelimit) { /* if we reached the count limit */ if (countmax >= countlimit) { /* skip it */ continue; } } } ++countmax; } /* compute the autosave size for all disk, even if not read */ /* this makes sense because the speed should be almost the same */ /* if the disks are read in parallel */ autosavelimit = state->autosave / (diskmax * state->block_size); autosavemissing = countmax; /* blocks to do */ autosavedone = 0; /* blocks done */ countsize = 0; countpos = 0; state_progress_begin(state, blockstart, blockmax, countmax); recountmax = 0; for(i=blockstart;i<blockmax;++i) { time_t blocktime; snapraid_info info; int error_on_this_block; int silent_error_on_this_block; int block_is_unsynced; int rehash; /* if it's unused */ info = info_get(&state->infoarr, i); if (info == 0) { /* skip it */ continue; } /* blocks marked as bad are always checked */ if (!info_get_bad(info)) { /* if it's too new */ blocktime = info_get_time(info); if (blocktime > timelimit) { /* skip it */ continue; } /* skip odd blocks, used only for testing */ if (state->opt.force_scrub_even && (i % 2) != 0) { /* skip it */ continue; } /* if the time is less than the limit, always include */ /* otherwise, check if we reaced the count max */ if (blocktime == timelimit) { /* if we reached the count limit */ if (recountmax >= countlimit) { /* skip it */ continue; } } } ++recountmax; /* one more block processed for autosave */ ++autosavedone; --autosavemissing; /* by default process the block, and skip it if something goes wrong */ error_on_this_block = 0; silent_error_on_this_block = 0; /* if all the blocks at this address are synced */ /* if not, parity is not even checked */ block_is_unsynced = 0; /* if we have to use the old hash */ rehash = info_get_rehash(info); /* for each disk, process the block */ for(j=0;j<diskmax;++j) { int read_size; unsigned char hash[HASH_SIZE]; struct snapraid_block* block; int file_is_unsynced; /* if the file on this disk is synced */ /* if not, silent errors are assumed as expected error */ file_is_unsynced = 0; /* by default no rehash in case of "continue" */ rehandle[j].block = 0; /* if the disk position is not used */ if (!handle[j].disk) { /* use an empty block */ memset(buffer[j], 0, state->block_size); continue; } /* if the block is not used */ block = disk_block_get(handle[j].disk, i); if (!block_has_file(block)) { /* use an empty block */ memset(buffer[j], 0, state->block_size); continue; } /* if the block is unsynced, errors are expected */ if (block_has_invalid_parity(block)) { /* report that the block and the file are not synced */ block_is_unsynced = 1; file_is_unsynced = 1; /* follow */ } /* if the file is different than the current one, close it */ if (handle[j].file != 0 && handle[j].file != block_file_get(block)) { /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* file = handle[j].file; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ fprintf(stdlog, "error:%u:%s:%s: Close error. %s\n", i, handle[j].disk->name, file->sub, strerror(errno)); fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to scrub.\n"); printf("Stopping at block %u\n", i); ++error; goto bail; /* LCOV_EXCL_STOP */ } } ret = handle_open(&handle[j], block_file_get(block), state->opt.skip_sequential, stderr); if (ret == -1) { /* file we have tried to open for error reporting */ struct snapraid_file* file = block_file_get(block); fprintf(stdlog, "error:%u:%s:%s: Open error. %s\n", i, handle[j].disk->name, file->sub, strerror(errno)); ++error; error_on_this_block = 1; continue; } /* check if the file is changed */ if (handle[j].st.st_size != block_file_get(block)->size || handle[j].st.st_mtime != block_file_get(block)->mtime_sec || STAT_NSEC(&handle[j].st) != block_file_get(block)->mtime_nsec || handle[j].st.st_ino != block_file_get(block)->inode ) { /* report that the block and the file are not synced */ block_is_unsynced = 1; file_is_unsynced = 1; /* follow */ } /* note that we intentionally don't abort if the file has different attributes */ /* from the last sync, as we are expected to return errors if running */ /* in an unsynced array. This is just like the check command. */ read_size = handle_read(&handle[j], block, buffer[j], state->block_size, stderr); if (read_size == -1) { fprintf(stdlog, "error:%u:%s:%s: Read error at position %u\n", i, handle[j].disk->name, handle[j].file->sub, block_file_pos(block)); ++error; error_on_this_block = 1; continue; } countsize += read_size; /* now compute the hash */ if (rehash) { memhash(state->prevhash, state->prevhashseed, hash, buffer[j], read_size); /* compute the new hash, and store it */ rehandle[j].block = block; memhash(state->hash, state->hashseed, rehandle[j].hash, buffer[j], read_size); } else { memhash(state->hash, state->hashseed, hash, buffer[j], read_size); } if (block_has_updated_hash(block)) { /* compare the hash */ if (memcmp(hash, block->hash, HASH_SIZE) != 0) { fprintf(stdlog, "error:%u:%s:%s: Data error at position %u\n", i, handle[j].disk->name, handle[j].file->sub, block_file_pos(block)); /* it's a silent error only if we are dealing with synced files */ if (file_is_unsynced) { ++error; error_on_this_block = 1; } else { fprintf(stderr, "Data error in file '%s' at position '%u'\n", handle[j].path, block_file_pos(block)); fprintf(stderr, "WARNING! Unexpected data error in a data disk! The block is now marked as bad!\n"); fprintf(stderr, "Try with 'snapraid -e fix' to recover!\n"); ++silent_error; silent_error_on_this_block = 1; } continue; } } } /* if we have read all the data required and it's correct, proceed with the parity check */ if (!error_on_this_block && !silent_error_on_this_block) { unsigned char* buffer_recov[LEV_MAX]; /* buffers for parity read and not computed */ for(l=0;l<state->level;++l) buffer_recov[l] = buffer[diskmax + state->level + l]; for(;l<LEV_MAX;++l) buffer_recov[l] = 0; /* read the parity */ for(l=0;l<state->level;++l) { ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, stdlog); if (ret == -1) { buffer_recov[l] = 0; fprintf(stdlog, "parity_error:%u:%s: Read error\n", i, lev_config_name(l)); ++error; error_on_this_block = 1; /* follow */ } } /* compute the parity */ raid_gen(diskmax, state->level, state->block_size, buffer); /* compare the parity */ for(l=0;l<state->level;++l) { if (buffer_recov[l] && memcmp(buffer[diskmax + l], buffer_recov[l], state->block_size) != 0) { fprintf(stdlog, "parity_error:%u:%s: Data error\n", i, lev_config_name(l)); /* it's a silent error only if we are dealing with synced blocks */ if (block_is_unsynced) { ++error; error_on_this_block = 1; } else { fprintf(stderr, "Data error in parity '%s' at position '%u'\n", lev_config_name(l), i); fprintf(stderr, "WARNING! Unexpected data error in a parity disk! The block is now marked as bad!\n"); fprintf(stderr, "Try with 'snapraid -e fix' to recover!\n"); ++silent_error; silent_error_on_this_block = 1; } } } } if (silent_error_on_this_block) { /* set the error status keeping the existing time and hash */ info_set(&state->infoarr, i, info_set_bad(info)); } else if (error_on_this_block) { /* do nothing, as this is a generic error */ /* likely caused by a not synced array */ } else { /* if rehash is needed */ if (rehash) { /* store all the new hash already computed */ for(j=0;j<diskmax;++j) { if (rehandle[j].block) memcpy(rehandle[j].block->hash, rehandle[j].hash, HASH_SIZE); } } /* update the time info of the block */ /* and clear any other flag */ info_set(&state->infoarr, i, info_make(now, 0, 0)); } /* mark the state as needing write */ state->need_write = 1; /* count the number of processed block */ ++countpos; /* progress */ if (state_progress(state, i, countpos, countmax, countsize)) { /* LCOV_EXCL_START */ break; /* LCOV_EXCL_STOP */ } /* autosave */ if (state->autosave != 0 && autosavedone >= autosavelimit /* if we have reached the limit */ && autosavemissing >= autosavelimit /* if we have at least a full step to do */ ) { autosavedone = 0; /* restart the counter */ state_progress_stop(state); printf("Autosaving...\n"); state_write(state); state_progress_restart(state); } } state_progress_end(state, countpos, countmax, countsize); if (error || silent_error) { printf("\n"); printf("%8u read errors\n", error); printf("%8u data errors\n", silent_error); printf("WARNING! There are errors!\n"); } else { /* print the result only if processed something */ if (countpos != 0) printf("Everything OK\n"); } fprintf(stdlog, "summary:error_read:%u\n", error); fprintf(stdlog, "summary:error_data:%u\n", silent_error); if (error + silent_error == 0) fprintf(stdlog, "summary:exit:ok\n"); else fprintf(stdlog, "summary:exit:error\n"); fflush(stdlog); bail: for(j=0;j<diskmax;++j) { ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n"); ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ } } free(handle); free(buffer_alloc); free(buffer); free(rehandle_alloc); if (state->opt.expect_recoverable) { if (error + silent_error == 0) return -1; } else { if (error + silent_error != 0) return -1; } return 0; }
void do_menu_command( long menuResult) { short menuID; short menuItem; menuID= GET_MENU_ID(menuResult); menuItem= GET_MENU_ITEM(menuResult); switch (menuID) { case mApple: switch (menuItem) { case iAbout: break; default: #if defined(OP_PLATFORM_MAC_CFM) && !defined(OP_PLATFORM_MAC_CARBON_FLAG) { Str255 daName; GetMenuItemText(GetMenuHandle(mApple), menuItem, daName); OpenDeskAcc(daName); } #endif break; } break; case mFile: switch (menuItem) { case iOpen: case iOpenPassive: handle_open(menuItem==iOpen, false); break; case iOpenActiveUI: case iOpenPassiveUI: handle_open(menuItem==iOpenActiveUI, true); break; case iClose: close_front_window(); break; case iQuit: handle_quit(); break; } break; case mSpecial: switch(menuItem) { case iSendPacket: send_packet(); break; case iSendStream: send_stream(); break; case iProtocolAlive: is_alive(); break; case iAcceptingConnections: accepting_connections= !accepting_connections; check_menu_item(menuID, menuItem, accepting_connections); break; case iActiveEnumeration: active_enumeration= !active_enumeration; check_menu_item(menuID, menuItem, active_enumeration); break; case iSetTimeout: set_timeout(); break; case iGetInfo: report_info(); break; case iGetConfigString: // get_config_string(); break; } break; case mWindowMenu: switch(menuItem) { case iCascade: case iTile: cascade_or_tile_windows(menuItem==iCascade); break; } } #if OP_PLATFORM_MAC_CFM || OP_PLATFORM_MAC_MACHO HiliteMenu(0); #endif adjust_menus(); return; }
static int state_dry_process(struct snapraid_state* state, struct snapraid_parity** parity, block_off_t blockstart, block_off_t blockmax) { struct snapraid_handle* handle; unsigned diskmax; block_off_t i; unsigned j; void* buffer_alloc; unsigned char* buffer_aligned; int ret; data_off_t countsize; block_off_t countpos; block_off_t countmax; unsigned error; unsigned l; handle = handle_map(state, &diskmax); buffer_aligned = malloc_nofail_align(state->block_size, &buffer_alloc); error = 0; /* dry all the blocks in files */ countmax = blockmax - blockstart; countsize = 0; countpos = 0; state_progress_begin(state, blockstart, blockmax, countmax); for(i=blockstart;i<blockmax;++i) { /* for each disk, process the block */ for(j=0;j<diskmax;++j) { int read_size; struct snapraid_block* block = BLOCK_EMPTY; if (handle[j].disk) block = disk_block_get(handle[j].disk, i); if (!block_has_file(block)) { /* if no file, nothing to do */ continue; } /* if the file is closed or different than the current one */ if (handle[j].file == 0 || handle[j].file != block_file_get(block)) { /* close the old one, if any */ ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to dry.\n"); printf("Stopping at block %u\n", i); ++error; goto bail; /* LCOV_EXCL_STOP */ } /* open the file only for reading */ ret = handle_open(&handle[j], block_file_get(block), state->opt.skip_sequential, stdlog); if (ret == -1) { /* LCOV_EXCL_START */ fprintf(stderr, "DANGER! Unexpected open error in a data disk, it isn't possible to dry.\n"); printf("Stopping at block %u\n", i); ++error; goto bail; /* LCOV_EXCL_STOP */ } } /* read from the file */ read_size = handle_read(&handle[j], block, buffer_aligned, state->block_size, stdlog); if (read_size == -1) { fprintf(stdlog, "error:%u:%s:%s: Read error at position %u\n", i, handle[j].disk->name, block_file_get(block)->sub, block_file_pos(block)); ++error; continue; } countsize += read_size; } /* read the parity */ for(l=0;l<state->level;++l) { if (parity[l]) { ret = parity_read(parity[l], i, buffer_aligned, state->block_size, stdlog); if (ret == -1) { fprintf(stdlog, "parity_error:%u:%s: Read error\n", i, lev_config_name(l)); ++error; } } } /* count the number of processed block */ ++countpos; /* progress */ if (state_progress(state, i, countpos, countmax, countsize)) { /* LCOV_EXCL_START */ break; /* LCOV_EXCL_STOP */ } } state_progress_end(state, countpos, countmax, countsize); bail: /* close all the files left open */ for(j=0;j<diskmax;++j) { ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n"); ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ } } if (error) { printf("%u read errors\n", error); } else { printf("Everything OK\n"); } free(handle); free(buffer_alloc); if (error != 0) return -1; return 0; }
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_size, uint32_t block_size) { int result; uint64_t mem = 0; uint64_t avail = 0; // If something's already mounted on our mountpoint, try to remove // it. (Mostly in case of a previous abnormal exit.) umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE); if (block_size < 1024) { fprintf(stderr, "block size (%u) is too small\n", block_size); return -1; } if (block_size > (1<<22)) { // 4 MiB fprintf(stderr, "block size (%u) is too large\n", block_size); return -1; } struct fuse_data fd; memset(&fd, 0, sizeof(fd)); fd.vtab = vtab; fd.cookie = cookie; fd.file_size = file_size; fd.block_size = block_size; fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1); if (fd.file_blocks > (1<<18)) { fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks); result = -1; goto done; } fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE); if (fd.hashes == NULL) { fprintf(stderr, "failed to allocate %d bites for hashes\n", fd.file_blocks * SHA256_DIGEST_SIZE); result = -1; goto done; } fd.uid = getuid(); fd.gid = getgid(); fd.curr_block = -1; fd.block_data = (uint8_t*)malloc(block_size); if (fd.block_data == NULL) { fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size); result = -1; goto done; } fd.extra_block = (uint8_t*)malloc(block_size); if (fd.extra_block == NULL) { fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size); result = -1; goto done; } fd.block_cache_max_size = 0; fd.block_cache_size = 0; fd.block_cache = NULL; mem = free_memory(); avail = mem - (INSTALL_REQUIRED_MEMORY + fd.file_blocks * sizeof(uint8_t*)); if (mem > avail) { uint32_t max_size = avail / fd.block_size; if (max_size > fd.file_blocks) { max_size = fd.file_blocks; } // The cache must be at least 1% of the file size or two blocks, // whichever is larger. if (max_size >= fd.file_blocks/100 && max_size >= 2) { fd.block_cache_max_size = max_size; fd.block_cache = (uint8_t**)calloc(fd.file_blocks, sizeof(uint8_t*)); } } signal(SIGTERM, sig_term); fd.ffd = open("/dev/fuse", O_RDWR); if (fd.ffd < 0) { perror("open /dev/fuse"); result = -1; goto done; } char opts[256]; snprintf(opts, sizeof(opts), ("fd=%d,user_id=%d,group_id=%d,max_read=%u," "allow_other,rootmode=040000"), fd.ffd, fd.uid, fd.gid, block_size); result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts); if (result < 0) { perror("mount"); goto done; } uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; while (!terminated) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd.ffd, &fds); tv.tv_sec = 1; tv.tv_usec = 0; int rc = select(fd.ffd+1, &fds, NULL, NULL, &tv); if (rc <= 0) { continue; } ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer))); if (len < 0) { if (errno != EINTR) { perror("read request"); if (errno == ENODEV) { result = -1; break; } } continue; } if ((size_t)len < sizeof(struct fuse_in_header)) { fprintf(stderr, "request too short: len=%zu\n", (size_t)len); continue; } struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer; void* data = request_buffer + sizeof(struct fuse_in_header); result = -ENOSYS; switch (hdr->opcode) { case FUSE_INIT: result = handle_init(data, &fd, hdr); break; case FUSE_LOOKUP: result = handle_lookup(data, &fd, hdr); break; case FUSE_GETATTR: result = handle_getattr(data, &fd, hdr); break; case FUSE_OPEN: result = handle_open(data, &fd, hdr); break; case FUSE_READ: result = handle_read(data, &fd, hdr); break; case FUSE_FLUSH: result = handle_flush(data, &fd, hdr); break; case FUSE_RELEASE: result = handle_release(data, &fd, hdr); break; default: fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode); break; } if (result != NO_STATUS) { struct fuse_out_header outhdr; outhdr.len = sizeof(outhdr); outhdr.error = result; outhdr.unique = hdr->unique; TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr))); } } done: fd.vtab->close(fd.cookie); result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH); if (result < 0) { printf("fuse_sideload umount failed: %s\n", strerror(errno)); } if (fd.ffd) close(fd.ffd); if (fd.block_cache) { uint32_t n; for (n = 0; n < fd.file_blocks; ++n) { free(fd.block_cache[n]); } free(fd.block_cache); } free(fd.hashes); free(fd.block_data); free(fd.extra_block); return result; }
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_size, uint32_t block_size) { int result; // If something's already mounted on our mountpoint, try to remove // it. (Mostly in case of a previous abnormal exit.) umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE); if (block_size < 1024) { fprintf(stderr, "block size (%u) is too small\n", block_size); return -1; } if (block_size > (1<<22)) { // 4 MiB fprintf(stderr, "block size (%u) is too large\n", block_size); return -1; } struct fuse_data fd; memset(&fd, 0, sizeof(fd)); fd.vtab = vtab; fd.cookie = cookie; fd.file_size = file_size; fd.block_size = block_size; fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1); if (fd.file_blocks > (1<<18)) { fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks); result = -1; goto done; } fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE); if (fd.hashes == NULL) { fprintf(stderr, "failed to allocate %d bites for hashes\n", fd.file_blocks * SHA256_DIGEST_SIZE); result = -1; goto done; } fd.uid = getuid(); fd.gid = getgid(); fd.curr_block = -1; fd.block_data = (uint8_t*)malloc(block_size); if (fd.block_data == NULL) { fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size); result = -1; goto done; } fd.extra_block = (uint8_t*)malloc(block_size); if (fd.extra_block == NULL) { fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size); result = -1; goto done; } fd.ffd = open("/dev/fuse", O_RDWR); if (fd.ffd < 0) { perror("open /dev/fuse"); result = -1; goto done; } char opts[256]; snprintf(opts, sizeof(opts), ("fd=%d,user_id=%d,group_id=%d,max_read=%zu," "allow_other,rootmode=040000"), fd.ffd, fd.uid, fd.gid, block_size); result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts); if (result < 0) { perror("mount"); goto done; } uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; for (;;) { ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer)); if (len < 0) { if (errno != EINTR) { perror("read request"); if (errno == ENODEV) { result = -1; break; } } continue; } if ((size_t)len < sizeof(struct fuse_in_header)) { fprintf(stderr, "request too short: len=%zu\n", (size_t)len); continue; } struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer; void* data = request_buffer + sizeof(struct fuse_in_header); result = -ENOSYS; switch (hdr->opcode) { case FUSE_INIT: result = handle_init(data, &fd, hdr); break; case FUSE_LOOKUP: result = handle_lookup(data, &fd, hdr); break; case FUSE_GETATTR: result = handle_getattr(data, &fd, hdr); break; case FUSE_OPEN: result = handle_open(data, &fd, hdr); break; case FUSE_READ: result = handle_read(data, &fd, hdr); break; case FUSE_FLUSH: result = handle_flush(data, &fd, hdr); break; case FUSE_RELEASE: result = handle_release(data, &fd, hdr); break; default: fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode); break; } if (result == NO_STATUS_EXIT) { result = 0; break; } if (result != NO_STATUS) { struct fuse_out_header outhdr; outhdr.len = sizeof(outhdr); outhdr.error = result; outhdr.unique = hdr->unique; write(fd.ffd, &outhdr, sizeof(outhdr)); } } done: fd.vtab->close(fd.cookie); result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH); if (result < 0) { printf("fuse_sideload umount failed: %s\n", strerror(errno)); } if (fd.ffd) close(fd.ffd); free(fd.hashes); free(fd.block_data); free(fd.extra_block); return result; }
static int state_scrub_process(struct snapraid_state* state, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax, struct snapraid_plan* plan, time_t now) { struct snapraid_handle* handle; void* rehandle_alloc; struct snapraid_rehash* rehandle; unsigned diskmax; block_off_t i; unsigned j; void* buffer_alloc; void** buffer; unsigned buffermax; data_off_t countsize; block_off_t countpos; block_off_t countmax; block_off_t autosavedone; block_off_t autosavelimit; block_off_t autosavemissing; int ret; unsigned error; unsigned silent_error; unsigned io_error; unsigned l; /* maps the disks to handles */ handle = handle_map(state, &diskmax); /* rehash buffers */ rehandle = malloc_nofail_align(diskmax * sizeof(struct snapraid_rehash), &rehandle_alloc); /* we need disk + 2 for each parity level buffers */ buffermax = diskmax + state->level * 2; buffer = malloc_nofail_vector_align(diskmax, buffermax, state->block_size, &buffer_alloc); if (!state->opt.skip_self) mtest_vector(buffermax, state->block_size, buffer); error = 0; silent_error = 0; io_error = 0; /* first count the number of blocks to process */ countmax = 0; plan->countlast = 0; for (i = blockstart; i < blockmax; ++i) { if (!block_is_enabled(state, i, plan)) continue; ++countmax; } /* compute the autosave size for all disk, even if not read */ /* this makes sense because the speed should be almost the same */ /* if the disks are read in parallel */ autosavelimit = state->autosave / (diskmax * state->block_size); autosavemissing = countmax; /* blocks to do */ autosavedone = 0; /* blocks done */ /* drop until now */ state_usage_waste(state); countsize = 0; countpos = 0; plan->countlast = 0; state_progress_begin(state, blockstart, blockmax, countmax); for (i = blockstart; i < blockmax; ++i) { snapraid_info info; int error_on_this_block; int silent_error_on_this_block; int io_error_on_this_block; int block_is_unsynced; int rehash; if (!block_is_enabled(state, i, plan)) continue; /* one more block processed for autosave */ ++autosavedone; --autosavemissing; /* by default process the block, and skip it if something goes wrong */ error_on_this_block = 0; silent_error_on_this_block = 0; io_error_on_this_block = 0; /* if all the blocks at this address are synced */ /* if not, parity is not even checked */ block_is_unsynced = 0; /* get block specific info */ info = info_get(&state->infoarr, i); /* if we have to use the old hash */ rehash = info_get_rehash(info); /* for each disk, process the block */ for (j = 0; j < diskmax; ++j) { int read_size; unsigned char hash[HASH_SIZE]; struct snapraid_block* block; int file_is_unsynced; struct snapraid_disk* disk = handle[j].disk; struct snapraid_file* file; block_off_t file_pos; /* if the file on this disk is synced */ /* if not, silent errors are assumed as expected error */ file_is_unsynced = 0; /* by default no rehash in case of "continue" */ rehandle[j].block = 0; /* if the disk position is not used */ if (!disk) { /* use an empty block */ memset(buffer[j], 0, state->block_size); continue; } /* if the block is not used */ block = fs_par2block_get(disk, i); if (!block_has_file(block)) { /* use an empty block */ memset(buffer[j], 0, state->block_size); continue; } /* get the file of this block */ file = fs_par2file_get(disk, i, &file_pos); /* if the block is unsynced, errors are expected */ if (block_has_invalid_parity(block)) { /* report that the block and the file are not synced */ block_is_unsynced = 1; file_is_unsynced = 1; /* follow */ } /* until now is CPU */ state_usage_cpu(state); /* if the file is different than the current one, close it */ if (handle[j].file != 0 && handle[j].file != file) { /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* report = handle[j].file; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ if (errno == EIO) { log_tag("error:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc(report->sub), strerror(errno)); log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); log_fatal("Stopping at block %u\n", i); ++io_error; goto bail; } log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(report->sub), strerror(errno)); log_fatal("WARNING! Unexpected close error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path); log_fatal("Stopping at block %u\n", i); ++error; goto bail; /* LCOV_EXCL_STOP */ } } ret = handle_open(&handle[j], file, state->file_mode, log_error, 0); if (ret == -1) { if (errno == EIO) { /* LCOV_EXCL_START */ log_tag("error:%u:%s:%s: Open EIO error. %s\n", i, disk->name, esc(file->sub), strerror(errno)); log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); log_fatal("Stopping at block %u\n", i); ++io_error; goto bail; /* LCOV_EXCL_STOP */ } log_tag("error:%u:%s:%s: Open error. %s\n", i, disk->name, esc(file->sub), strerror(errno)); ++error; error_on_this_block = 1; continue; } /* check if the file is changed */ if (handle[j].st.st_size != file->size || handle[j].st.st_mtime != file->mtime_sec || STAT_NSEC(&handle[j].st) != file->mtime_nsec /* don't check the inode to support filesystem without persistent inodes */ ) { /* report that the block and the file are not synced */ block_is_unsynced = 1; file_is_unsynced = 1; /* follow */ } /* note that we intentionally don't abort if the file has different attributes */ /* from the last sync, as we are expected to return errors if running */ /* in an unsynced array. This is just like the check command. */ read_size = handle_read(&handle[j], file_pos, buffer[j], state->block_size, log_error, 0); if (read_size == -1) { if (errno == EIO) { log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, esc(file->sub), file_pos, strerror(errno)); if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ log_fatal("DANGER! Too many input/output read error in a data disk, it isn't possible to scrub.\n"); log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); log_fatal("Stopping at block %u\n", i); ++io_error; goto bail; /* LCOV_EXCL_STOP */ } log_error("Input/Output error in file '%s' at position '%u'\n", handle[j].path, file_pos); ++io_error; io_error_on_this_block = 1; continue; } log_tag("error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, esc(file->sub), file_pos, strerror(errno)); ++error; error_on_this_block = 1; continue; } /* until now is disk */ state_usage_disk(state, disk); countsize += read_size; /* now compute the hash */ if (rehash) { memhash(state->prevhash, state->prevhashseed, hash, buffer[j], read_size); /* compute the new hash, and store it */ rehandle[j].block = block; memhash(state->hash, state->hashseed, rehandle[j].hash, buffer[j], read_size); } else { memhash(state->hash, state->hashseed, hash, buffer[j], read_size); } if (block_has_updated_hash(block)) { /* compare the hash */ if (memcmp(hash, block->hash, HASH_SIZE) != 0) { unsigned diff = memdiff(hash, block->hash, HASH_SIZE); log_tag("error:%u:%s:%s: Data error at position %u, diff bits %u\n", i, disk->name, esc(file->sub), file_pos, diff); /* it's a silent error only if we are dealing with synced files */ if (file_is_unsynced) { ++error; error_on_this_block = 1; } else { log_error("Data error in file '%s' at position '%u', diff bits %u\n", handle[j].path, file_pos, diff); ++silent_error; silent_error_on_this_block = 1; } continue; } } } /* if we have read all the data required and it's correct, proceed with the parity check */ if (!error_on_this_block && !silent_error_on_this_block && !io_error_on_this_block) { unsigned char* buffer_recov[LEV_MAX]; /* until now is CPU */ state_usage_cpu(state); /* buffers for parity read and not computed */ for (l = 0; l < state->level; ++l) buffer_recov[l] = buffer[diskmax + state->level + l]; for (; l < LEV_MAX; ++l) buffer_recov[l] = 0; /* read the parity */ for (l = 0; l < state->level; ++l) { ret = parity_read(parity[l], i, buffer_recov[l], state->block_size, log_error); if (ret == -1) { buffer_recov[l] = 0; if (errno == EIO) { log_tag("parity_error:%u:%s: Read EIO error. %s\n", i, lev_config_name(l), strerror(errno)); if (io_error >= state->opt.io_error_limit) { /* LCOV_EXCL_START */ log_fatal("DANGER! Too many input/output read error in the %s disk, it isn't possible to scrub.\n", lev_name(l)); log_fatal("Ensure that disk '%s' is sane and can be read.\n", lev_config_name(l)); log_fatal("Stopping at block %u\n", i); ++io_error; goto bail; /* LCOV_EXCL_STOP */ } log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(l), i); ++io_error; io_error_on_this_block = 1; continue; } log_tag("parity_error:%u:%s: Read error. %s\n", i, lev_config_name(l), strerror(errno)); ++error; error_on_this_block = 1; continue; } /* until now is parity */ state_usage_parity(state, l); } /* compute the parity */ raid_gen(diskmax, state->level, state->block_size, buffer); /* compare the parity */ for (l = 0; l < state->level; ++l) { if (buffer_recov[l] && memcmp(buffer[diskmax + l], buffer_recov[l], state->block_size) != 0) { unsigned diff = memdiff(buffer[diskmax + l], buffer_recov[l], state->block_size); log_tag("parity_error:%u:%s: Data error, diff bits %u\n", i, lev_config_name(l), diff); /* it's a silent error only if we are dealing with synced blocks */ if (block_is_unsynced) { ++error; error_on_this_block = 1; } else { log_fatal("Data error in parity '%s' at position '%u', diff bits %u\n", lev_config_name(l), i, diff); ++silent_error; silent_error_on_this_block = 1; } } } } if (silent_error_on_this_block || io_error_on_this_block) { /* set the error status keeping other info */ info_set(&state->infoarr, i, info_set_bad(info)); } else if (error_on_this_block) { /* do nothing, as this is a generic error */ /* likely caused by a not synced array */ } else { /* if rehash is needed */ if (rehash) { /* store all the new hash already computed */ for (j = 0; j < diskmax; ++j) { if (rehandle[j].block) memcpy(rehandle[j].block->hash, rehandle[j].hash, HASH_SIZE); } } /* update the time info of the block */ /* and clear any other flag */ info_set(&state->infoarr, i, info_make(now, 0, 0, 0)); } /* mark the state as needing write */ state->need_write = 1; /* count the number of processed block */ ++countpos; /* progress */ if (state_progress(state, i, countpos, countmax, countsize)) { /* LCOV_EXCL_START */ break; /* LCOV_EXCL_STOP */ } /* autosave */ if (state->autosave != 0 && autosavedone >= autosavelimit /* if we have reached the limit */ && autosavemissing >= autosavelimit /* if we have at least a full step to do */ ) { autosavedone = 0; /* restart the counter */ /* until now is CPU */ state_usage_cpu(state); state_progress_stop(state); msg_progress("Autosaving...\n"); state_write(state); state_progress_restart(state); /* drop until now */ state_usage_waste(state); } } state_progress_end(state, countpos, countmax, countsize); state_usage_print(state); if (error || silent_error || io_error) { msg_status("\n"); msg_status("%8u file errors\n", error); msg_status("%8u io errors\n", io_error); msg_status("%8u data errors\n", silent_error); } else { /* print the result only if processed something */ if (countpos != 0) msg_status("Everything OK\n"); } if (error) log_fatal("WARNING! Unexpected file errors!\n"); if (io_error) log_fatal("DANGER! Unexpected input/output errors! The failing blocks are now marked as bad!\n"); if (silent_error) log_fatal("DANGER! Unexpected data errors! The failing blocks are now marked as bad!\n"); if (io_error || silent_error) { log_fatal("Use 'snapraid status' to list the bad blocks.\n"); log_fatal("Use 'snapraid -e fix' to recover.\n"); } log_tag("summary:error_file:%u\n", error); log_tag("summary:error_io:%u\n", io_error); log_tag("summary:error_data:%u\n", silent_error); if (error + silent_error + io_error == 0) log_tag("summary:exit:ok\n"); else log_tag("summary:exit:error\n"); log_flush(); bail: for (j = 0; j < diskmax; ++j) { struct snapraid_file* file = handle[j].file; struct snapraid_disk* disk = handle[j].disk; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(file->sub), strerror(errno)); log_fatal("DANGER! Unexpected close error in a data disk.\n"); ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ } } free(handle); free(buffer_alloc); free(buffer); free(rehandle_alloc); if (state->opt.expect_recoverable) { if (error + silent_error + io_error == 0) return -1; } else { if (error + silent_error + io_error != 0) return -1; } return 0; }
static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler, const struct fuse_in_header *hdr, const void *data, size_t data_len) { switch (hdr->opcode) { case FUSE_LOOKUP: { /* bytez[] -> entry_out */ const char* name = data; return handle_lookup(fuse, handler, hdr, name); } case FUSE_FORGET: { const struct fuse_forget_in *req = data; return handle_forget(fuse, handler, hdr, req); } case FUSE_GETATTR: { /* getattr_in -> attr_out */ const struct fuse_getattr_in *req = data; return handle_getattr(fuse, handler, hdr, req); } case FUSE_SETATTR: { /* setattr_in -> attr_out */ const struct fuse_setattr_in *req = data; return handle_setattr(fuse, handler, hdr, req); } // case FUSE_READLINK: // case FUSE_SYMLINK: case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */ const struct fuse_mknod_in *req = data; const char *name = ((const char*) data) + sizeof(*req); return handle_mknod(fuse, handler, hdr, req, name); } case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */ const struct fuse_mkdir_in *req = data; const char *name = ((const char*) data) + sizeof(*req); return handle_mkdir(fuse, handler, hdr, req, name); } case FUSE_UNLINK: { /* bytez[] -> */ const char* name = data; return handle_unlink(fuse, handler, hdr, name); } case FUSE_RMDIR: { /* bytez[] -> */ const char* name = data; return handle_rmdir(fuse, handler, hdr, name); } case FUSE_RENAME: { /* rename_in, oldname, newname -> */ const struct fuse_rename_in *req = data; const char *old_name = ((const char*) data) + sizeof(*req); const char *new_name = old_name + strlen(old_name) + 1; return handle_rename(fuse, handler, hdr, req, old_name, new_name); } // case FUSE_LINK: case FUSE_OPEN: { /* open_in -> open_out */ const struct fuse_open_in *req = data; return handle_open(fuse, handler, hdr, req); } case FUSE_READ: { /* read_in -> byte[] */ const struct fuse_read_in *req = data; return handle_read(fuse, handler, hdr, req); } case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */ const struct fuse_write_in *req = data; const void* buffer = (const __u8*)data + sizeof(*req); return handle_write(fuse, handler, hdr, req, buffer); } case FUSE_STATFS: { /* getattr_in -> attr_out */ return handle_statfs(fuse, handler, hdr); } case FUSE_RELEASE: { /* release_in -> */ const struct fuse_release_in *req = data; return handle_release(fuse, handler, hdr, req); } case FUSE_FSYNC: { const struct fuse_fsync_in *req = data; return handle_fsync(fuse, handler, hdr, req); } // case FUSE_SETXATTR: // case FUSE_GETXATTR: // case FUSE_LISTXATTR: // case FUSE_REMOVEXATTR: case FUSE_FLUSH: { return handle_flush(fuse, handler, hdr); } case FUSE_OPENDIR: { /* open_in -> open_out */ const struct fuse_open_in *req = data; return handle_opendir(fuse, handler, hdr, req); } case FUSE_READDIR: { const struct fuse_read_in *req = data; return handle_readdir(fuse, handler, hdr, req); } case FUSE_RELEASEDIR: { /* release_in -> */ const struct fuse_release_in *req = data; return handle_releasedir(fuse, handler, hdr, req); } // case FUSE_FSYNCDIR: case FUSE_INIT: { /* init_in -> init_out */ const struct fuse_init_in *req = data; return handle_init(fuse, handler, hdr, req); } default: { TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n", handler->token, hdr->opcode, hdr->unique, hdr->nodeid); return -ENOSYS; } } }
/* * System call handler * * retrieves system call number from user space * and invokes the requested method */ static void syscall_handler (struct intr_frame *f) { /* retrieve system call number and switch to corresponding method */ unsigned int syscall_number = *((unsigned int*) syscall_get_kernel_address(f->esp)); switch(syscall_number) { /* process system calls */ case SYS_HALT: handle_halt(f); break; case SYS_EXIT: handle_exit(f); break; case SYS_EXEC: handle_exec(f); break; case SYS_WAIT: handle_wait(f); break; /* file system calls */ case SYS_CREATE: handle_create(f); break; case SYS_REMOVE: handle_remove(f); break; case SYS_OPEN: handle_open(f); break; case SYS_FILESIZE: handle_filesize(f); break; case SYS_READ: handle_read(f); break; case SYS_WRITE: handle_write(f); break; case SYS_SEEK: handle_seek(f); break; case SYS_TELL: handle_tell(f); break; case SYS_CLOSE: handle_close(f); break; case SYS_CHDIR: handle_chdir(f); break; case SYS_MKDIR: handle_mkdir(f); break; case SYS_READDIR: handle_readdir(f); break; case SYS_ISDIR: handle_isdir(f); break; case SYS_INUMBER: handle_inumber(f); break; default: /* SYSCALL_ERROR: */ handle_no_such_syscall(f); break; } }
static int state_dry_process(struct snapraid_state* state, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax) { struct snapraid_handle* handle; unsigned diskmax; block_off_t i; unsigned j; void* buffer_alloc; unsigned char* buffer_aligned; int ret; data_off_t countsize; block_off_t countpos; block_off_t countmax; unsigned error; unsigned l; handle = handle_map(state, &diskmax); buffer_aligned = malloc_nofail_align(state->block_size, &buffer_alloc); error = 0; /* drop until now */ state_usage_waste(state); countmax = blockmax - blockstart; countsize = 0; countpos = 0; state_progress_begin(state, blockstart, blockmax, countmax); for (i = blockstart; i < blockmax; ++i) { /* for each disk, process the block */ for (j = 0; j < diskmax; ++j) { int read_size; struct snapraid_block* block = BLOCK_EMPTY; struct snapraid_disk* disk = handle[j].disk; if (!disk) { /* if no disk, nothing to do */ continue; } block = disk_block_get(disk, i); if (!block_has_file(block)) { /* if no file, nothing to do */ continue; } /* until now is CPU */ state_usage_cpu(state); /* if the file is closed or different than the current one */ if (handle[j].file == 0 || handle[j].file != block_file_get(block)) { struct snapraid_file* file = handle[j].file; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ msg_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(file->sub), strerror(errno)); msg_error("DANGER! Unexpected close error in a data disk, it isn't possible to dry.\n"); msg_error("Stopping at block %u\n", i); ++error; goto bail; /* LCOV_EXCL_STOP */ } /* open the file only for reading */ ret = handle_open(&handle[j], block_file_get(block), state->file_mode, msg_error); if (ret == -1) { /* LCOV_EXCL_START */ msg_error("DANGER! Unexpected open error in a data disk, it isn't possible to dry.\n"); msg_error("Stopping at block %u\n", i); ++error; goto bail; /* LCOV_EXCL_STOP */ } } /* read from the file */ read_size = handle_read(&handle[j], block, buffer_aligned, state->block_size, msg_warning); if (read_size == -1) { msg_tag("error:%u:%s:%s: Read error at position %u\n", i, disk->name, esc(block_file_get(block)->sub), block_file_pos(block)); ++error; continue; } /* until now is disk */ state_usage_disk(state, disk); countsize += read_size; } /* read the parity */ for (l = 0; l < state->level; ++l) { if (parity[l]) { /* until now is CPU */ state_usage_cpu(state); ret = parity_read(parity[l], i, buffer_aligned, state->block_size, msg_warning); if (ret == -1) { msg_tag("parity_error:%u:%s: Read error\n", i, lev_config_name(l)); ++error; } /* until now is parity */ state_usage_parity(state, l); } } /* count the number of processed block */ ++countpos; /* progress */ if (state_progress(state, i, countpos, countmax, countsize)) { /* LCOV_EXCL_START */ break; /* LCOV_EXCL_STOP */ } } state_progress_end(state, countpos, countmax, countsize); state_usage_print(state); bail: /* close all the files left open */ for (j = 0; j < diskmax; ++j) { struct snapraid_file* file = handle[j].file; struct snapraid_disk* disk = handle[j].disk; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ msg_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc(file->sub), strerror(errno)); msg_error("DANGER! Unexpected close error in a data disk.\n"); ++error; /* continue, as we are already exiting */ /* LCOV_EXCL_STOP */ } } if (error) { msg_status("\n"); msg_status("%8u errors\n", error); } else { msg_status("Everything OK\n"); } if (error) msg_error("DANGER! Unexpected errors!\n"); free(handle); free(buffer_alloc); if (error != 0) return -1; return 0; }