char *file_read_string(void *parent, const char *path) { int ret, fd = open(path, O_RDONLY); char *string = NULL; off_t sz = 0; if (fd < 0) { nih_error("Error opening %s: %s", path, strerror(errno)); return NULL; } while (1) { char *n; sz += 1024; if (!(n = nih_realloc(string, parent, sz))) { nih_free(string); string = NULL; goto out; } string = n; memset(string+sz-1024, 0, 1024); ret = read(fd, string+sz-1024, 1024); if (ret < 0) { nih_free(string); string = NULL; goto out; } if (ret < 1024) break; } out: close(fd); drop_newlines(string); return string; }
/** * fgets_alloc: * @stream: stdio stream to read from. * * Reads from stream up to EOF or a newline, without any line-length * limitations. * * Returns: static string containing the entire line WITHOUT the * terminating newline, or NULL if end of file is reached and nothing * was read. **/ char * fgets_alloc (const void *parent, FILE * stream) { char * buf = NULL; size_t buf_sz = 0; size_t buf_len = 0; nih_assert (stream != NULL); for (;;) { char *ret; char *pos; if (buf_sz <= (buf_len + 1)) { buf_sz += 4096; buf = NIH_MUST (nih_realloc (buf, parent, buf_sz)); } ret = fgets (buf + buf_len, buf_sz - buf_len, stream); if ((! ret) && (! buf_len)) { nih_free (buf); return NULL; } else if (! ret) { return buf; } buf_len += strlen (ret); pos = strchr (ret, '\n'); if (pos) { *pos = '\0'; break; } } return buf; }
void test_realloc (void) { void *ptr1; void *ptr2; void *ptr3; TEST_FUNCTION ("nih_realloc"); /* Check that nih_realloc behaves like nih_alloc if the pointer is * NULL (it should, in fact, just call it) */ TEST_FEATURE ("as nih_alloc"); ptr1 = nih_realloc (NULL, NULL, 4096); memset (ptr1, 'x', 4096); TEST_ALLOC_SIZE (ptr1, 4096); TEST_ALLOC_PARENT (ptr1, NULL); nih_free (ptr1); /* Check that nih_realloc works if the block doesn't have a parent. */ TEST_FEATURE ("with no parent"); ptr1 = nih_alloc (NULL, 4096); memset (ptr1, 'x', 4096); ptr1 = nih_realloc (ptr1, NULL, 8096); memset (ptr1, 'x', 8096); TEST_ALLOC_SIZE (ptr1, 8096); TEST_ALLOC_PARENT (ptr1, NULL); /* Check that nih_realloc works if the block has a parent, the size * should change but the parent should remain the same. */ TEST_FEATURE ("with a parent"); ptr2 = nih_alloc (ptr1, 5); memset (ptr2, 'x', 5); ptr2 = nih_realloc (ptr2, ptr1, 10); memset (ptr2, 'x', 10); TEST_ALLOC_SIZE (ptr2, 10); TEST_ALLOC_PARENT (ptr2, ptr1); nih_free (ptr1); /* Check that nih_realloc works if the block being reallocated has * a child. This is fiddly as they need their parent pointers * adjusted. */ TEST_FEATURE ("with a child"); ptr1 = nih_alloc (NULL, 128); memset (ptr1, 'x', 128); ptr2 = nih_alloc (ptr1, 512); memset (ptr2, 'x', 512); ptr3 = nih_realloc (ptr1, NULL, 1024); memset (ptr3, 'x', 1024); TEST_ALLOC_PARENT (ptr2, ptr3); nih_free (ptr3); /* Check that nih_realloc returns NULL and doesn't alter the block * if the allocator fails. */ TEST_FEATURE ("with failing realloc"); ptr1 = nih_alloc (NULL, 10); assert (ptr1); memset (ptr1, 'x', 10); __nih_realloc = realloc_null; ptr2 = nih_realloc (ptr1, NULL, 200); __nih_realloc = realloc; TEST_EQ_P (ptr2, NULL); TEST_ALLOC_SIZE (ptr1, 10); nih_free (ptr1); }
int list_controllers_main (void *parent, char ***output) { DBusMessage *message = NULL, *reply = NULL; char ** output_local = NULL; DBusError error; DBusMessageIter iter; int ret = -1; DBusMessageIter output_local_iter; size_t output_local_size; *output = NULL; message = dbus_message_new_method_call(dbus_bus_get_unique_name(server_conn), "/org/linuxcontainers/cgmanager", "org.linuxcontainers.cgmanager0_0", "ListControllers"); dbus_error_init (&error); reply = dbus_connection_send_with_reply_and_block (server_conn, message, -1, &error); if (! reply) { dbus_message_unref (message); nih_error("%s: error completing dbus request: %s %s", __func__, error.name, error.message); dbus_error_free (&error); return -1; } dbus_message_unref (message); dbus_message_iter_init (reply, &iter); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) goto out; dbus_message_iter_recurse (&iter, &output_local_iter); output_local_size = 0; output_local = NULL; output_local = NIH_MUST( nih_alloc (parent, sizeof (char *)) ); output_local[output_local_size] = NULL; while (dbus_message_iter_get_arg_type (&output_local_iter) != DBUS_TYPE_INVALID) { const char *output_local_element_dbus; char ** output_local_tmp; char * output_local_element; if (dbus_message_iter_get_arg_type (&output_local_iter) != DBUS_TYPE_STRING) goto out; dbus_message_iter_get_basic (&output_local_iter, &output_local_element_dbus); output_local_element = NIH_MUST( nih_strdup (output_local, output_local_element_dbus) ); dbus_message_iter_next (&output_local_iter); output_local_tmp = NIH_MUST( nih_realloc (output_local, parent, sizeof (char *) * (output_local_size + 2)) ); output_local = output_local_tmp; output_local[output_local_size] = output_local_element; output_local[output_local_size + 1] = NULL; output_local_size++; } dbus_message_iter_next (&iter); if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID) goto out; *output = output_local; ret = 0; out: if (reply) dbus_message_unref (reply); if (ret) nih_free (output_local); return ret; }
int main (int argc, char *argv[]) { char ** args; nih_local char *message = NULL; size_t messagelen; nih_local char *msg = NULL; int arg; pid_t pid = 0; nih_main_init (argv[0]); nih_option_set_usage (_("TIME [MESSAGE]")); nih_option_set_synopsis (_("Bring the system down.")); nih_option_set_help ( _("TIME may have different formats, the most common is simply " "the word 'now' which will bring the system down " "immediately. Other valid formats are +m, where m is the " "number of minutes to wait until shutting down and hh:mm " "which specifies the time on the 24hr clock.\n" "\n" "Logged in users are warned by a message sent to their " "terminal, you may include an optional MESSAGE included " "with this. Messages can be sent without actually " "bringing the system down by using the -k option.\n" "\n" "If TIME is given, the command will remain in the " "foreground until the shutdown occurs. It can be cancelled " "by Control-C, or by another user using the -c option.\n" "\n" "The system is brought down into maintenance (single-user) " "mode by default, you can change this with either the -r or " "-h option which specify a reboot or system halt " "respectively. The -h option can be further modified with " "-H or -P to specify whether to halt the system, or to " "power it off afterwards. The default is left up to the " "shutdown scripts.")); args = nih_option_parser (NULL, argc, argv, options, FALSE); if (! args) exit (1); /* If the runlevel wasn't given explicitly, set it to 1 so we go * down into single-user mode. */ if (! runlevel) { runlevel = '1'; init_halt = NULL; } /* When may be specified with -g, or must be first argument */ if (! (cancel || when || args[0])) { fprintf (stderr, _("%s: time expected\n"), program_name); nih_main_suggest_help (); exit (1); } else if (! (cancel || when)) { when = NIH_MUST (nih_strdup (NULL, args[0])); arg = 1; } else { arg = 0; } /* Parse the time argument */ if (when) { if (! strcmp (when, "now")) { /* "now" means, err, now */ delay = 0; } else if (strchr (when, ':')) { /* Clock time */ long hours, mins; char *endptr; struct tm *tm; time_t now; hours = strtoul (when, &endptr, 10); if ((*endptr != ':') || (hours < 0) || (hours > 23)) { fprintf (stderr, _("%s: illegal hour value\n"), program_name); nih_main_suggest_help (); exit (1); } mins = strtoul (endptr + 1, &endptr, 10); if (*endptr || (mins < 0) || (mins > 59)) { fprintf (stderr, _("%s: illegal minute value\n"), program_name); nih_main_suggest_help (); exit (1); } /* Subtract the current time to get the delay. * Add a whole day if we go negative */ now = time (NULL); tm = localtime (&now); delay = (((hours * 60) + mins) - ((tm->tm_hour * 60) + tm->tm_min)); if (delay < 0) delay += 1440; } else { /* Delay in minutes */ char *endptr; delay = strtoul (when, &endptr, 10); if (*endptr || (delay < 0)) { fprintf (stderr, _("%s: illegal time value\n"), program_name); nih_main_suggest_help (); exit (1); } } nih_free (when); } /* The rest of the arguments are a message. * Really this should be just the next argument, but that's not * how this has been traditionally done *sigh* */ message = NIH_MUST (nih_strdup (NULL, "")); messagelen = 0; for (; args[arg]; arg++) { message = NIH_MUST (nih_realloc ( message, NULL, messagelen + strlen(args[arg]) + 4)); strcat (message, args[arg]); strcat (message, " "); messagelen += strlen (args[arg]) + 1; } /* Terminate with \r\n */ if (messagelen) strcat (message, "\r\n"); /* Check we're root, or setuid root */ setuid (geteuid ()); if (getuid ()) { nih_fatal (_("Need to be root")); exit (1); } /* Look for an existing pid file and deal with the existing * process if there is one. */ pid = nih_main_read_pidfile (); if (pid > 0) { if (cancel) { if (kill (pid, SIGINT) < 0) { nih_error (_("Shutdown is not running")); exit (1); } if (messagelen) wall (message); exit (0); } else if (kill (pid, 0) == 0) { nih_error (_("Another shutdown is already running")); exit (1); } } else if (cancel) { nih_error (_("Cannot find pid of running shutdown")); exit (1); } /* Send an initial message */ msg = NIH_MUST (warning_message (message)); wall (msg); if (warn_only) exit (0); /* Give us a sane environment */ if (chdir ("/") < 0) nih_warn ("%s: %s", _("Unable to change directory"), strerror (errno)); umask (022); /* Shutdown now? */ if (! delay) shutdown_now (); /* Save our pid so we can be interrupted later */ if (nih_main_write_pidfile (getpid ()) < 0) { NihError *err; err = nih_error_get (); nih_warn ("%s: %s: %s", nih_main_get_pidfile(), _("Unable to write pid file"), err->message); nih_free (err); } /* Ignore a whole bunch of signals */ nih_signal_set_ignore (SIGCHLD); nih_signal_set_ignore (SIGHUP); nih_signal_set_ignore (SIGTSTP); nih_signal_set_ignore (SIGTTIN); nih_signal_set_ignore (SIGTTOU); /* Catch the usual quit signals */ nih_signal_set_handler (SIGINT, nih_signal_handler); NIH_MUST (nih_signal_add_handler (NULL, SIGINT, cancel_callback, NULL)); nih_signal_set_handler (SIGQUIT, nih_signal_handler); NIH_MUST (nih_signal_add_handler (NULL, SIGQUIT, cancel_callback, NULL)); nih_signal_set_handler (SIGTERM, nih_signal_handler); NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, cancel_callback, NULL)); /* Call a timer every minute until we shutdown */ NIH_MUST (nih_timer_add_periodic (NULL, 60, (NihTimerCb)timer_callback, message)); /* Hang around */ nih_main_loop (); return 0; }