예제 #1
0
파일: localed.c 프로젝트: vlajos/systemd
static int x11_read_data(Context *c) {
        _cleanup_fclose_ FILE *f;
        char line[LINE_MAX];
        bool in_section = false;
        int r;

        context_free_x11(c);

        f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
        if (!f)
                return errno == ENOENT ? 0 : -errno;

        while (fgets(line, sizeof(line), f)) {
                char *l;

                char_array_0(line);
                l = strstrip(line);

                if (l[0] == 0 || l[0] == '#')
                        continue;

                if (in_section && first_word(l, "Option")) {
                        _cleanup_strv_free_ char **a = NULL;

                        r = strv_split_quoted(&a, l, false);
                        if (r < 0)
                                return r;

                        if (strv_length(a) == 3) {
                                if (streq(a[1], "XkbLayout")) {
                                        free_and_replace(&c->x11_layout, a[2]);
                                        a[2] = NULL;
                                } else if (streq(a[1], "XkbModel")) {
                                        free_and_replace(&c->x11_model, a[2]);
                                        a[2] = NULL;
                                } else if (streq(a[1], "XkbVariant")) {
                                        free_and_replace(&c->x11_variant, a[2]);
                                        a[2] = NULL;
                                } else if (streq(a[1], "XkbOptions")) {
                                        free_and_replace(&c->x11_options, a[2]);
                                        a[2] = NULL;
                                }
                        }

                } else if (!in_section && first_word(l, "Section")) {
                        _cleanup_strv_free_ char **a = NULL;

                        r = strv_split_quoted(&a, l, false);
                        if (r < 0)
                                return -ENOMEM;

                        if (strv_length(a) == 2 && streq(a[1], "InputClass"))
                                in_section = true;

                } else if (in_section && first_word(l, "EndSection"))
                        in_section = false;
        }

        return 0;
}
예제 #2
0
파일: test-util.c 프로젝트: banada/systemd
static void test_first_word(void) {
        assert_se(first_word("Hello", ""));
        assert_se(first_word("Hello", "Hello"));
        assert_se(first_word("Hello world", "Hello"));
        assert_se(first_word("Hello\tworld", "Hello"));
        assert_se(first_word("Hello\nworld", "Hello"));
        assert_se(first_word("Hello\rworld", "Hello"));
        assert_se(first_word("Hello ", "Hello"));

        assert_se(!first_word("Hello", "Hellooo"));
        assert_se(!first_word("Hello", "xxxxx"));
        assert_se(!first_word("Hellooo", "Hello"));
}
예제 #3
0
/* Parses a string into the provided IrcMessage struct. Returns 1 on success, 0 on failure. */
int irc_parse_string(char *msgstr, int len, IrcMessage *msg) {
	//Copy msgstr into the full field
	char *fullcpy = malloc(sizeof(char) * strlen(msgstr));
	msg->full = strcpy(fullcpy, msgstr);

	//Set up all other fields
	msg->prefix = NULL;
	msg->command = IRC_NONE;
	msg->argc = 0;
	msg->argv = NULL;

	//Make parser pointer
	char *ptr = msgstr;

	//If first char is : we have a prefix
	if(msgstr[0] == ':') {
		ptr++;
		msg->prefix = first_word(&ptr);
	}

	if(ptr == NULL) return 1;
	
	//First word after optional prefix is command
	char *commandstr = first_word(&ptr);

	//Convert command string to command const
	int cmdlen = strlen(commandstr);
	if(cmdlen <= 3 && strndigit(commandstr,cmdlen)) {
		msg->command = IRC_NUMERIC;
	} else if(!strncmp(commandstr,"PING",4)) {
		msg->command = IRC_PING;
	} else if(!strncmp(commandstr,"NOTICE",6) || !strncmp(commandstr,"PRIVMSG",7)) {
		msg->command = IRC_MESSAGE;
	} else if(!strncmp(commandstr,"ERROR",5)) {
		msg->command = IRC_ERROR;
	} else if(!strncmp(commandstr,"JOIN",4)) {
		msg->command = IRC_JOIN;
	} else {
		msg->command = IRC_OTHER;
	}

	if(ptr == NULL) return 1;

	//Read additional arguments
	msg->argv = read_args(&ptr, &(msg->argc));

	return 1;
}
int		main(int ac, char **av)
{
	if (ac == 2)
		first_word(av[1]);
	ft_putchar('\n');
	return (0);
}
예제 #5
0
파일: shutdown.c 프로젝트: Keruspe/systemd
/* Read the following fields from /proc/meminfo:
 *
 *  NFS_Unstable
 *  Writeback
 *  Dirty
 *
 * Return true if the sum of these fields is greater than the previous
 * value input. For all other issues, report the failure and indicate that
 * the sync is not making progress.
 */
static bool sync_making_progress(unsigned long long *prev_dirty) {
        _cleanup_fclose_ FILE *f = NULL;
        unsigned long long val = 0;
        bool r = false;

        f = fopen("/proc/meminfo", "re");
        if (!f)
                return log_warning_errno(errno, "Failed to open /proc/meminfo: %m");

        for (;;) {
                _cleanup_free_ char *line = NULL;
                unsigned long long ull = 0;
                int q;

                q = read_line(f, LONG_LINE_MAX, &line);
                if (q < 0)
                        return log_warning_errno(q, "Failed to parse /proc/meminfo: %m");
                if (q == 0)
                        break;

                if (!first_word(line, "NFS_Unstable:") && !first_word(line, "Writeback:") && !first_word(line, "Dirty:"))
                        continue;

                errno = 0;
                if (sscanf(line, "%*s %llu %*s", &ull) != 1) {
                        if (errno != 0)
                                log_warning_errno(errno, "Failed to parse /proc/meminfo: %m");
                        else
                                log_warning("Failed to parse /proc/meminfo");

                        return false;
                }

                val += ull;
        }

        r = *prev_dirty > val;

        *prev_dirty = val;

        return r;
}
예제 #6
0
void InterpretedIC::replace(LookupResult result, klassOop receiver_klass) {
  // IC entries before modification - used for loging only
  Bytecodes::Code code_before  = send_code();
  oop             word1_before = first_word();
  oop             word2_before = second_word();
  int             transition   = 0;
  // modify IC
  guarantee(word2_before == receiver_klass, "klass should be the same");
  if (result.is_empty()) {
    clear();
    transition = 1;
  } else if (result.is_method()) {
    if (send_type() == Bytecodes::megamorphic_send) {
      set(send_code(), result.method(), receiver_klass);
      transition = 2;
    } else {
      // Please Fix this Robert
      // implement set_monomorphic(klass, method)
      clear();
      transition = 3;
    }
  } else {
    if (send_type() == Bytecodes::megamorphic_send) {
      set(send_code(), oop(result.entry()), receiver_klass);
      transition = 4;
    } else {
      assert(result.is_entry(), "must be jump table entry");
      // a jump table entry of a nmethod is found so let's update the current send
      set(Bytecodes::compiled_send_code_for(send_code()), oop(result.entry()), receiver_klass);
      transition = 5;
    }
  }
  // IC entries after modification - used for loging only
  Bytecodes::Code code_after  = send_code();
  oop             word1_after = first_word();
  oop             word2_after = second_word();
  // log modification
  LOG_EVENT3("InterpretedIC::replace: IC at 0x%x: entry for klass 0x%x replaced (transition %d)", this, receiver_klass, transition);
  LOG_EVENT3("  from (%s, 0x%x, 0x%x)", Bytecodes::name(code_before), word1_before, word2_before);
  LOG_EVENT3("  to   (%s, 0x%x, 0x%x)", Bytecodes::name(code_after ), word1_after , word2_after );
}
예제 #7
0
symbolOop InterpretedIC::selector() const {
  oop fw = first_word();
  if (fw->is_symbol()) {
    return symbolOop(fw);
  } else if (fw->is_method()) {
    return methodOop(fw)->selector();
  } else {
    jumpTableEntry* e = jump_table_entry();
    nmethod* nm = e->method();
    assert(nm != NULL, "must have an nmethod");
    return nm->key.selector();
  }
}
예제 #8
0
파일: stripper.c 프로젝트: Ecdosis/calliope
/**
 * Add markup for the detected hyphen 
 * @param u the userdata
 * @param text the current text after the hyphen
 * @param len its length
 */
static void process_hyphen( userdata *u, XML_Char *text, int len )
{
    XML_Char *next = first_word(text,len);
    if ( next != NULL && strlen(next)>0 )
    {
        char *force = "weak";
        XML_Char *last = userdata_last_word(u);
        XML_Char *combined = combine_words(last,next);
        if ( (userdata_has_word(u,last)
            && userdata_has_word(u,next)
            && combined!=NULL
            && (!userdata_has_word(u,combined)
                ||userdata_has_hh_exception(u,combined)))
            || (strlen(next)>0&&isupper(next[0])) )
        {
            force = "strong";
            //printf("strong: %s-%s\n",last,next);
        }
        //else
        //    printf("weak: %s\n",combined);
        // create a range to describe a hard hyphen
        char **atts = calloc(1,sizeof(char*));
        if ( atts != NULL )
        {
            range *r = range_new( 0, force, atts, userdata_hoffset(u) );
            if ( r != NULL )
            {
                dest_file *df = userdata_get_markup_dest( u, force );
                userdata_set_hyphen_state(u,HYPHEN_NONE);
                range_set_len( r, 1 );
                dest_file_enqueue( df, r );
            }
        }
        else
            fprintf(stderr,"stripper: failed to create hyphen range\n");
        if ( combined != NULL )
            free( combined );
    }
    if ( next != NULL )
        free( next );
}
예제 #9
0
int x11_read_data(Context *c, sd_bus_message *m) {
        _cleanup_fclose_ FILE *f = NULL;
        bool in_section = false;
        char line[LINE_MAX];
        struct stat st;
        usec_t t;
        int r;

        /* Do not try to re-read the file within single bus operation. */
        if (m) {
                if (m == c->x11_cache)
                        return 0;

                sd_bus_message_unref(c->x11_cache);
                c->x11_cache = sd_bus_message_ref(m);
        }

        if (stat("/etc/X11/xorg.conf.d/00-keyboard.conf", &st) < 0) {
                if (errno != ENOENT)
                        return -errno;

                c->x11_mtime = USEC_INFINITY;
                context_free_x11(c);
                return 0;
        }

        /* If mtime is not changed, then we do not need to re-read */
        t = timespec_load(&st.st_mtim);
        if (c->x11_mtime != USEC_INFINITY && t == c->x11_mtime)
                return 0;

        c->x11_mtime = t;
        context_free_x11(c);

        f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
        if (!f)
                return -errno;

        while (fgets(line, sizeof(line), f)) {
                char *l;

                char_array_0(line);
                l = strstrip(line);

                if (IN_SET(l[0], 0, '#'))
                        continue;

                if (in_section && first_word(l, "Option")) {
                        _cleanup_strv_free_ char **a = NULL;

                        r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES);
                        if (r < 0)
                                return r;

                        if (strv_length(a) == 3) {
                                char **p = NULL;

                                if (streq(a[1], "XkbLayout"))
                                        p = &c->x11_layout;
                                else if (streq(a[1], "XkbModel"))
                                        p = &c->x11_model;
                                else if (streq(a[1], "XkbVariant"))
                                        p = &c->x11_variant;
                                else if (streq(a[1], "XkbOptions"))
                                        p = &c->x11_options;

                                if (p) {
                                        free_and_replace(*p, a[2]);
                                }
                        }

                } else if (!in_section && first_word(l, "Section")) {
                        _cleanup_strv_free_ char **a = NULL;

                        r = strv_split_extract(&a, l, WHITESPACE, EXTRACT_QUOTES);
                        if (r < 0)
                                return -ENOMEM;

                        if (strv_length(a) == 2 && streq(a[1], "InputClass"))
                                in_section = true;

                } else if (in_section && first_word(l, "EndSection"))
                        in_section = false;
        }

        return 0;
}
예제 #10
0
파일: cgtop.c 프로젝트: g33s3/systemmd
static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) {
        Group *g;
        int r;
        FILE *f = NULL;
        pid_t pid;
        unsigned n;

        assert(controller);
        assert(path);
        assert(a);

        g = hashmap_get(a, path);
        if (!g) {
                g = hashmap_get(b, path);
                if (!g) {
                        g = new0(Group, 1);
                        if (!g)
                                return -ENOMEM;

                        g->path = strdup(path);
                        if (!g->path) {
                                group_free(g);
                                return -ENOMEM;
                        }

                        r = hashmap_put(a, g->path, g);
                        if (r < 0) {
                                group_free(g);
                                return r;
                        }
                } else {
                        assert_se(hashmap_move_one(a, b, path) == 0);
                        g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false;
                }
        }

        /* Regardless which controller, let's find the maximum number
         * of processes in any of it */

        r = cg_enumerate_processes(controller, path, &f);
        if (r < 0)
                return r;

        n = 0;
        while (cg_read_pid(f, &pid) > 0)
                n++;
        fclose(f);

        if (n > 0) {
                if (g->n_tasks_valid)
                        g->n_tasks = MAX(g->n_tasks, n);
                else
                        g->n_tasks = n;

                g->n_tasks_valid = true;
        }

        if (streq(controller, "cpuacct")) {
                uint64_t new_usage;
                char *p, *v;
                struct timespec ts;

                r = cg_get_path(controller, path, "cpuacct.usage", &p);
                if (r < 0)
                        return r;

                r = read_one_line_file(p, &v);
                free(p);
                if (r < 0)
                        return r;

                r = safe_atou64(v, &new_usage);
                free(v);
                if (r < 0)
                        return r;

                assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);

                if (g->cpu_iteration == iteration - 1) {
                        uint64_t x, y;

                        x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) -
                                ((uint64_t) g->cpu_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->cpu_timestamp.tv_nsec);

                        y = new_usage - g->cpu_usage;

                        if (y > 0) {
                                g->cpu_fraction = (double) y / (double) x;
                                g->cpu_valid = true;
                        }
                }

                g->cpu_usage = new_usage;
                g->cpu_timestamp = ts;
                g->cpu_iteration = iteration;

        } else if (streq(controller, "memory")) {
                char *p, *v;

                r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
                if (r < 0)
                        return r;

                r = read_one_line_file(p, &v);
                free(p);
                if (r < 0)
                        return r;

                r = safe_atou64(v, &g->memory);
                free(v);
                if (r < 0)
                        return r;

                if (g->memory > 0)
                        g->memory_valid = true;

        } else if (streq(controller, "blkio")) {
                char *p;
                uint64_t wr = 0, rd = 0;
                struct timespec ts;

                r = cg_get_path(controller, path, "blkio.io_service_bytes", &p);
                if (r < 0)
                        return r;

                f = fopen(p, "re");
                free(p);

                if (!f)
                        return -errno;

                for (;;) {
                        char line[LINE_MAX], *l;
                        uint64_t k, *q;

                        if (!fgets(line, sizeof(line), f))
                                break;

                        l = strstrip(line);
                        l += strcspn(l, WHITESPACE);
                        l += strspn(l, WHITESPACE);

                        if (first_word(l, "Read")) {
                                l += 4;
                                q = &rd;
                        } else if (first_word(l, "Write")) {
                                l += 5;
                                q = &wr;
                        } else
                                continue;

                        l += strspn(l, WHITESPACE);
                        r = safe_atou64(l, &k);
                        if (r < 0)
                                continue;

                        *q += k;
                }

                fclose(f);

                assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);

                if (g->io_iteration == iteration - 1) {
                        uint64_t x, yr, yw;

                        x = ((uint64_t) ts.tv_sec * 1000000000ULL + (uint64_t) ts.tv_nsec) -
                                ((uint64_t) g->io_timestamp.tv_sec * 1000000000ULL + (uint64_t) g->io_timestamp.tv_nsec);

                        yr = rd - g->io_input;
                        yw = wr - g->io_output;

                        if (yr > 0 || yw > 0) {
                                g->io_input_bps = (yr * 1000000000ULL) / x;
                                g->io_output_bps = (yw * 1000000000ULL) / x;
                                g->io_valid = true;

                        }
                }

                g->io_input = rd;
                g->io_output = wr;
                g->io_timestamp = ts;
                g->io_iteration = iteration;
        }

        return 0;
}
예제 #11
0
파일: localed.c 프로젝트: mariux/systemd
static int read_data_x11(void) {
        FILE *f;
        char line[LINE_MAX];
        bool in_section = false;

        free_data_x11();

        f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
        if (!f) {
                if (errno == ENOENT) {

#ifdef TARGET_FEDORA
                        f = fopen("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf", "re");
                        if (!f) {
                                if (errno == ENOENT)
                                        return 0;
                                else
                                        return -errno;
                        }
#else
                        return 0;
#endif

                } else
                          return -errno;
        }

        while (fgets(line, sizeof(line), f)) {
                char *l;

                char_array_0(line);
                l = strstrip(line);

                if (l[0] == 0 || l[0] == '#')
                        continue;

                if (in_section && first_word(l, "Option")) {
                        char **a;

                        a = strv_split_quoted(l);
                        if (!a) {
                                fclose(f);
                                return -ENOMEM;
                        }

                        if (strv_length(a) == 3) {

                                if (streq(a[1], "XkbLayout")) {
                                        free(state.x11_layout);
                                        state.x11_layout = a[2];
                                        a[2] = NULL;
                                } else if (streq(a[1], "XkbModel")) {
                                        free(state.x11_model);
                                        state.x11_model = a[2];
                                        a[2] = NULL;
                                } else if (streq(a[1], "XkbVariant")) {
                                        free(state.x11_variant);
                                        state.x11_variant = a[2];
                                        a[2] = NULL;
                                } else if (streq(a[1], "XkbOptions")) {
                                        free(state.x11_options);
                                        state.x11_options = a[2];
                                        a[2] = NULL;
                                }
                        }

                        strv_free(a);

                } else if (!in_section && first_word(l, "Section")) {
                        char **a;

                        a = strv_split_quoted(l);
                        if (!a) {
                                fclose(f);
                                return -ENOMEM;
                        }

                        if (strv_length(a) == 2 && streq(a[1], "InputClass"))
                                in_section = true;

                        strv_free(a);
                } else if (in_section && first_word(l, "EndSection"))
                        in_section = false;
        }

        fclose(f);

        return 0;
}
예제 #12
0
/* Parse a single logical line */
static int parse_line(
                const char* unit,
                const char *filename,
                unsigned line,
                const char *sections,
                ConfigItemLookup lookup,
                const void *table,
                ConfigParseFlags flags,
                char **section,
                unsigned *section_line,
                bool *section_ignored,
                char *l,
                void *userdata) {

        char *e, *include;

        assert(filename);
        assert(line > 0);
        assert(lookup);
        assert(l);

        l = strstrip(l);
        if (!*l)
                return 0;

        if (strchr(COMMENTS "\n", *l))
                return 0;

        include = first_word(l, ".include");
        if (include) {
                _cleanup_free_ char *fn = NULL;

                /* .includes are a bad idea, we only support them here
                 * for historical reasons. They create cyclic include
                 * problems and make it difficult to detect
                 * configuration file changes with an easy
                 * stat(). Better approaches, such as .d/ drop-in
                 * snippets exist.
                 *
                 * Support for them should be eventually removed. */

                if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
                        log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
                        return 0;
                }

                log_syntax(unit, LOG_WARNING, filename, line, 0,
                           ".include directives are deprecated, and support for them will be removed in a future version of systemd. "
                           "Please use drop-in files instead.");

                fn = file_in_same_dir(filename, strstrip(include));
                if (!fn)
                        return -ENOMEM;

                return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
        }

        if (!utf8_is_valid(l))
                return log_syntax_invalid_utf8(unit, LOG_WARNING, filename, line, l);

        if (*l == '[') {
                size_t k;
                char *n;

                k = strlen(l);
                assert(k > 0);

                if (l[k-1] != ']') {
                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
                        return -EBADMSG;
                }

                n = strndup(l+1, k-2);
                if (!n)
                        return -ENOMEM;

                if (sections && !nulstr_contains(sections, n)) {

                        if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
                                log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);

                        free(n);
                        *section = mfree(*section);
                        *section_line = 0;
                        *section_ignored = true;
                } else {
                        free_and_replace(*section, n);
                        *section_line = line;
                        *section_ignored = false;
                }

                return 0;
        }

        if (sections && !*section) {

                if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");

                return 0;
        }

        e = strchr(l, '=');
        if (!e) {
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
                return -EINVAL;
        }

        *e = 0;
        e++;

        return next_assignment(unit,
                               filename,
                               line,
                               lookup,
                               table,
                               *section,
                               *section_line,
                               strstrip(l),
                               strstrip(e),
                               flags,
                               userdata);
}
예제 #13
0
파일: do_command.c 프로젝트: execunix/vinos
static void
child_process(entry *e) {
    int stdin_pipe[2], stdout_pipe[2];
    char * volatile input_data;
    char *homedir, *usernm, * volatile mailto;
    int children = 0;

    Debug(DPROC, ("[%ld] child_process('%s')\n", (long)getpid(), e->cmd));

    setproctitle("running job");

    /* discover some useful and important environment settings
     */
    usernm = e->pwd->pw_name;
    mailto = env_get("MAILTO", e->envp);

    /* our parent is watching for our death by catching SIGCHLD.  we
     * do not care to watch for our children's deaths this way -- we
     * use wait() explicitly.  so we have to reset the signal (which
     * was inherited from the parent).
     */
    (void) signal(SIGCHLD, SIG_DFL);

    /* create some pipes to talk to our future child
     */
    if (pipe(stdin_pipe) == -1) 	/* child's stdin */
        log_it("CRON", getpid(), "error", "create child stdin pipe");
    if (pipe(stdout_pipe) == -1)	/* child's stdout */
        log_it("CRON", getpid(), "error", "create child stdout pipe");

    /* since we are a forked process, we can diddle the command string
     * we were passed -- nobody else is going to use it again, right?
     *
     * if a % is present in the command, previous characters are the
     * command, and subsequent characters are the additional input to
     * the command.  An escaped % will have the escape character stripped
     * from it.  Subsequent %'s will be transformed into newlines,
     * but that happens later.
     */
    /*local*/{
        int escaped = FALSE;
        int ch;
        char *p;

        /* translation:
         *	\% -> %
         *	%  -> end of command, following is command input.
         *	\x -> \x	for all x != %
         */
        input_data = p = e->cmd;
        while ((ch = *input_data++) != '\0') {
            if (escaped) {
                if (ch != '%')
                    *p++ = '\\';
            } else {
                if (ch == '%') {
                    break;
                }
            }

            if (!(escaped = (ch == '\\'))) {
                *p++ = ch;
            }
        }
        if (ch == '\0') {
            /* move pointer back, so that code below
             * won't think we encountered % sequence */
            input_data--;
        }
        if (escaped)
            *p++ = '\\';

        *p = '\0';
    }

    /* fork again, this time so we can exec the user's command.
     */
    switch (vfork()) {
    case -1:
        log_it("CRON", getpid(), "error", "can't vfork");
        exit(ERROR_EXIT);
    /*NOTREACHED*/
    case 0:
        Debug(DPROC, ("[%ld] grandchild process vfork()'ed\n",
                      (long)getpid()));

        /* write a log message.  we've waited this long to do it
         * because it was not until now that we knew the PID that
         * the actual user command shell was going to get and the
         * PID is part of the log message.
         */
        if ((e->flags & DONT_LOG) == 0) {
            char *x = mkprints(e->cmd, strlen(e->cmd));

            log_it(usernm, getpid(), "CMD START", x);
            free(x);
        }

        /* that's the last thing we'll log.  close the log files.
         */
        log_close();

        /* get new pgrp, void tty, etc.
         */
        if (setsid() == -1)
            syslog(LOG_ERR, "setsid() failure: %m");

        /* close the pipe ends that we won't use.  this doesn't affect
         * the parent, who has to read and write them; it keeps the
         * kernel from recording us as a potential client TWICE --
         * which would keep it from sending SIGPIPE in otherwise
         * appropriate circumstances.
         */
        (void)close(stdin_pipe[WRITE_PIPE]);
        (void)close(stdout_pipe[READ_PIPE]);

        /* grandchild process.  make std{in,out} be the ends of
         * pipes opened by our daddy; make stderr go to stdout.
         */
        if (stdin_pipe[READ_PIPE] != STDIN) {
            (void)dup2(stdin_pipe[READ_PIPE], STDIN);
            (void)close(stdin_pipe[READ_PIPE]);
        }
        if (stdout_pipe[WRITE_PIPE] != STDOUT) {
            (void)dup2(stdout_pipe[WRITE_PIPE], STDOUT);
            (void)close(stdout_pipe[WRITE_PIPE]);
        }
        (void)dup2(STDOUT, STDERR);

        /* set our directory, uid and gid.  Set gid first, since once
         * we set uid, we've lost root privledges.
         */
#ifdef LOGIN_CAP
        {
#ifdef BSD_AUTH
            auth_session_t *as;
#endif
            login_cap_t *lc;
            char *p;

            if ((lc = login_getclass(e->pwd->pw_class)) == NULL) {
                warnx("unable to get login class for `%s'",
                      e->pwd->pw_name);
                _exit(ERROR_EXIT);
            }
            if (setusercontext(lc, e->pwd, e->pwd->pw_uid, LOGIN_SETALL) < 0) {
                warnx("setusercontext failed for `%s'",
                      e->pwd->pw_name);
                _exit(ERROR_EXIT);
            }
#ifdef BSD_AUTH
            as = auth_open();
            if (as == NULL || auth_setpwd(as, e->pwd) != 0) {
                warn("can't malloc");
                _exit(ERROR_EXIT);
            }
            if (auth_approval(as, lc, usernm, "cron") <= 0) {
                warnx("approval failed for `%s'",
                      e->pwd->pw_name);
                _exit(ERROR_EXIT);
            }
            auth_close(as);
#endif /* BSD_AUTH */
            login_close(lc);

            /* If no PATH specified in crontab file but
             * we just added one via login.conf, add it to
             * the crontab environment.
             */
            if (env_get("PATH", e->envp) == NULL) {
                if ((p = getenv("PATH")) != NULL)
                    e->envp = env_set(e->envp, p);
            }
        }
#else
        if (setgid(e->pwd->pw_gid) != 0) {
            syslog(LOG_ERR, "setgid(%d) failed for %s: %m",
                   e->pwd->pw_gid, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
        if (initgroups(usernm, e->pwd->pw_gid) != 0) {
            syslog(LOG_ERR, "initgroups(%s, %d) failed for %s: %m",
                   usernm, e->pwd->pw_gid, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
#if (defined(BSD)) && (BSD >= 199103)
        if (setlogin(usernm) < 0) {
            syslog(LOG_ERR, "setlogin(%s) failure for %s: %m",
                   usernm, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
#endif /* BSD */
        if (setuid(e->pwd->pw_uid) != 0) {
            syslog(LOG_ERR, "setuid(%d) failed for %s: %m",
                   e->pwd->pw_uid, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }
        /* we aren't root after this... */
#endif /* LOGIN_CAP */
        homedir = env_get("HOME", e->envp);
        if (chdir(homedir) != 0) {
            syslog(LOG_ERR, "chdir(%s) $HOME failed for %s: %m",
                   homedir, e->pwd->pw_name);
            _exit(ERROR_EXIT);
        }

#ifdef USE_SIGCHLD
        /* our grandparent is watching for our death by catching
         * SIGCHLD.  the parent is ignoring SIGCHLD's; we want
         * to restore default behaviour.
         */
        (void) signal(SIGCHLD, SIG_DFL);
#endif
        (void) signal(SIGHUP, SIG_DFL);

        /*
         * Exec the command.
         */
        {
            char	*shell = env_get("SHELL", e->envp);

# if DEBUGGING
            if (DebugFlags & DTEST) {
                (void)fprintf(stderr,
                              "debug DTEST is on, not exec'ing command.\n");
                (void)fprintf(stderr,
                              "\tcmd='%s' shell='%s'\n", e->cmd, shell);
                _exit(OK_EXIT);
            }
# endif /*DEBUGGING*/
            (void)execle(shell, shell, "-c", e->cmd, NULL, e->envp);
            warn("execl: couldn't exec `%s'", shell);
            _exit(ERROR_EXIT);
        }
        break;
    default:
        /* parent process */
        break;
    }

    children++;

    /* middle process, child of original cron, parent of process running
     * the user's command.
     */

    Debug(DPROC, ("[%ld] child continues, closing pipes\n",(long)getpid()));

    /* close the ends of the pipe that will only be referenced in the
     * grandchild process...
     */
    (void)close(stdin_pipe[READ_PIPE]);
    (void)close(stdout_pipe[WRITE_PIPE]);

    /*
     * write, to the pipe connected to child's stdin, any input specified
     * after a % in the crontab entry.  while we copy, convert any
     * additional %'s to newlines.  when done, if some characters were
     * written and the last one wasn't a newline, write a newline.
     *
     * Note that if the input data won't fit into one pipe buffer (2K
     * or 4K on most BSD systems), and the child doesn't read its stdin,
     * we would block here.  thus we must fork again.
     */

    if (*input_data && fork() == 0) {
        FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
        int need_newline = FALSE;
        int escaped = FALSE;
        int ch;

        Debug(DPROC, ("[%ld] child2 sending data to grandchild\n",
                      (long)getpid()));

        /* close the pipe we don't use, since we inherited it and
         * are part of its reference count now.
         */
        (void)close(stdout_pipe[READ_PIPE]);

        /* translation:
         *	\% -> %
         *	%  -> \n
         *	\x -> \x	for all x != %
         */
        while ((ch = *input_data++) != '\0') {
            if (escaped) {
                if (ch != '%')
                    (void)putc('\\', out);
            } else {
                if (ch == '%')
                    ch = '\n';
            }

            if (!(escaped = (ch == '\\'))) {
                (void)putc(ch, out);
                need_newline = (ch != '\n');
            }
        }
        if (escaped)
            (void)putc('\\', out);
        if (need_newline)
            (void)putc('\n', out);

        /* close the pipe, causing an EOF condition.  fclose causes
         * stdin_pipe[WRITE_PIPE] to be closed, too.
         */
        (void)fclose(out);

        Debug(DPROC, ("[%ld] child2 done sending to grandchild\n",
                      (long)getpid()));
        exit(0);
    }

    /* close the pipe to the grandkiddie's stdin, since its wicked uncle
     * ernie back there has it open and will close it when he's done.
     */
    (void)close(stdin_pipe[WRITE_PIPE]);

    children++;

    /*
     * read output from the grandchild.  it's stderr has been redirected to
     * it's stdout, which has been redirected to our pipe.  if there is any
     * output, we'll be mailing it to the user whose crontab this is...
     * when the grandchild exits, we'll get EOF.
     */

    Debug(DPROC, ("[%ld] child reading output from grandchild\n",
                  (long)getpid()));

    /*local*/{
        FILE	*in = fdopen(stdout_pipe[READ_PIPE], "r");
        int	ch = getc(in);

        if (ch != EOF) {
            FILE	*mail = NULL;
            int	bytes = 1;
            int	status = 0;

            Debug(DPROC|DEXT,
                  ("[%ld] got data (%x:%c) from grandchild\n",
                   (long)getpid(), ch, ch));

            /* get name of recipient.  this is MAILTO if set to a
             * valid local username; USER otherwise.
             */
            if (mailto) {
                /* MAILTO was present in the environment
                 */
                if (!*mailto) {
                    /* ... but it's empty. set to NULL
                     */
                    mailto = NULL;
                }
            } else {
                /* MAILTO not present, set to USER.
                 */
                mailto = usernm;
            }

            /* if we are supposed to be mailing, MAILTO will
             * be non-NULL.  only in this case should we set
             * up the mail command and subjects and stuff...
             */

            if (mailto && safe_p(usernm, mailto)) {
                char	**env;
                char	mailcmd[MAX_COMMAND];
                char	hostname[MAXHOSTNAMELEN + 1];

                (void)gethostname(hostname, MAXHOSTNAMELEN);
                if (strlens(MAILFMT, MAILARG, NULL) + 1
                        >= sizeof mailcmd) {
                    warnx("mailcmd too long");
                    (void) _exit(ERROR_EXIT);
                }
                (void)snprintf(mailcmd, sizeof(mailcmd),
                               MAILFMT, MAILARG);
                if (!(mail = cron_popen(mailcmd, "w", e->pwd))) {
                    warn("cannot run `%s'", mailcmd);
                    (void) _exit(ERROR_EXIT);
                }
                (void)fprintf(mail,
                              "From: root (Cron Daemon)\n");
                (void)fprintf(mail, "To: %s\n", mailto);
                (void)fprintf(mail,
                              "Subject: Cron <%s@%s> %s\n",
                              usernm, first_word(hostname, "."), e->cmd);
                (void)fprintf(mail,
                              "Auto-Submitted: auto-generated\n");
#ifdef MAIL_DATE
                (void)fprintf(mail, "Date: %s\n",
                              arpadate(&StartTime));
#endif /*MAIL_DATE*/
                for (env = e->envp;  *env;  env++)
                    (void)fprintf(mail,
                                  "X-Cron-Env: <%s>\n", *env);
                (void)fprintf(mail, "\n");

                /* this was the first char from the pipe
                 */
                (void)putc(ch, mail);
            }

            /* we have to read the input pipe no matter whether
             * we mail or not, but obviously we only write to
             * mail pipe if we ARE mailing.
             */

            while (EOF != (ch = getc(in))) {
                bytes++;
                if (mailto)
                    (void)putc(ch, mail);
            }

            /* only close pipe if we opened it -- i.e., we're
             * mailing...
             */

            if (mailto) {
                Debug(DPROC, ("[%ld] closing pipe to mail\n",
                              (long)getpid()));
                /* Note: the pclose will probably see
                 * the termination of the grandchild
                 * in addition to the mail process, since
                 * it (the grandchild) is likely to exit
                 * after closing its stdout.
                 */
                status = cron_pclose(mail);
            }

            /* if there was output and we could not mail it,
             * log the facts so the poor user can figure out
             * what's going on.
             */
            if (mailto && status) {
                char buf[MAX_TEMPSTR];

                (void)snprintf(buf, sizeof(buf),
                               "mailed %d byte%s of output but got status 0x%04x\n",
                               bytes, (bytes==1)?"":"s",
                               status);
                log_it(usernm, getpid(), "MAIL", buf);
            }

        } /*if data from grandchild*/

        Debug(DPROC, ("[%ld] got EOF from grandchild\n",
                      (long)getpid()));

        (void)fclose(in);	/* also closes stdout_pipe[READ_PIPE] */
    }

    /* wait for children to die.
     */
    for (; children > 0; children--) {
        WAIT_T waiter;
        PID_T pid;

        Debug(DPROC, ("[%ld] waiting for grandchild #%d to finish\n",
                      (long)getpid(), children));
        while ((pid = wait(&waiter)) < OK && errno == EINTR)
            ;
        if (pid < OK) {
            Debug(DPROC,
                  ("[%ld] no more grandchildren--mail written?\n",
                   (long)getpid()));
            break;
        }
        Debug(DPROC, ("[%ld] grandchild #%ld finished, status=%04x",
                      (long)getpid(), (long)pid, WEXITSTATUS(waiter)));
        if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
            Debug(DPROC, (", dumped core"));
        Debug(DPROC, ("\n"));
    }

    /* Log the time when we finished deadling with the job */
    /*local*/{
        char *x = mkprints(e->cmd, strlen(e->cmd));

        log_it(usernm, getpid(), "CMD FINISH", x);
        free(x);
    }
}
예제 #14
0
void InterpretedIC::cleanup() {
  if (is_empty()) return; // Nothing to cleanup

  switch (send_type()) {
    case Bytecodes::accessor_send:    // fall through
    case Bytecodes::primitive_send:   // fall through
    case Bytecodes::predicted_send:   // fall through
    case Bytecodes::interpreted_send:
      { // check if the interpreted send should be replaced by a compiled send
        klassOop receiver_klass = klassOop(second_word());
        assert(receiver_klass->is_klass(), "receiver klass must be a klass");
        methodOop method = methodOop(first_word());
        assert(method->is_method(), "first word in interpreter IC must be method");
        if (!Bytecodes::is_super_send(send_code())) {
          // super sends cannot be handled since the sending method holder is unknown at this point.
          LookupKey key(receiver_klass, selector());
          LookupResult result = lookupCache::lookup(&key);
          if (!result.matches(method)) {
            replace(result, receiver_klass);
          }
        }
      }
      break;
    case Bytecodes::compiled_send:
      { // check if the current compiled send is valid
        klassOop receiver_klass = klassOop(second_word());
        assert(receiver_klass->is_klass(), "receiver klass must be a klass");
        jumpTableEntry* entry = (jumpTableEntry*) first_word();
        nmethod* nm = entry->method();
        LookupResult result = lookupCache::lookup(&nm->key);
        if (!result.matches(nm)) {
          replace(result, receiver_klass);
        }
      }
      break;
    case Bytecodes::megamorphic_send:
      // Note that with the current definition of is_empty()
      // this will not be called for normal megamorphic sends
      // since they store only the selector.
      { klassOop receiver_klass = klassOop(second_word());
      if (first_word()->is_smi()) {
        jumpTableEntry* entry = (jumpTableEntry*) first_word();
        nmethod* nm = entry->method();
        LookupResult result = lookupCache::lookup(&nm->key);
        if (!result.matches(nm)) {
          replace(result, receiver_klass);
        }
      } else {
        methodOop method = methodOop(first_word());
        assert(method->is_method(), "first word in interpreter IC must be method");
        if (!Bytecodes::is_super_send(send_code())) {
          // super sends cannot be handled since the sending method holder is unknown at this point.
          LookupKey key(receiver_klass, selector());
          LookupResult result = lookupCache::lookup(&key);
          if (!result.matches(method)) {
            replace(result, receiver_klass);
          }
        }
      }
      }
      break;
    case Bytecodes::polymorphic_send:
      {
        // %implementation note:
        //   when cleaning up we can always preserve the old pic since the
        //   the only transitions are:
        //     (compiled    -> compiled)
        //     (compiled    -> interpreted)
        //     (interpreted -> compiled)
        //   in case of a super send we do not have to cleanup because
        //   no nmethods are compiled for super sends.
        if (!Bytecodes::is_super_send(send_code())) {
          objArrayOop pic = pic_array();
          for (int index = pic->length(); index > 0; index -= 2) {
            klassOop klass = klassOop(pic->obj_at(index));
            assert(klass->is_klass(), "receiver klass must be klass");
            oop first = pic->obj_at(index-1);
            if (first->is_smi()) {
              jumpTableEntry* entry = (jumpTableEntry*) first;
              nmethod* nm = entry->method();
              LookupResult result = lookupCache::lookup(&nm->key);
              if (!result.matches(nm)) {
                pic->obj_at_put(index-1, result.value());
              }
            } else {
              methodOop method = methodOop(first);
              assert(method->is_method(), "first word in interpreter IC must be method");
              LookupKey key(klass, selector());
              LookupResult result = lookupCache::lookup(&key);
              if (!result.matches(method)) {
                pic->obj_at_put(index-1, result.value());
              }
            }
          }
        }
      }
  }
}
예제 #15
0
jumpTableEntry* InterpretedIC::jump_table_entry() const {
  assert(send_type() == Bytecodes::compiled_send ||
    send_type() == Bytecodes::megamorphic_send, "must be a compiled call");
  assert(first_word()->is_smi(), "must be smi");
  return (jumpTableEntry*) first_word();
}
예제 #16
0
int manager_read_resolv_conf(Manager *m) {
        _cleanup_fclose_ FILE *f = NULL;
        struct stat st, own;
        char line[LINE_MAX];
        usec_t t;
        int r;

        assert(m);

        /* Reads the system /etc/resolv.conf, if it exists and is not
         * symlinked to our own resolv.conf instance */

        if (!m->read_resolv_conf)
                return 0;

        r = stat("/etc/resolv.conf", &st);
        if (r < 0) {
                if (errno == ENOENT)
                        return 0;

                r = log_warning_errno(errno, "Failed to stat /etc/resolv.conf: %m");
                goto clear;
        }

        /* Have we already seen the file? */
        t = timespec_load(&st.st_mtim);
        if (t == m->resolv_conf_mtime)
                return 0;

        /* Is it symlinked to our own file? */
        if (stat(PRIVATE_RESOLV_CONF, &own) >= 0 &&
            st.st_dev == own.st_dev &&
            st.st_ino == own.st_ino)
                return 0;

        f = fopen("/etc/resolv.conf", "re");
        if (!f) {
                if (errno == ENOENT)
                        return 0;

                r = log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
                goto clear;
        }

        if (fstat(fileno(f), &st) < 0) {
                r = log_error_errno(errno, "Failed to stat open file: %m");
                goto clear;
        }

        dns_server_mark_all(m->dns_servers);
        dns_search_domain_mark_all(m->search_domains);

        FOREACH_LINE(line, f, r = -errno; goto clear) {
                const char *a;
                char *l;

                l = strstrip(line);
                if (IN_SET(*l, '#', ';'))
                        continue;

                a = first_word(l, "nameserver");
                if (a) {
                        r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_SYSTEM, a);
                        if (r < 0)
                                log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);

                        continue;
                }

                a = first_word(l, "domain");
                if (!a) /* We treat "domain" lines, and "search" lines as equivalent, and add both to our list. */
                        a = first_word(l, "search");
                if (a) {
                        r = manager_parse_search_domains_and_warn(m, a);
                        if (r < 0)
                                log_warning_errno(r, "Failed to parse search domain string '%s', ignoring.", a);
                }
        }

        m->resolv_conf_mtime = t;

        /* Flush out all servers and search domains that are still
         * marked. Those are then ones that didn't appear in the new
         * /etc/resolv.conf */
        dns_server_unlink_marked(m->dns_servers);
        dns_search_domain_unlink_marked(m->search_domains);

        /* Whenever /etc/resolv.conf changes, start using the first
         * DNS server of it. This is useful to deal with broken
         * network managing implementations (like NetworkManager),
         * that when connecting to a VPN place both the VPN DNS
         * servers and the local ones in /etc/resolv.conf. Without
         * resetting the DNS server to use back to the first entry we
         * will continue to use the local one thus being unable to
         * resolve VPN domains. */
        manager_set_dns_server(m, m->dns_servers);

        /* Unconditionally flush the cache when /etc/resolv.conf is
         * modified, even if the data it contained was completely
         * identical to the previous version we used. We do this
         * because altering /etc/resolv.conf is typically done when
         * the network configuration changes, and that should be
         * enough to flush the global unicast DNS cache. */
        if (m->unicast_scope)
                dns_cache_flush(&m->unicast_scope->cache);

        /* If /etc/resolv.conf changed, make sure to forget everything we learned about the DNS servers. After all we
         * might now talk to a very different DNS server that just happens to have the same IP address as an old one
         * (think 192.168.1.1). */
        dns_server_reset_features_all(m->dns_servers);

        return 0;

clear:
        dns_server_unlink_all(m->dns_servers);
        dns_search_domain_unlink_all(m->search_domains);
        return r;
}
예제 #17
0
static int process(
                const char *controller,
                const char *path,
                Hashmap *a,
                Hashmap *b,
                unsigned iteration,
                Group **ret) {

        Group *g;
        int r;

        assert(controller);
        assert(path);
        assert(a);

        g = hashmap_get(a, path);
        if (!g) {
                g = hashmap_get(b, path);
                if (!g) {
                        g = new0(Group, 1);
                        if (!g)
                                return -ENOMEM;

                        g->path = strdup(path);
                        if (!g->path) {
                                group_free(g);
                                return -ENOMEM;
                        }

                        r = hashmap_put(a, g->path, g);
                        if (r < 0) {
                                group_free(g);
                                return r;
                        }
                } else {
                        r = hashmap_move_one(a, b, path);
                        if (r < 0)
                                return r;

                        g->cpu_valid = g->memory_valid = g->io_valid = g->n_tasks_valid = false;
                }
        }

        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
                _cleanup_fclose_ FILE *f = NULL;
                pid_t pid;

                r = cg_enumerate_processes(controller, path, &f);
                if (r == -ENOENT)
                        return 0;
                if (r < 0)
                        return r;

                g->n_tasks = 0;
                while (cg_read_pid(f, &pid) > 0) {

                        if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0)
                                continue;

                        g->n_tasks++;
                }

                if (g->n_tasks > 0)
                        g->n_tasks_valid = true;

        } else if (streq(controller, "pids") && arg_count == COUNT_PIDS) {
                _cleanup_free_ char *p = NULL, *v = NULL;

                r = cg_get_path(controller, path, "pids.current", &p);
                if (r < 0)
                        return r;

                r = read_one_line_file(p, &v);
                if (r == -ENOENT)
                        return 0;
                if (r < 0)
                        return r;

                r = safe_atou64(v, &g->n_tasks);
                if (r < 0)
                        return r;

                if (g->n_tasks > 0)
                        g->n_tasks_valid = true;

        } else if (streq(controller, "cpu") || streq(controller, "cpuacct")) {
                _cleanup_free_ char *p = NULL, *v = NULL;
                uint64_t new_usage;
                nsec_t timestamp;

                if (cg_all_unified() > 0) {
                        const char *keys[] = { "usage_usec", NULL };
                        _cleanup_free_ char *val = NULL;

                        if (!streq(controller, "cpu"))
                                return 0;

                        r = cg_get_keyed_attribute("cpu", path, "cpu.stat", keys, &val);
                        if (r == -ENOENT)
                                return 0;
                        if (r < 0)
                                return r;

                        r = safe_atou64(val, &new_usage);
                        if (r < 0)
                                return r;

                        new_usage *= NSEC_PER_USEC;
                } else {
                        if (!streq(controller, "cpuacct"))
                                return 0;

                        r = cg_get_path(controller, path, "cpuacct.usage", &p);
                        if (r < 0)
                                return r;

                        r = read_one_line_file(p, &v);
                        if (r == -ENOENT)
                                return 0;
                        if (r < 0)
                                return r;

                        r = safe_atou64(v, &new_usage);
                        if (r < 0)
                                return r;
                }

                timestamp = now_nsec(CLOCK_MONOTONIC);

                if (g->cpu_iteration == iteration - 1 &&
                    (nsec_t) new_usage > g->cpu_usage) {

                        nsec_t x, y;

                        x = timestamp - g->cpu_timestamp;
                        if (x < 1)
                                x = 1;

                        y = (nsec_t) new_usage - g->cpu_usage;
                        g->cpu_fraction = (double) y / (double) x;
                        g->cpu_valid = true;
                }

                g->cpu_usage = (nsec_t) new_usage;
                g->cpu_timestamp = timestamp;
                g->cpu_iteration = iteration;

        } else if (streq(controller, "memory")) {
                _cleanup_free_ char *p = NULL, *v = NULL;

                if (cg_all_unified() <= 0)
                        r = cg_get_path(controller, path, "memory.usage_in_bytes", &p);
                else
                        r = cg_get_path(controller, path, "memory.current", &p);
                if (r < 0)
                        return r;

                r = read_one_line_file(p, &v);
                if (r == -ENOENT)
                        return 0;
                if (r < 0)
                        return r;

                r = safe_atou64(v, &g->memory);
                if (r < 0)
                        return r;

                if (g->memory > 0)
                        g->memory_valid = true;

        } else if ((streq(controller, "io") && cg_all_unified() > 0) ||
                   (streq(controller, "blkio") && cg_all_unified() <= 0)) {
                _cleanup_fclose_ FILE *f = NULL;
                _cleanup_free_ char *p = NULL;
                bool unified = cg_all_unified() > 0;
                uint64_t wr = 0, rd = 0;
                nsec_t timestamp;

                r = cg_get_path(controller, path, unified ? "io.stat" : "blkio.io_service_bytes", &p);
                if (r < 0)
                        return r;

                f = fopen(p, "re");
                if (!f) {
                        if (errno == ENOENT)
                                return 0;
                        return -errno;
                }

                for (;;) {
                        char line[LINE_MAX], *l;
                        uint64_t k, *q;

                        if (!fgets(line, sizeof(line), f))
                                break;

                        /* Trim and skip the device */
                        l = strstrip(line);
                        l += strcspn(l, WHITESPACE);
                        l += strspn(l, WHITESPACE);

                        if (unified) {
                                while (!isempty(l)) {
                                        if (sscanf(l, "rbytes=%" SCNu64, &k))
                                                rd += k;
                                        else if (sscanf(l, "wbytes=%" SCNu64, &k))
                                                wr += k;

                                        l += strcspn(l, WHITESPACE);
                                        l += strspn(l, WHITESPACE);
                                }
                        } else {
                                if (first_word(l, "Read")) {
                                        l += 4;
                                        q = &rd;
                                } else if (first_word(l, "Write")) {
                                        l += 5;
                                        q = &wr;
                                } else
                                        continue;

                                l += strspn(l, WHITESPACE);
                                r = safe_atou64(l, &k);
                                if (r < 0)
                                        continue;

                                *q += k;
                        }
                }

                timestamp = now_nsec(CLOCK_MONOTONIC);

                if (g->io_iteration == iteration - 1) {
                        uint64_t x, yr, yw;

                        x = (uint64_t) (timestamp - g->io_timestamp);
                        if (x < 1)
                                x = 1;

                        if (rd > g->io_input)
                                yr = rd - g->io_input;
                        else
                                yr = 0;

                        if (wr > g->io_output)
                                yw = wr - g->io_output;
                        else
                                yw = 0;

                        if (yr > 0 || yw > 0) {
                                g->io_input_bps = (yr * 1000000000ULL) / x;
                                g->io_output_bps = (yw * 1000000000ULL) / x;
                                g->io_valid = true;
                        }
                }

                g->io_input = rd;
                g->io_output = wr;
                g->io_timestamp = timestamp;
                g->io_iteration = iteration;
        }

        if (ret)
                *ret = g;

        return 0;
}
예제 #18
0
static void
child_process (entry * e, user * u)
{
  int stdin_pipe[2], stdout_pipe[2];
  register char *input_data;
  char *usernm, *mailto;
  int verbose;			/* Put lots of info about job in the output mail msg */
  int children = 0;

  Debug (DPROC, ("[%d] child_process('%s')\n", getpid (), e->cmd));
  /* mark ourselves as different to PS command watchers by upshifting
   * our process name.  This has no effect on some kernels.
   */
  /*local */
  {
    register char *pch;

    for (pch = ProcessName; *pch; pch++)
      *pch = MkUpper (*pch);
  }

  /* discover some useful and important environment settings
   */
  usernm = env_get ("LOGNAME", e->envp);
  mailto = env_get ("MAILTO", e->envp);

  /* The environment variable CRON_VERBOSE is normally set in the crontab
     itself.  It means user wants lots of info in the mail message to the cron
     job owner, including the full environment.
   */
  if (env_get ("CRON_VERBOSE", e->envp))
    verbose = 1;
  else
    verbose = 0;

  /* Check for arguments */
  if (mailto)
    {
      const char *end;

      /* These chars have to match those cron_popen()
       * uses to split the command string */
      mailto += strspn (mailto, " \t\n");
      end = mailto + strcspn (mailto, " \t\n");
      if (*mailto == '-' || *end != '\0')
	{
	  printf ("Bad Mailto karma.\n");
	  log_it ("CRON", getpid (), "error", "bad mailto");
	  mailto = NULL;
	}
    }

#ifdef USE_SIGCHLD
  /* our parent is watching for our death by catching SIGCHLD.  we
   * do not care to watch for our children's deaths this way -- we
   * use wait() explictly.  so we have to disable the signal (which
   * was inherited from the parent).
   */
  (void) signal (SIGCHLD, SIG_IGN);
#else
  /* on system-V systems, we are ignoring SIGCHLD.  we have to stop
   * ignoring it now or the wait() in cron_pclose() won't work.
   * because of this, we have to wait() for our children here, as well.
   */
  (void) signal (SIGCHLD, SIG_DFL);
#endif /* USE_SIGCHLD */

  /* create some pipes to talk to our future child
   */
  pipe (stdin_pipe);		/* child's stdin */
  pipe (stdout_pipe);		/* child's stdout */

  /* since we are a forked process, we can diddle the command string
   * we were passed -- nobody else is going to use it again, right?
   *
   * if a % is present in the command, previous characters are the
   * command, and subsequent characters are the additional input to
   * the command.  Subsequent %'s will be transformed into newlines,
   * but that happens later.
   */
  /*local */
  {
    register int escaped = FALSE;
    register int ch;

    for (input_data = e->cmd; (ch = *input_data); input_data++)
      {
	if (escaped)
	  {
	    escaped = FALSE;
	    continue;
	  }
	if (ch == '\\')
	  {
	    escaped = TRUE;
	    continue;
	  }
	if (ch == '%')
	  {
	    *input_data++ = '\0';
	    break;
	  }
      }
  }

  /* fork again, this time so we can exec the user's command.
   */
  switch (vfork ())
    {
    case -1:
      log_it ("CRON", getpid (), "error", "can't vfork");
      exit (ERROR_EXIT);
     /*NOTREACHED*/ case 0:
      Debug (DPROC, ("[%d] grandchild process Vfork()'ed\n", getpid ()));
      /* write a log message.  we've waited this long to do it
       * because it was not until now that we knew the PID that
       * the actual user command shell was going to get and the
       * PID is part of the log message.
       */
      /*local */
      {
	char *x = mkprints ((u_char *) e->cmd, strlen (e->cmd));

	log_it (usernm, getpid (), "CMD", x);
	free (x);
      }

      /* that's the last thing we'll log.  close the log files.
       */
#ifdef HAVE_SYSLOG_H
      if (log_syslog)
	closelog ();
#endif

      /* get new pgrp, void tty, etc.
       */
      (void) setsid ();

      /* close the pipe ends that we won't use.  this doesn't affect
       * the parent, who has to read and write them; it keeps the
       * kernel from recording us as a potential client TWICE --
       * which would keep it from sending SIGPIPE in otherwise
       * appropriate circumstances.
       */
      close (stdin_pipe[WRITE_PIPE]);
      close (stdout_pipe[READ_PIPE]);

      /* grandchild process.  make std{in,out} be the ends of
       * pipes opened by our daddy; make stderr go to stdout.
       */
      close (STDIN);
      dup2 (stdin_pipe[READ_PIPE], STDIN);
      close (STDOUT);
      dup2 (stdout_pipe[WRITE_PIPE], STDOUT);
      close (STDERR);
      dup2 (STDOUT, STDERR);

      /* close the pipes we just dup'ed.  The resources will remain.
       */
      close (stdin_pipe[READ_PIPE]);
      close (stdout_pipe[WRITE_PIPE]);

      /* set our directory, uid and gid.  Set gid first, since once
       * we set uid, we've lost root privledges.
       */
      setgid (e->gid);
#ifdef HAVE_INITGROUPS
      initgroups (env_get ("LOGNAME", e->envp), e->gid);
#endif
      setuid (e->uid);		/* we aren't root after this... */
      chdir (env_get ("HOME", e->envp));

      /* exec the command.
       */
      {
	char *shell = env_get ("SHELL", e->envp);

#if DEBUGGING
	if (DebugFlags & DTEST)
	  {
	    fprintf (stderr, "debug DTEST is on, not exec'ing command.\n");
	    fprintf (stderr, "\tcmd='%s' shell='%s'\n", e->cmd, shell);
	    _exit (OK_EXIT);
	  }
#endif	 /*DEBUGGING*/
#ifdef USE_SIGCHLD
	  /* Our grandparent is watching for our parent's death by
	   * catching SIGCHLD. Meanwhile, our parent will use wait
	   * explicitly and so has disabled SIGCHLD. So now it's
	   * time to reset SIGCHLD handling.
	   */
	(void) signal (SIGCHLD, SIG_DFL);
#endif
	execle (shell, shell, "-c", e->cmd, (char *) 0, e->envp);
	fprintf (stderr, "execl: couldn't exec `%s'\n", shell);
	perror ("execl");

	execle (shell, shell, "-c", e->cmd, (char *) 0, e->envp);
	fprintf (stderr, "execl: couldn't exec `%s'\n", shell);
	perror ("execl");
	_exit (ERROR_EXIT);
      }
      break;
    default:
      /* parent process */
      break;
    }

  children++;

  /* middle process, child of original cron, parent of process running
   * the user's command.
   */

  Debug (DPROC, ("[%d] child continues, closing pipes\n", getpid ()));
  /* close the ends of the pipe that will only be referenced in the
   * grandchild process...
   */
  close (stdin_pipe[READ_PIPE]);
  close (stdout_pipe[WRITE_PIPE]);

  /*
   * write, to the pipe connected to child's stdin, any input specified
   * after a % in the crontab entry.  while we copy, convert any
   * additional %'s to newlines.  when done, if some characters were
   * written and the last one wasn't a newline, write a newline.
   *
   * Note that if the input data won't fit into one pipe buffer (2K
   * or 4K on most BSD systems), and the child doesn't read its stdin,
   * we would block here.  thus we must fork again.
   */

  if (*input_data && fork () == 0)
    {
      register FILE *out = fdopen (stdin_pipe[WRITE_PIPE], "w");
      register int need_newline = FALSE;
      register int escaped = FALSE;
      register int ch;

      Debug (DPROC, ("[%d] child2 sending data to grandchild\n", getpid ()));
      /* close the pipe we don't use, since we inherited it and
       * are part of its reference count now.
       */
      close (stdout_pipe[READ_PIPE]);

      /* translation:
       *      \% -> %
       *      %  -> \n
       *      \x -> \x        for all x != %
       */
      while ((ch = *input_data++))
	{
	  if (escaped)
	    {
	      if (ch != '%')
		putc ('\\', out);
	    }
	  else
	    {
	      if (ch == '%')
		ch = '\n';
	    }

	  if (!(escaped = (ch == '\\')))
	    {
	      putc (ch, out);
	      need_newline = (ch != '\n');
	    }
	}
      if (escaped)
	putc ('\\', out);
      if (need_newline)
	putc ('\n', out);

      /* close the pipe, causing an EOF condition.  fclose causes
       * stdin_pipe[WRITE_PIPE] to be closed, too.
       */
      fclose (out);

      Debug (DPROC, ("[%d] child2 done sending to grandchild\n", getpid ()));
      exit (0);
    }

  /* close the pipe to the grandkiddie's stdin, since its wicked uncle
   * ernie back there has it open and will close it when he's done.
   */
  close (stdin_pipe[WRITE_PIPE]);

  children++;

  /*
   * read output from the grandchild.  it's stderr has been redirected to
   * it's stdout, which has been redirected to our pipe.  if there is any
   * output, we'll be mailing it to the user whose crontab this is...
   * when the grandchild exits, we'll get EOF.
   */

  Debug (DPROC, ("[%d] child reading output from grandchild\n", getpid ()));
  /*local */
  {
    char mailcmd[MAX_COMMAND];
    register FILE *in = fdopen (stdout_pipe[READ_PIPE], "r");
    register int ch = getc (in);

    if (ch != EOF)
      {
	register FILE *mail;
	register int bytes = 1;
	int status = 0;

	Debug (DPROC | DEXT,
	       ("[%d] got data (%x:%c) from grandchild\n", getpid (), ch,
		ch));
	/* get name of recipient.  this is MAILTO if set to a
	 * valid local username; USER otherwise.
	 */
	if (mailto)
	  {
	    /* MAILTO was present in the environment
	     */
	    if (!*mailto)
	      {
		/* ... but it's empty. set to NULL
		 */
		mailto = NULL;
	      }
	  }
	else
	  {
	    /* MAILTO not present, set to USER.
	     */
	    mailto = usernm;
	  }

	/* if we are supposed to be mailing, MAILTO will
	 * be non-NULL.  only in this case should we set
	 * up the mail command and subjects and stuff...
	 */

	if (mailto)
	  {
	    register char **env;
	    auto char hostname[MAXHOSTNAMELEN];

	    (void) gethostname (hostname, MAXHOSTNAMELEN);
	    (void) snprintf (mailcmd, MAX_COMMAND, mailargs, mailprog, mailto);
	    if (!(mail = cron_popen (mailcmd, "w", e)))
	      {
		fprintf (stderr,
			 "Unable to create process to mail job results.\n"
			 "Mail command was: '%s'.  \n"
			 "popen() returned errno %s (%d).\n", mailcmd,
			 strerror (errno), errno);

		(void) _exit (ERROR_EXIT);
	      }
	    fprintf (mail, "From: root (Cron Daemon)\n");
	    fprintf (mail, "To: %s\n", mailto);
	    fprintf (mail, "Subject: Cron <%s@%s> %s\n",
		     usernm, first_word (hostname, "."), e->cmd);
# if defined(MAIL_DATE)
	    fprintf (mail, "Date: %s\n", arpadate (&TargetTime));
# endif	/* MAIL_DATE */
	    if (verbose)
	      {
		for (env = e->envp; *env; env++)
		  fprintf (mail, "X-Cron-Env: <%s>\n", *env);
	      }
	    fprintf (mail, "\n");

	    /* this was the first char from the pipe
	     */
	    putc (ch, mail);
	  }

	/* we have to read the input pipe no matter whether
	 * we mail or not, but obviously we only write to
	 * mail pipe if we ARE mailing.
	 */

	while (EOF != (ch = getc (in)))
	  {
	    bytes++;
	    if (mailto)
	      putc (ch, mail);
	  }

	/* only close pipe if we opened it -- i.e., we're
	 * mailing...
	 */

	if (mailto)
	  {
	    Debug (DPROC, ("[%d] closing pipe to mail\n", getpid ()));
	    /* Note: the pclose will probably see
	     * the termination of the grandchild
	     * in addition to the mail process, since
	     * it (the grandchild) is likely to exit
	     * after closing its stdout.
	     */
	    status = cron_pclose (mail);
	  }

	/* if there was output and we could not mail it,
	 * log the facts so the poor user can figure out
	 * what's going on.
	 */
	if (mailto && status)
	  {
	    char buf[MAX_TEMPSTR];

	    snprintf (buf, MAX_TEMPSTR,
		      "mailed %d byte%s of output but got status 0x%04x.\n"
		      "mail command was '%s'\n",
		      bytes, (bytes == 1) ? "" : "s", status, mailcmd);
	    log_it (usernm, getpid (), "MAIL", buf);
	  }

      }				/*if data from grandchild */

    Debug (DPROC, ("[%d] got EOF from grandchild\n", getpid ()));
    fclose (in);		/* also closes stdout_pipe[READ_PIPE] */
  }


  /* wait for children to die.
   */
  for (; children > 0; children--)
    {
      WAIT_T waiter;
      pid_t pid;

      Debug (DPROC, ("[%d] waiting for grandchild #%d to finish\n",
		     getpid (), children));
      pid = wait (&waiter);
      if (pid < OK)
	{
	  Debug (DPROC, ("[%d] no more grandchildren--mail written?\n",
			 getpid ()));
	  break;
	}
      Debug (DPROC, ("[%d] grandchild #%d finished, status=%04x",
		     getpid (), pid, WEXITSTATUS (waiter)));
      if (WIFSIGNALED (waiter) && WCOREDUMP (waiter))
	Debug (DPROC, (", dumped core"));
      Debug (DPROC, ("\n"));
    }
}