GLuint graphics_create_shader_from_file( GLenum shader_type, const char *filename) { FILE *file = fopen(filename, "rb"); error_on(!file, "create_shader '%s'", filename); error_on(fseek(file, 0, SEEK_END) < 0, "create_shader '%s'", filename); GLint size = ftell(file); error_on(size < 0, "create_shader '%s'", filename); rewind(file); char *data = malloc(size+1); data[size] = 0; error_on(fread(data, size, 1, file) < 1, "create_shader '%s'", filename); return graphics_create_shader(shader_type, filename, data); }
/* Scans the inname file and dumps on the outname file, by transliterating to Greek inside "greek regions", delimited by g_escape. */ void greml(char *inname, char *outname) { int c; g_in = fopen(inname, "r"); g_out = fopen(outname, "w"); error_on(g_in == NULL, "Cannot open file %s for reading", inname); error_on(g_out == NULL, "Cannot open file %s for writing", outname); g_line = 1; g_col = 1; g_name = inname; while ( (c = fget_char()) != EOF ) { ++ g_col; if ( c == '\n' ) { ++ g_line; g_col = 1; } if ( c != g_escape ) { fputc(c, g_out); } else { c = fget_char(); if ( c == g_escape ) { /* A repeated escape character dumps itself on the output file. */ fputc(g_escape, g_out); } else { ungetc(c, g_in); greml_transliterate(); } } } fclose(g_out); fclose(g_in); }
/* Translates the content of a greek region, until che end of file or the next escape character is found. */ void greml_transliterate(void) { int c, i; /* Resets diacritic flags. */ g_acute = 0; g_circumflex = 0; g_diaeresis = 0; g_grave = 0; g_iota = 0; g_rough = 0; g_smooth = 0; /* Scanning loop. */ while ( (c = fget_char()) != EOF && c != g_escape ) { int breathing = g_rough + g_smooth; int accent = g_acute + g_circumflex + g_grave; int other = g_diaeresis + g_iota; /* Check against diacritics coherence. */ error_on( breathing > 1, "Cannot mix different breathings: %s", print_diacritics(c)); error_on( accent > 1, "Cannot mix different accents: %s", print_diacritics(c)); error_on( breathing + accent + other > 3, "More than three diacritics together: %s", print_diacritics(c)); /* Take care of diacritics... */ if ( breathing + accent + other > 0 && isalpha(c) ) { /* Produces the bit string corresponding to diacritic flags. */ int flag = g_rough * ROUGH + g_smooth * SMOOTH + g_acute * ACUTE + g_grave * GRAVE + g_circumflex * CIRCUMFLEX + g_diaeresis * DIAERESIS + g_iota * IOTA; for ( i = 0; i < SIZE(DIACRITICS); ++ i ) { if ( DIACRITICS[i].c == c && DIACRITICS[i].diacritic == flag ) { fprintf(g_out, DIACRITICS[i].value); g_rough = g_smooth = g_acute = g_grave = g_circumflex = g_diaeresis = g_iota = 0; break; /* actually will continue the outer while loop. */ } } error_on(i == SIZE(DIACRITICS), "Invalid diacritic combination: %s", print_diacritics(c)); continue; /* the outer while loop. */ } /* Here there aren't diacritics, so any kind of character is expected. */ /* Check against an "alias characters". */ if ( c >= 0x20 && c < 0x80 && CHR_TRANS[c - 0x20] != NULL ) { fputs(CHR_TRANS[c - 0x20], g_out); continue; /* the outer while loop. */ } /* Check against an "executable character". */ for ( i = 0; i < SIZE(CHR_ACTION); ++ i ) { if ( CHR_ACTION[i].c == c ) { (*CHR_ACTION[i].fun)(); goto Continue; /* continue the outer while loop. */ } } /* Here c is a bare character to print! */ fputc(c, g_out); Continue: ; } }
static int cmd_device_scan(int argc, char **argv) { int i; int devstart; int all = 0; int ret = 0; optind = 0; while (1) { int c; static const struct option long_options[] = { { "all-devices", no_argument, NULL, 'd'}, { NULL, 0, NULL, 0} }; c = getopt_long(argc, argv, "d", long_options, NULL); if (c < 0) break; switch (c) { case 'd': all = 1; break; default: usage(cmd_device_scan_usage); } } devstart = optind; if (all && check_argc_max(argc - optind, 1)) usage(cmd_device_scan_usage); if (all || argc - optind == 0) { printf("Scanning for Btrfs filesystems\n"); ret = btrfs_scan_devices(); error_on(ret, "error %d while scanning", ret); ret = btrfs_register_all_devices(); error_on(ret, "there are %d errors while registering devices", ret); goto out; } for( i = devstart ; i < argc ; i++ ){ char *path; if (is_block_device(argv[i]) != 1) { error("not a block device: %s", argv[i]); ret = 1; goto out; } path = canonicalize_path(argv[i]); if (!path) { error("could not canonicalize path '%s': %m", argv[i]); ret = 1; goto out; } printf("Scanning for Btrfs filesystems in '%s'\n", path); if (btrfs_register_one_device(path) != 0) { ret = 1; free(path); goto out; } free(path); } out: return !!ret; }
static int scrub_start(int argc, char **argv, int resume) { int fdmnt; int prg_fd = -1; int fdres = -1; int ret; pid_t pid; int c; int i; int err = 0; int e_uncorrectable = 0; int e_correctable = 0; int print_raw = 0; char *path; int do_background = 1; int do_wait = 0; int do_print = 0; int do_quiet = 0; int do_record = 1; int readonly = 0; int do_stats_per_dev = 0; int ioprio_class = IOPRIO_CLASS_IDLE; int ioprio_classdata = 0; int n_start = 0; int n_skip = 0; int n_resume = 0; struct btrfs_ioctl_fs_info_args fi_args; struct btrfs_ioctl_dev_info_args *di_args = NULL; struct scrub_progress *sp = NULL; struct scrub_fs_stat fs_stat; struct timeval tv; struct sockaddr_un addr = { .sun_family = AF_UNIX, }; pthread_t *t_devs = NULL; pthread_t t_prog; struct scrub_file_record **past_scrubs = NULL; struct scrub_file_record *last_scrub = NULL; char *datafile = strdup(SCRUB_DATA_FILE); char fsid[BTRFS_UUID_UNPARSED_SIZE]; char sock_path[PATH_MAX] = ""; struct scrub_progress_cycle spc; pthread_mutex_t spc_write_mutex = PTHREAD_MUTEX_INITIALIZER; void *terr; u64 devid; DIR *dirstream = NULL; int force = 0; int nothing_to_resume = 0; while ((c = getopt(argc, argv, "BdqrRc:n:f")) != -1) { switch (c) { case 'B': do_background = 0; do_wait = 1; do_print = 1; break; case 'd': do_stats_per_dev = 1; break; case 'q': do_quiet = 1; break; case 'r': readonly = 1; break; case 'R': print_raw = 1; break; case 'c': ioprio_class = (int)strtol(optarg, NULL, 10); break; case 'n': ioprio_classdata = (int)strtol(optarg, NULL, 10); break; case 'f': force = 1; break; case '?': default: usage(resume ? cmd_scrub_resume_usage : cmd_scrub_start_usage); } } /* try to catch most error cases before forking */ if (check_argc_exact(argc - optind, 1)) { usage(resume ? cmd_scrub_resume_usage : cmd_scrub_start_usage); } spc.progress = NULL; if (do_quiet && do_print) do_print = 0; if (mkdir_p(datafile)) { warning_on(!do_quiet, "cannot create scrub data file, mkdir %s failed: %s. Status recording disabled", datafile, strerror(errno)); do_record = 0; } free(datafile); path = argv[optind]; fdmnt = open_path_or_dev_mnt(path, &dirstream, !do_quiet); if (fdmnt < 0) return 1; ret = get_fs_info(path, &fi_args, &di_args); if (ret) { error_on(!do_quiet, "getting dev info for scrub failed: %s", strerror(-ret)); err = 1; goto out; } if (!fi_args.num_devices) { error_on(!do_quiet, "no devices found"); err = 1; goto out; } uuid_unparse(fi_args.fsid, fsid); fdres = scrub_open_file_r(SCRUB_DATA_FILE, fsid); if (fdres < 0 && fdres != -ENOENT) { warning_on(!do_quiet, "failed to open status file: %s", strerror(-fdres)); } else if (fdres >= 0) { past_scrubs = scrub_read_file(fdres, !do_quiet); if (IS_ERR(past_scrubs)) warning_on(!do_quiet, "failed to read status file: %s", strerror(-PTR_ERR(past_scrubs))); close(fdres); } /* * Check for stale information in the status file, ie. if it's * canceled=0, finished=0 but no scrub is running. */ if (!is_scrub_running_in_kernel(fdmnt, di_args, fi_args.num_devices)) force = 1; /* * check whether any involved device is already busy running a * scrub. This would cause damaged status messages and the state * "aborted" without the explanation that a scrub was already * running. Therefore check it first, prevent it and give some * feedback to the user if scrub is already running. * Note that if scrub is started with a block device as the * parameter, only that particular block device is checked. It * is a normal mode of operation to start scrub on multiple * single devices, there is no reason to prevent this. */ if (!force && is_scrub_running_on_fs(&fi_args, di_args, past_scrubs)) { error_on(!do_quiet, "Scrub is already running.\n" "To cancel use 'btrfs scrub cancel %s'.\n" "To see the status use 'btrfs scrub status [-d] %s'", path, path); err = 1; goto out; } t_devs = malloc(fi_args.num_devices * sizeof(*t_devs)); sp = calloc(fi_args.num_devices, sizeof(*sp)); spc.progress = calloc(fi_args.num_devices * 2, sizeof(*spc.progress)); if (!t_devs || !sp || !spc.progress) { error_on(!do_quiet, "scrub failed: %s", strerror(errno)); err = 1; goto out; } for (i = 0; i < fi_args.num_devices; ++i) { devid = di_args[i].devid; ret = pthread_mutex_init(&sp[i].progress_mutex, NULL); if (ret) { error_on(!do_quiet, "pthread_mutex_init failed: %s", strerror(ret)); err = 1; goto out; } last_scrub = last_dev_scrub(past_scrubs, devid); sp[i].scrub_args.devid = devid; sp[i].fd = fdmnt; if (resume && last_scrub && (last_scrub->stats.canceled || !last_scrub->stats.finished)) { ++n_resume; sp[i].scrub_args.start = last_scrub->p.last_physical; sp[i].resumed = last_scrub; } else if (resume) { ++n_skip; sp[i].skip = 1; sp[i].resumed = last_scrub; continue; } else { ++n_start; sp[i].scrub_args.start = 0ll; sp[i].resumed = NULL; } sp[i].skip = 0; sp[i].scrub_args.end = (u64)-1ll; sp[i].scrub_args.flags = readonly ? BTRFS_SCRUB_READONLY : 0; sp[i].ioprio_class = ioprio_class; sp[i].ioprio_classdata = ioprio_classdata; } if (!n_start && !n_resume) { if (!do_quiet) printf("scrub: nothing to resume for %s, fsid %s\n", path, fsid); nothing_to_resume = 1; goto out; } ret = prg_fd = socket(AF_UNIX, SOCK_STREAM, 0); while (ret != -1) { ret = scrub_datafile(SCRUB_PROGRESS_SOCKET_PATH, fsid, NULL, sock_path, sizeof(sock_path)); /* ignore EOVERFLOW, try using a shorter path for the socket */ addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1); ret = bind(prg_fd, (struct sockaddr *)&addr, sizeof(addr)); if (ret != -1 || errno != EADDRINUSE) break; /* * bind failed with EADDRINUSE. so let's see if anyone answers * when we make a call to the socket ... */ ret = connect(prg_fd, (struct sockaddr *)&addr, sizeof(addr)); if (!ret || errno != ECONNREFUSED) { /* ... yes, so scrub must be running. error out */ error("scrub already running"); close(prg_fd); prg_fd = -1; goto out; } /* * ... no, this means someone left us alone with an unused * socket in the file system. remove it and try again. */ ret = unlink(sock_path); } if (ret != -1) ret = listen(prg_fd, 100); if (ret == -1) { warning_on(!do_quiet, "failed to open the progress status socket at %s: %s. Progress cannot be queried", sock_path[0] ? sock_path : SCRUB_PROGRESS_SOCKET_PATH, strerror(errno)); if (prg_fd != -1) { close(prg_fd); prg_fd = -1; if (sock_path[0]) unlink(sock_path); } } if (do_record) { /* write all-zero progress file for a start */ ret = scrub_write_progress(&spc_write_mutex, fsid, sp, fi_args.num_devices); if (ret) { warning_on(!do_quiet, "failed to write the progress status file: %s. Status recording disabled", strerror(-ret)); do_record = 0; } } if (do_background) { pid = fork(); if (pid == -1) { error_on(!do_quiet, "cannot scrub, fork failed: %s", strerror(errno)); err = 1; goto out; } if (pid) { int stat; scrub_handle_sigint_parent(); if (!do_quiet) printf("scrub %s on %s, fsid %s (pid=%d)\n", n_start ? "started" : "resumed", path, fsid, pid); if (!do_wait) { err = 0; goto out; } ret = wait(&stat); if (ret != pid) { error_on(!do_quiet, "wait failed (ret=%d): %s", ret, strerror(errno)); err = 1; goto out; } if (!WIFEXITED(stat) || WEXITSTATUS(stat)) { error_on(!do_quiet, "scrub process failed"); err = WIFEXITED(stat) ? WEXITSTATUS(stat) : -1; goto out; } err = 0; goto out; } } scrub_handle_sigint_child(fdmnt); for (i = 0; i < fi_args.num_devices; ++i) { if (sp[i].skip) { sp[i].scrub_args.progress = sp[i].resumed->p; sp[i].stats = sp[i].resumed->stats; sp[i].ret = 0; sp[i].stats.finished = 1; continue; } devid = di_args[i].devid; gettimeofday(&tv, NULL); sp[i].stats.t_start = tv.tv_sec; ret = pthread_create(&t_devs[i], NULL, scrub_one_dev, &sp[i]); if (ret) { if (do_print) error("creating scrub_one_dev[%llu] thread failed: %s", devid, strerror(ret)); err = 1; goto out; } } spc.fdmnt = fdmnt; spc.prg_fd = prg_fd; spc.do_record = do_record; spc.write_mutex = &spc_write_mutex; spc.shared_progress = sp; spc.fi = &fi_args; ret = pthread_create(&t_prog, NULL, scrub_progress_cycle, &spc); if (ret) { if (do_print) error("creating progress thread failed: %s", strerror(ret)); err = 1; goto out; } err = 0; for (i = 0; i < fi_args.num_devices; ++i) { if (sp[i].skip) continue; devid = di_args[i].devid; ret = pthread_join(t_devs[i], NULL); if (ret) { if (do_print) error("pthread_join failed for scrub_one_dev[%llu]: %s", devid, strerror(ret)); ++err; continue; } if (sp[i].ret) { switch (sp[i].ioctl_errno) { case ENODEV: if (do_print) warning("device %lld not present", devid); continue; case ECANCELED: ++err; break; default: if (do_print) error("scrubbing %s failed for device id %lld: ret=%d, errno=%d (%s)", path, devid, sp[i].ret, sp[i].ioctl_errno, strerror(sp[i].ioctl_errno)); ++err; continue; } } if (sp[i].scrub_args.progress.uncorrectable_errors > 0) e_uncorrectable++; if (sp[i].scrub_args.progress.corrected_errors > 0 || sp[i].scrub_args.progress.unverified_errors > 0) e_correctable++; } if (do_print) { const char *append = "done"; if (!do_stats_per_dev) init_fs_stat(&fs_stat); for (i = 0; i < fi_args.num_devices; ++i) { if (do_stats_per_dev) { print_scrub_dev(&di_args[i], &sp[i].scrub_args.progress, print_raw, sp[i].ret ? "canceled" : "done", &sp[i].stats); } else { if (sp[i].ret) append = "canceled"; add_to_fs_stat(&sp[i].scrub_args.progress, &sp[i].stats, &fs_stat); } } if (!do_stats_per_dev) { printf("scrub %s for %s\n", append, fsid); print_fs_stat(&fs_stat, print_raw); } } ret = pthread_cancel(t_prog); if (!ret) ret = pthread_join(t_prog, &terr); /* check for errors from the handling of the progress thread */ if (do_print && ret) { error("progress thread handling failed: %s", strerror(ret)); } /* check for errors returned from the progress thread itself */ if (do_print && terr && terr != PTHREAD_CANCELED) error("recording progress failed: %s", strerror(-PTR_ERR(terr))); if (do_record) { ret = scrub_write_progress(&spc_write_mutex, fsid, sp, fi_args.num_devices); if (ret && do_print) error("failed to record the result: %s", strerror(-ret)); } scrub_handle_sigint_child(-1); out: free_history(past_scrubs); free(di_args); free(t_devs); free(sp); free(spc.progress); if (prg_fd > -1) { close(prg_fd); if (sock_path[0]) unlink(sock_path); } close_file_or_dir(fdmnt, dirstream); if (err) return 1; if (nothing_to_resume) return 2; if (e_uncorrectable) { error_on(!do_quiet, "there are uncorrectable errors"); return 3; } if (e_correctable) warning_on(!do_quiet, "errors detected during scrubbing, corrected"); return 0; }