int listen_port(char *ipaddr, int port) { int fd __attribute__((cleanup(close_fd_))) = -1, sock = -1; int flags; struct sockaddr_in sin; fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd == -1) { say_error("can't create socket: %m"); return -1; } if ((flags = fcntl(fd, F_GETFL, 0) < 0) || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { say_error("can't move socket to non-blocking state: %m"); return -1; } sin.sin_family = AF_INET; sin.sin_port = htons(port); if (ipaddr == NULL || ipaddr[0] == '\0') sin.sin_addr.s_addr = INADDR_ANY; else if (inet_aton(ipaddr, &sin.sin_addr) == 0) { say_error("inet_aton `%s': %m", ipaddr); return -1; } if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) != 0) { say_error("can't bind to `%s:%d': %m", ipaddr, port); return -1; } if (listen(fd, 1) != 0) { say_error("can't listen on `%s:%d': %m", ipaddr, port); return -1; } say_info("listenning on '%s:%d'", ipaddr, port); sock = fd; fd = -1; return sock; }
void Thought_Bubble::remove_selected_element(Sprite *element, SelectionReason reason, Sprite *, boolean add_to_floor) { if (element != cubby) { #if TT_DEBUG say_error("Somehow a non-box is being removed from a thought bubble."); #endif // tt_error_file() << "Removing non-cubby from thought bubble!" << endl; return; }; if (reason == GRASPED || reason == VACUUM_USED) { // how can it be grasped??? remove_follower(cubby); if (add_to_floor) { floor->add_item(cubby); if (reason == GRASPED) { // city_coordinate saved_width, saved_height; // cubby->saved_size(saved_width,saved_height); // cubby->animate_size(saved_width,saved_height,1000); cubby->animate_to_good_size(1000,tt_log_version_number >= 64?tt_toolbox:NULL); }; }; cubby->set_cause_of_match_failure(FALSE,TRUE); // new on 260302 so that reset indication of what last failed to match tt_just_vacuumed = cubby; cubby = NULL; set_clean_status(DIRTY); }; };
void Floor::load(InputStream *stream, int notebook_version, NaturalLanguage language) { if (stream->get() != FLOOR_MARKER) { say_error(IDS_BAD_FLOOR_IN_CITY_FILE,TRUE); return; }; Sprites *floor_items = load_items(stream,notebook_version,language); if (floor_items != NULL) { // add_items(floor_items); Sprites *remaining = floor_items; while (remaining != NULL) { // new on 101099 if priority of item is fixed then don't reset it // so Marty, for example, loads in with correct priority add_item(remaining->first(),FALSE); // FALSE replaced !remaining->first()->priority_fixed() above on 211199 since priority is now saved correctly remaining = remaining->rest(); }; floor_items->recursively_propagate_changes(); floor_items->activate(); floor_items->remove_all(); delete floor_items; }; if (notebook_version >= first_version_to_save_number_colors) { stream->read((string) ¤t_priority, sizeof(current_priority)); // new on 150100 }; };
Status heapio__read_block (Inbuf* bp, void* blk, long len) { // ================== // Status status = SUCCESS; if (bp->nbytes == 0) { // if (bp->file != NULL) { status = read_block (bp->file, blk, len); } else { say_error( "missing data in pickle bytevector" ); return FAILURE; } } else if (bp->nbytes >= len) { // memcpy (blk, bp->buf, len); bp->nbytes -= len; bp->buf += len; // } else { // memcpy (blk, bp->buf, bp->nbytes); status = read_block (bp->file, ((Unt8 *)blk) + bp->nbytes, len - bp->nbytes); bp->nbytes = 0; } if (bp->needs_to_be_byteswapped) die ("byte-swapping not implemented yet"); return status; } // fun heapio__read_block
static int telnet_client_force_raw(int fd) { static const char iacs_to_send[] __attribute__((aligned(1))) = { IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS, IAC, DO, TELOPT_LFLOW, IAC, DO, TELOPT_EOR, IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA }; const char *snd_buf = iacs_to_send; char recv_buf[4096]; ssize_t r; size_t l; l = sizeof(iacs_to_send); while (true) { r = write(fd, snd_buf, l); if (r <= 0) { say_error("can't write to client: %m"); return -1; } if ((size_t)r == l) break; l -= r; snd_buf += r; } r = read(fd, recv_buf, sizeof(recv_buf)); if (r <= 0) { say_error("can't read from client: %m"); return -1; } return 0; }
static FILE* open_file ( // ========= // const char* filename, Bool is_binary ){ // Open a file in the .compiled file directory. FILE* file = fopen (filename, is_binary ? "rb" : "r"); if (!file) say_error( "Unable to open \"%s\"\n", filename ); return file; }
off_t fio_lseek(int fd, off_t offset, int whence) { off_t effective_offset = lseek(fd, offset, whence); if (effective_offset == -1) { say_syserror("lseek, [%s]: offset=%jd, whence=%d", fio_filename(fd), (intmax_t) offset, whence); } else if (whence == SEEK_SET && effective_offset != offset) { say_error("lseek, [%s]: offset set to unexpected value: " "requested %jd effective %jd", fio_filename(fd), (intmax_t)offset, (intmax_t)effective_offset); } return effective_offset; }
static Status read_block (FILE* file, void* blk, long len) { // ========== int status; Unt8* bp = (Unt8*) blk; while (len > 0) { // status = fread (bp, 1, len, file); len -= status; bp += status; // if ((status < len) && (ferror(file) || feof(file))) { // say_error( "Unable to read %d bytes from image.\n", len ); return FAILURE; } } return SUCCESS; }
void record_event(EventCode code, Sprite *by, Background *floor, Sprite *subject, boolean type_of_subject_fixed, int key, AddToWorkingSet add_to_working_set, boolean notebook_page_really_selected, int label_index #if TT_POST3187 ,Sprite *original_subject #endif ) { #if TT_DEBUG_ON if (tt_debug_mode == 5050) { tt_error_file() << timeGetTime() << " "; Event *event = new Event(code,NULL); event->debug(NULL); delete event; }; #endif // until I generate instructions programmer actions aren't recorded if (tt_log_version_number >= 22) { if (by == NULL || tt_recording_off || (by->kind_of() != ROBOT && by->kind_of() != ROBOT_IN_TRAINING) || tt_shutting_down) return; } else { if (by == NULL || tt_recording_off || by->kind_of() == PROGRAMMER || tt_shutting_down) return; }; // third condition prior to 050400 was by->kind_of() == PROGRAMMER but by might be a bird for example boolean body_cubby; if (by->kind_of() == ROBOT) { body_cubby = (subject == ((Robot *) by)->pointer_to_working_cubby()); } else if (floor != NULL || tt_log_version_number < 22) { // condition added 050400 body_cubby = (subject == floor->pointer_to_body_cubby()); } else { body_cubby = FALSE; }; // doesn't count that its main cubby if put somewhere // if (body_cubby) { // body_cubby = (subject->pointer_to_leader() == NULL || // subject->pointer_to_leader()->kind_of() == ROBOT_IN_TRAINING); // }; const boolean notebook = (tt_toolbox != NULL && subject == tt_toolbox_notebook); // following screws up if main cubby put into something and then taken out // also bad to have just 1 optimization like this // restored for notebook since it is shared and shouldn't be moved by robots if (code == RELEASE_ITEM && notebook) { // ((body_cubby && subject->pointer_to_leader() == NULL) || notebook)) { // could be more clever and if anything is released right // after being picked up it is ignored // picked up and released main cubby or notebook // (or vacuumed up and restored) // robot shouldn't be doing this so ok to assume floor if (tt_events != NULL) { Event *last_event = tt_events->last()->first(); if (last_event->event_code() == GRASP_ITEM || last_event->event_code() == VACUUM_APPLY) { // test new on 120305 since can be keyboard event, for example floor->remove_last_n_events(1); // must have been a grasp_item (or apply_vacuum) return; }; }; // else should be OK since there are no events to remove, right? }; if (code == RELEASE_ITEM_ON && by->kind_of() == ROBOT_IN_TRAINING) { if (subject->kind_of() == NEST && subject->infinite_stack()) { // returning a nest with egg back to stack but already // generated a hatch_bird message floor->remove_last_n_events(1); ((Robot *) by)->remove_last_working_set_item(); // taken care of by :now_part_of_somthing() // } else { // Happens in event.cpp so needs to happen here as well // ((Robot *) by)->remove_tool_from_working_set(subject); }; }; Path *path = NULL; Event *new_item_event = NULL; if (body_cubby || notebook) { add_to_working_set = DONT_ADD_TO_WORKING_SET; }; if (code == NEW_ITEM || code == HATCH_BIRD || code == RELEASE_ITEM || code == VACUUM_APPLY_RESTORE) { if (subject != NULL && !body_cubby && !(tt_toolbox != NULL && toolbox_tool(subject))) { // either defining a body so add to this // or by is a robot so add to its // or by is programmer so ignore switch (by->kind_of()) { case ROBOT_IN_TRAINING: // if (!by->still_running()) { if (add_to_working_set != DONT_ADD_TO_WORKING_SET) { int index = ((Robot *) by)->add_to_working_set(subject,(add_to_working_set == ADD_TO_WORKING_SET_IF_NEW)); if (type_of_subject_fixed) { path = new Path(index,new Path(subject->fine_kind_of())); } else if (code == VACUUM_APPLY_RESTORE) { path = new Path(index,new Path(NONE_GIVEN)); subject = NULL; }; // } else if (code == HATCH_BIRD) { // path = new Path(index,new Path(BIRD)); // } else { // path = new Path(index,new Path(NONE_GIVEN)); }; break; // }; // otherwise fall thru to the following case ROBOT: if (add_to_working_set != DONT_ADD_TO_WORKING_SET) { ((Robot *) by)->add_to_working_set(subject,(add_to_working_set == ADD_TO_WORKING_SET_IF_NEW)); }; break; }; // floor->add_to_some_working_set(subject,by); if (code != GRASP_ITEM && code != GRASP_NEST && code != VACUUM_APPLY_RESTORE && notebook_page_really_selected) { subject->set_available_for_indexing(TRUE); }; }; // following commented out so path is recorded for generating Java properly // if (code == VACUUM_APPLY_RESTORE) subject = NULL; if (path != NULL) { new_item_event = new Event(NEW_ITEM,path,0); if (code != VACUUM_APPLY_RESTORE) { if (tt_events == NULL) { tt_events = new Events(new_item_event,tt_events); } else { tt_events->insert_at_end(new_item_event); }; new_item_event = NULL; }; // else add it after this event }; // following just are used to update working set // can combine them to one?? except for descriptions? if (code == NEW_ITEM || code == HATCH_BIRD) return; }; if (by->kind_of() != ROBOT_IN_TRAINING) { if (code == NEW_MAIN_CUBBY) { floor->set_body_cubby((Cubby *) subject, by); }; return; // already knows the path }; if (subject != NULL && code == GRASP_ITEM) { if (subject->kind_of() == NEST) { code = GRASP_NEST; // the whole thing not the top of its stack } else if (tt_toolbox != NULL) { // used to do switch (subject->kind_of()) but copies of tools break if (subject == tt_toolbox_copier) { code = GRASP_COPIER; } else if (subject == tt_toolbox_vacuum) { code = GRASP_VACUUM; } else if (subject == tt_toolbox_expander) { code = GRASP_EXPANDER; } else if (subject == tt_toolbox) { return; // no semantic meaning }; } else { // e.g. puzzle game switch (subject->kind_of()) { case COPIER: code = GRASP_COPIER; break; case VACUUM: code = GRASP_VACUUM; break; case EXPANDER: code = GRASP_EXPANDER; break; }; }; }; if (subject != NULL && subject->kind_of() == NEST) { // don't wait for subject to receieve something to apply tool switch (code) { case COPIER_APPLY: code = COPIER_APPLY_NEST; break; case VACUUM_APPLY: code = VACUUM_APPLY_NEST; break; case APPLY_GRASPED_ITEM: code = APPLY_GRASPED_NEST; break; }; }; if (subject != NULL && code == RELEASE_ITEM) { subject->set_available_for_indexing(TRUE); // switch (subject->kind_of()) { if (tt_toolbox != NULL) { if (subject == tt_toolbox_copier) { code = RELEASE_COPIER; } else if (subject == tt_toolbox_vacuum) { code = RELEASE_VACUUM; } else if (subject == tt_toolbox_expander) { code = RELEASE_EXPANDER; } else if (subject == tt_toolbox) { // was subject == tt_toolbox_expander || return; }; } else { // puzzle game switch (subject->kind_of()) { case COPIER: code = RELEASE_COPIER; break; case VACUUM: code = RELEASE_VACUUM; break; case EXPANDER: code = RELEASE_EXPANDER; break; }; }; }; // safe cast? path = ((Floor *) floor)->compute_path(subject,code,(Robot *) by,notebook_page_really_selected #if TT_POST3187 ,original_subject #endif ); #if TT_CAREFUL if (path == NULL && subject != tt_toolbox) { // ignore actions on Toolbox... #if TT_DEBUG_ON #if TT_NEW_IO output_string_stream err_message; #else string buffer = new char[10000]; output_string_stream err_message(buffer,10000); #endif err_message << "Warning: Robot is confused and couldn't find "; subject->describe(err_message,INDEFINITE_ARTICLE); err_message << "."; err_message.put('\0'); say_error(err_message.STR,TRUE); #if !TT_NEW_IO delete [] buffer; #endif log(event_string(code)); #endif return; // working_set->insert_at_end_if_not_member(subject); // path = compute_path(subject); }; #endif // if (code == RELEASE_ITEM_ON && by->kind_of() == ROBOT_IN_TRAINING && // subject->kind_of() != PROGRAM_PAD && subject->is_container()) { // notebooks use this as well as cubbies //// && subject->pointer_to_leader() != NULL) { // // is now part of something and should be accessed via that container // ((Robot *) by)->remove_tool_from_working_set(subject); // }; //on 5/27 re-wrote the above to match the similar situation in event.cpp // handled by now_released_on // if (code == RELEASE_ITEM_ON && by->kind_of() == ROBOT_IN_TRAINING && // // except when dropping a cubby on a number since both are around afterwards // !(item_underneath != NULL && item_underneath->kind_of() == INTEGER && // subject->kind_of() == CUBBY)) { // ((Robot *) by)->remove_tool_from_working_set(subject); // }; if (code == LABEL_CHARACTER) { path->add_to_end(new Path(label_index)); }; if (code == NEW_MAIN_CUBBY) { // do this after computing the path floor->set_body_cubby((Cubby *) subject, by); }; if ((code == GRASP_ITEM || code == GRASP_NEST) && !notebook_page_really_selected) { subject->set_available_for_indexing(FALSE); // does this ever get restored?? }; Event *event = new Event(code,path,key); if (tt_events == NULL) { tt_events = new Events(event,tt_events); } else { tt_events->insert_at_end(event); }; if (new_item_event != NULL) { tt_events->insert_at_end(new_item_event); }; if (by->kind_of() == ROBOT_IN_TRAINING && code != SELECT_STACK_ITEM) { if (subject != ((Robot *) by)->pointer_to_initial_tool()) { ((Robot *) by)->decrement_training_counter(); }; }; };
Heapcleaner_Args* handle_cleaner_commandline_arguments (char **argv) { // ==================================== // // Parse any heapcleaner args from the user commandline: char option[ MAX_COMMANDLINE_ARGUMENT_PART_LENGTH ]; char* option_arg; Bool seen_error = FALSE; char* arg; Heapcleaner_Args* params; if ((params = MALLOC_CHUNK(Heapcleaner_Args)) == NULL) { die("unable to allocate heap_params"); } // We use 0 or "-1" to signify that // the default value should be used: // params->agegroup0_buffer_bytesize = 0; params->active_agegroups = -1; params->oldest_agegroup_keeping_idle_fromspace_buffers = -1; #define MATCH(opt) (strcmp(opt, option) == 0) #define CHECK(opt) { \ if (option_arg[0] == '\0') { \ seen_error = TRUE; \ say_error("missing argument for \"%s\" option\n", opt); \ continue; \ } \ } // CHECK while ((arg = *argv++) != NULL) { // // is_runtime_option def in src/c/main/runtime-options.c if (is_runtime_option(arg, option, &option_arg)) { // A runtime option is one starting with "--runtime-". // if (MATCH("gc-gen0-bufsize")) { // Set cleaner agegroup0 buffer size. // CHECK("gc-gen0-bufsize"); params->agegroup0_buffer_bytesize = get_size_option( ONE_K_BINARY, option_arg ); if (params->agegroup0_buffer_bytesize < 0) { // seen_error = TRUE; say_error( "bad argument for \"--runtime-gc-gen0-bufsize\" option\n" ); } } else if (MATCH("gc-generations")) { CHECK("gc-generations"); params->active_agegroups = atoi(option_arg); if (params->active_agegroups < 1) params->active_agegroups = 1; else if (params->active_agegroups > MAX_ACTIVE_AGEGROUPS) params->active_agegroups = MAX_ACTIVE_AGEGROUPS; } else if (MATCH("vmcache")) { CHECK("vmcache"); params->oldest_agegroup_keeping_idle_fromspace_buffers = atoi(option_arg); if (params->oldest_agegroup_keeping_idle_fromspace_buffers < 0) { params->oldest_agegroup_keeping_idle_fromspace_buffers = 0; } else if (params->oldest_agegroup_keeping_idle_fromspace_buffers > MAX_ACTIVE_AGEGROUPS) { params->oldest_agegroup_keeping_idle_fromspace_buffers = MAX_ACTIVE_AGEGROUPS; } } else if (MATCH("unlimited-heap")) { unlimited_heap_is_enabled__global = TRUE; } } if (seen_error) return NULL; } // while return params; }
int stdio_wrap(const char *ifname, const char *ofname) { int master __attribute__((cleanup(close_fd_))) = -1, slave __attribute__((cleanup(close_fd_))) = -1, ifd __attribute__((cleanup(close_fd_))) = -1, ofd __attribute__((cleanup(close_fd_))) = -1, listen_sock __attribute__((cleanup(close_fd_))) = -1, sock = -1; fd_set rfd_set; struct termios termios; int nfds = 0; if (ifname && (ifd = mfifo(ifname, O_RDWR)) == -1) say_error("can't open `%s': %m", ifname); if (ofname && (ofd = open(ofname, O_WRONLY | O_CREAT | O_TRUNC)) == -1) say_error("can't open `%s': %m", ofname); if (config.debug_port != 0 && (listen_sock = listen_port(config.debug_ipaddr, config.debug_port)) == -1) say_error("can't create debug socket"); if (pty_open(&master, &slave) != 0) { say_error("can't open pty: %m"); return -1; } switch (fork()) { case -1: say_error("can't fork: %m"); return -1; case 0: close(master); (void)login_tty(slave); (void)setvbuf(stdout, NULL, _IOLBF, 0); (void)setvbuf(stderr, NULL, _IONBF, 0); return 0; default: close(slave); if (isatty(STDIN_FILENO)) { (void)tcgetattr(STDIN_FILENO, &termios); cfmakeraw(&termios); (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios); } break; } FD_ZERO(&rfd_set); FD_SET(master, &rfd_set); FD_SET(STDIN_FILENO, &rfd_set); if (ifd != -1) FD_SET(ifd, &rfd_set); if (listen_sock != -1) FD_SET(listen_sock, &rfd_set); nfds = MAX(master, MAX(ifd, listen_sock)); while (true) { fd_set rfd_; int n; char buf[4096]; int r; int i = -1, o[3] = {-1, -1, -1}; rfd_ = rfd_set; n = select(nfds + 1, &rfd_, NULL, NULL, NULL); if (n < 0 && errno != EINTR) { say_error("select failed: %m"); _exit(EXIT_FAILURE); } for (; n > 0; n--) { if (listen_sock != -1 && FD_ISSET(listen_sock, &rfd_)) { if ((sock = accept(listen_sock, NULL, NULL)) == -1) { say_error("can't accept connection: %m"); continue; } // Force client into `raw' mode if (telnet_client_force_raw(sock) != 0) { say_error("failed to force client into `raw' mode:" " disconnecting"); close(sock); continue; } FD_CLR(listen_sock, &rfd_set); FD_SET(sock, &rfd_set); nfds = MAX(nfds, sock); continue; } else if (sock != -1 && FD_ISSET(sock, &rfd_)) { i = sock; o[0] = master; } else if (FD_ISSET(STDIN_FILENO, &rfd_)) { i = STDIN_FILENO; o[0] = master; } else if (ifd != -1 && FD_ISSET(ifd, &rfd_)) { i = ifd; o[0] = master; } else if (FD_ISSET(master, &rfd_)) { i = master; o[0] = sock; o[1] = STDOUT_FILENO; o[2] = ofd; } else // not reacheable assert(0); FD_CLR(i, &rfd_); if ((r = read(i, buf, sizeof(buf))) <= 0) { if (r < 0) say_error("couldn't read from %d: %m", i); if (i == master) _exit(EXIT_FAILURE); FD_CLR(i, &rfd_set); close(i); if (i == sock) { sock = -1; FD_SET(listen_sock, &rfd_set); } continue; } if (buf[r - 1] == '\0') // telnet client sent <CR><NUL> r -= 1; for (unsigned j = 0; j < 3; j++) { if (o[j] != -1 && write(o[j], buf, r) == -1 && errno != EBADF) { say_error("couldn't write to %d: %m", o[j]); if (o[j] == master) _exit(EXIT_FAILURE); close(o[j]); if (o[j] == sock) { sock = -1; FD_SET(listen_sock, &rfd_set); } } } } } _exit(EXIT_SUCCESS); }
KeyValuePair *parseCfgFile(const char *file) { FILE *stream __attribute__((cleanup(_close_stream))) = NULL; if (file == NULL) return NULL; stream = fopen(file, "r"); if (stream == NULL) { say_error("can't open `%s': %m", file); return NULL; } KeyValuePair *pairs __attribute__((cleanup(_free_pairs))) = NULL; unsigned npairs = 0; unsigned n = 0; size_t len = 0; char *line = NULL; while (!feof(stream)) { if (getline(&line, &len, stream) == -1 ) { if (feof(stream)) break; say_error("can't read line from `%s': %m", file); return NULL; } // skip empty lines and comments if (line[0] == '\0' || line[0] == '\n' || line[0] == '#') continue; if (n == npairs) { // use here malloc instead of realloc because realloc is broken by ... unsigned new_npairs = (1 + npairs) * 2; KeyValuePair *tmp = malloc(new_npairs * sizeof(KeyValuePair)); if (tmp == NULL) return NULL; if (pairs) { memcpy(tmp, pairs, npairs * sizeof(KeyValuePair)); free(pairs); } pairs = tmp; npairs = new_npairs; } int r; r = sscanf(line, "%s = %[^\n]", pairs[n].key, pairs[n].value); if (r != 2) { say_error("bad line format: `%s'", line); return NULL; } ++n; } free(line); pairs[n].key[0] = '\0'; KeyValuePair *r_pairs = pairs; pairs = NULL; return r_pairs; }
static ssize_t fiob_read(void *cookie, char *buf, size_t count) #endif { struct fiob *f = (struct fiob *)cookie; ssize_t to_read = (ssize_t) count; /* The number of starting bytes in f->buf to skip due to alignment */ off_t skip = 0; while (to_read > 0) { /* Align `to_read' FIOB_ALIGN to be <= size of f->buf */ ssize_t to_read_al = MIN(fiob_ceil(to_read), f->bsize); /* * Optimistically try to read aligned size into the aligned * buffer. If the current file position is not aligned then * read(2) returns EINVAL. In this case seek to an aligned * position and try again. This trick saves one extra * syscall for general workflow. */ ssize_t nrd = read(f->fd, f->buf, to_read_al); if (nrd < 0) { if (errno == EINTR) { errno = 0; continue; } else if (errno == EINVAL && skip == 0) { /* * read(2) can return EINVAL only in 3 cases: * 1. read buffer is not aligned - handled in * fiob_open(). * 2. read size is not aligned - handled above * 3. current file position is not aligned - * handled here. */ off_t pos = lseek(f->fd, 0, SEEK_CUR); if (pos < 0) { say_syserror("lseek, [%s]", f->path); return -1; } /* Calculate aligned position */ skip = pos % FIOB_ALIGN; pos -= skip; if (skip == 0) { /* Position is aligned. */ errno = EINVAL; say_error("read, [%s]", f->path); return -1; } /* Seek to the new position */ if (lseek(f->fd, pos, SEEK_SET) != pos) { say_syserror("lseek, [%s]", f->path); return -1; } /* Try to read again. */ continue; } say_syserror("read, [%s]", f->path); return -1; /* XXX: file position is unspecified */ } /* Ignore starting bytes if the position was aligned. */ nrd -= skip; if (nrd == 0) break; if (nrd > to_read) { /* * A few more bytes have been read because `to_read' * is not aligned to FIOB_ALIGN. Set the file position * to the expected libc value and ignore extra bytes. */ if (lseek(f->fd, to_read - nrd, SEEK_CUR) < 0) { say_syserror("lseek, [%s]", f->path); return -1; } nrd = to_read; } memcpy(buf, f->buf + skip, nrd); /* see nrd -= skip */ skip = 0; /* reset alignment offset */ buf += nrd; to_read -= nrd; } return count - to_read; }
int __wrap_main(int argc, char *argv[], char *envp[]) { int c; char *config_file = NULL; char *log_file = NULL; bool daemon = false; while ((c = getopt(argc, argv, "c:dhl:vV")) != -1) { switch (c) { case 'c': config_file = strdup(optarg); break; case 'd': daemon = true; break; case 'h': usage(); _exit(EXIT_SUCCESS); case 'l': log_file = strdup(optarg); break; case 'v': ++verbose; break; case 'V': printf("%s\n", openrelease_version()); _exit(EXIT_SUCCESS); case '?': usage(); _exit(EXIT_FAILURE); default: say_error("unmatched option: -%c", c); _exit(EXIT_FAILURE); } } create_log(log_file); config_init(config_file); if (getenv("OPENRELEASE_STAGE2") == NULL) { if (daemon) { if (daemonize(1, 0) == -1) { say_error("can't daemonize"); _exit(EXIT_FAILURE); } } if (stdio_wrap(config.input, config.output) == -1) { say_error("stdio_wrap failed"); _exit(EXIT_FAILURE); } putenv("OPENRELEASE_STAGE2=1"); execvp(argv[0], argv); } mmaps_init(); symfile_load(config.symfile); wrap_init(); debug_init(); key_action_init(); say_info("dive into RELEASE"); unsetenv("LD_PRELOAD"); argc = 1; if (optind != argc) { memmove(&argv[1], &argv[optind], (optind - argc) * sizeof(argv[0])); argc += optind - argc; } argv[argc] = NULL; __real_main(argc, argv, envp); _exit(EXIT_SUCCESS); return 0; }
static Val pickle_heap_datastructure (Task *task, Val root_chunk, Pickler_Result* result) { // ========================= // Heap* heap = task->heap; int max_age = result->oldest_agegroup_included_in_pickle; Vunt total_sib_buffer_bytesize[ MAX_PLAIN_SIBS ]; Vunt total_bytesize; struct { Vunt base; // Base address of the sib buffer in the heap. Vunt offset; // Relative position in the merged sib buffer. // } adjust[ MAX_AGEGROUPS ][ MAX_PLAIN_SIBS ]; Sib_Header* p; // Sib_Header def in src/c/heapcleaner/runtime-heap-image.h Sib_Header* sib_headers[ TOTAL_SIBS ]; Sib_Header* sib_header_buffer; int sib_header_bytesize; int smallchunk_sibs_count; Val pickle; Writer* wr; // Compute the sib offsets in the heap image: // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // total_sib_buffer_bytesize[ ilk ] = 0; } // The embedded literals go first: // total_sib_buffer_bytesize[ NONPTR_DATA_SIB ] // pickler__relocate_embedded_literals def in src/c/heapcleaner/datastructure-pickler-cleaner.c = pickler__relocate_embedded_literals( result, NONPTR_DATA_SIB, 0 ); // DEBUG debug_say("%d bytes of string literals\n", total_sib_buffer_bytesize[NONPTR_DATA_SIB]); for (int age = 0; age < max_age; age++) { for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; adjust[ age ][ ilk ].offset = total_sib_buffer_bytesize[ ilk ]; if (!sib_is_active(sib)) { // sib_is_active def in src/c/h/heap.h // adjust[ age ][ ilk ].base = 0; // } else { // total_sib_buffer_bytesize[ ilk ] += (Vunt) sib->tospace.first_free - (Vunt) sib->tospace.start; adjust[ age ][ ilk ].base = (Vunt) sib->tospace.start; } } } // DEBUG for (ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) debug_say ("sib %d: %d bytes\n", ilk+1, total_sib_buffer_bytesize[ilk]); // WHAT ABOUT THE BIG CHUNKS??? XXX BUGGO FIXME // Compute the total size of the pickled datastructure: // smallchunk_sibs_count = 0; total_bytesize = 0; // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (total_sib_buffer_bytesize[ilk] > 0) { smallchunk_sibs_count++; total_bytesize += total_sib_buffer_bytesize[ilk]; } } total_bytesize += sizeof( Heapfile_Header ) + sizeof( Pickle_Header ) + (smallchunk_sibs_count * sizeof( Sib_Header )); // COUNT SPACE FOR BIG CHUNKS total_bytesize += sizeof(Externs_Header) + heapfile_cfun_table_bytesize( result->cfun_table ); // Include the space for the external symbols (i.e., runtime C functions referenced within the heapgraph). // Allocate the heap bytevector for the pickled // datastructure representation and initialize // the bytevector-writer. // pickle = allocate_heap_ram_for_pickle( task, total_bytesize ); // wr = WR_OpenMem( PTR_CAST(Unt8*, pickle), total_bytesize ); // WR_OpenMem def in src/c/heapcleaner/mem-writer.c // Initialize the sib headers: // sib_header_bytesize = smallchunk_sibs_count * sizeof(Sib_Header); // sib_header_buffer = (Sib_Header*) MALLOC (sib_header_bytesize); // p = sib_header_buffer; // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (total_sib_buffer_bytesize[ ilk ] <= 0) { // sib_headers[ilk] = NULL; // } else { // p->age = 0; p->chunk_ilk = ilk; // p->info.o.base_address = 0; // Not used. p->info.o.bytesize = total_sib_buffer_bytesize[ ilk ]; p->info.o.rounded_bytesize = -1; // Not used. // p->offset = -1; // Not used. sib_headers[ ilk ] = p; p++; } } // What about big chunks? XXX BUGGO FIXME // Write the pickle image header: // if (heapio__write_image_header (wr, NORMAL_DATASTRUCTURE_PICKLE) == FALSE) { // heapio__write_image_header def in src/c/heapcleaner/export-heap-stuff.c // FREE( sib_header_buffer ); return PICKLER_ERROR; } // Write the pickle header: // { Pickle_Header header; header.smallchunk_sibs_count = smallchunk_sibs_count; header.hugechunk_sibs_count = 0; // FIX THIS XXX BUGGO FIXME header.hugechunk_quire_count = 0; // FIX THIS XXX BUGGO FIXME if (!IS_EXTERNAL_TAG( root_chunk )) { Sibid sibid = SIBID_FOR_POINTER( book_to_sibid__global, root_chunk ); if (!SIBID_KIND_IS_CODE(sibid)) { // This is the normal case -- // we're saving a vanilla heap value. Vunt addr = HEAP_POINTER_AS_UNT( root_chunk ); int age = GET_AGE_FROM_SIBID( sibid) - 1; int kind = GET_KIND_FROM_SIBID(sibid) - 1; // GET_KIND_FROM_SIBID def in src/c/h/sibid.h addr -= adjust[ age ][ kind ].base; addr += adjust[ age ][ kind ].offset; header.root_chunk = HIO_TAG_PTR(kind, addr); // HIO_TAG_PTR def in src/c/heapcleaner/runtime-heap-image.h } else { // Embedded_Chunk_Info* p = FIND_EMBEDDED_CHUNK( result->embedded_chunk_table, root_chunk ); if ((p == NULL) || (p->kind == USED_CODE)) { // say_error( "Pickling compiled Mythryl code not implemented\n" ); FREE (sib_header_buffer); return PICKLER_ERROR; } else { header.root_chunk = p->relocated_address; } } } else { // IS_EXTERNAL_TAG( root_chunk ) // ASSERT( smallchunk_sibs_count == 0 ); header.root_chunk = root_chunk; } WR_WRITE(wr, &header, sizeof(header)); // WR_WRITE def in src/c/heapcleaner/writer.h // if (WR_ERROR(wr)) { FREE (sib_header_buffer); return PICKLER_ERROR; } } // Record in the pickle the table of heap-referenced // runtime C functions. May also include // a handful of assembly fns, exceptions // and refcells: // { int bytes_written = heapio__write_cfun_table( wr, result->cfun_table ); // heapio__write_cfun_table def in src/c/heapcleaner/export-heap-stuff.c if (bytes_written == -1) { FREE( sib_header_buffer ); return PICKLER_ERROR; } } // Write the pickle sib headers: // WR_WRITE (wr, sib_header_buffer, sib_header_bytesize); // if (WR_ERROR(wr)) { FREE (sib_header_buffer); return PICKLER_ERROR; } // Write the pickled datastructure proper: // for (int ilk = 0; ilk < MAX_PLAIN_SIBS; ilk++) { // if (ilk == NONPTR_DATA_SIB) { // Write into the pickle the required embedded literals: // pickler__pickle_embedded_literals( wr ); // pickler__pickle_embedded_literals def in src/c/heapcleaner/datastructure-pickler-cleaner.c // Write into the pickle remaining required strings: // for (int age = 0; age < max_age; age++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; if (sib_is_active(sib)) { // sib_is_active def in src/c/h/heap.h // WR_WRITE( wr, sib->tospace.start, (Vunt) sib->tospace.first_free -(Vunt) sib->tospace.start ); } } } else { for (int age = 0; age < max_age; age++) { // Sib* sib = heap->agegroup[ age ]->sib[ ilk ]; if (sib_is_active( sib )) { // Val* top = sib->tospace.first_free; // for (Val* p = sib->tospace.start; p < top; p++ ){ Val w = *p; if (IS_POINTER(w)) { // Sibid sibid = SIBID_FOR_POINTER( book_to_sibid__global, w ); if (BOOK_IS_UNMAPPED(sibid)) { // w = add_cfun_to_heapfile_cfun_table( result->cfun_table, w); ASSERT (w != HEAP_VOID); } else if (SIBID_KIND_IS_CODE(sibid)) { Embedded_Chunk_Info* chunk_info = FIND_EMBEDDED_CHUNK( result->embedded_chunk_table, w ); if (chunk_info == NULL || chunk_info->kind == USED_CODE ){ die("Pickling of Mythryl compiled code not implemented"); } else { w = chunk_info->relocated_address; } } else { // Adjust the pointer: // int age = GET_AGE_FROM_SIBID( sibid)-1; int kind = GET_KIND_FROM_SIBID(sibid)-1; Vunt addr = HEAP_POINTER_AS_UNT(w); addr -= adjust[ age ][ kind ].base; addr += adjust[ age ][ kind ].offset; w = HIO_TAG_PTR( kind, addr ); } } // if (IS_POINTER(w)) WR_PUT(wr, (Vunt)w); } // for } } } } FREE( sib_header_buffer ); if (WR_ERROR(wr)) return PICKLER_ERROR; return make_vector_header(task, STRING_TAGWORD, pickle, total_bytesize); } // fun pickle_heap_datastructure
static Status map_quire (Quire* chunk, Punt bytesize) { // // Map a BOOK_BYTESIZE // aligned chunk of bytesize bytes of virtual memory. // // Return the address of the mapped memory // or NULL on failure. // // We get called (only) from // src/c/ram/get-quire-from-os-stuff.c int fd; Punt addr; Punt offset; #ifdef HAS_ANON_MMAP fd = -1; #else // Note: we use O_RDONLY, because some OS are // configured such that /dev/zero is not writable. // This works because we are using MAP_PRIVATE // as the mapping mode. // if ((fd = open("/dev/zero", O_RDONLY)) == -1) { // say_error( "Unable to open /dev/zero, errno = %d\n", errno ); // strerror would be nice here and elsewhere XXX BUGGO FIXME // return FALSE; } #endif // We grab an extra BOOK_BYTESIZE bytes // to give us some room for alignment: // addr = (Punt) mmap( NULL, // Requested address at which to map new memory. NULL lets the kernel choose freely -- the most portable choice. bytesize + BOOK_BYTESIZE, // Number of bytes of ram desired from OS. (PROT_READ | PROT_WRITE | PROT_EXEC), // Requested protection mode for mmap memory. We want full read-write-execute access to it. MMAP_FLGS, // Make allocated memory private -- changes not visible to other processes. fd, // File to map into memory. Ignored (unnecessary) on systems with MAP_ANONYMOUS, else /dev/zero. Either way we get zero-initialized memory. 0 // Offset within file 'fd'. ); // if (addr == -1) { // say_error( "Unable to map %d bytes, errno = %d\n", bytesize, errno ); #ifndef HAS_ANON_MMAP close (fd); // This call clobbers errno. #endif return FALSE; } #ifndef HAS_ANON_MMAP close (fd); #endif // Ensure BOOK_BYTESIZE alignment: // offset = BOOK_BYTESIZE - (addr & (BOOK_BYTESIZE-1)); // #ifndef HAS_PARTIAL_MUNMAP // chunk->mapBase = (Vunt*) addr; chunk->mapSizeB = bytesize + BOOK_BYTESIZE; addr += offset; #else if (offset == BOOK_BYTESIZE) { // munmap ((void *)(addr+bytesize), BOOK_BYTESIZE); // } else { // // Align addr and discard unused portions of memory: // munmap ((void *)addr, offset); addr += offset; munmap ((void *)(addr+bytesize), BOOK_BYTESIZE-offset); } #endif chunk->base = (Vunt *)addr; chunk->bytesize = bytesize; return TRUE; } // fun map_quire