Beispiel #1
0
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;
}
Beispiel #2
0
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);
	};
};
Beispiel #3
0
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) &current_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
Beispiel #5
0
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;
}
Beispiel #6
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;
}
Beispiel #7
0
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;
}
Beispiel #9
0
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;
}
Beispiel #11
0
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);
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
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
Beispiel #16
0
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