Fix: reintroduce lazy kernel modules load, fix empty syscall list
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 23 May 2019 19:11:50 +0000 (15:11 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 5 Sep 2019 20:39:16 +0000 (16:39 -0400)
Up and including to lttng 2.10, if the lttng-modules are not available
when the session daemon starts, an attempt is made to load them each
time a command attempts to interact with the kernel domain.

2.11-rc introduces a change in behavior which removes this lazy
initialization. This is an issue for distribution packaging (e.g.
Ubuntu) where there is no strong dependency between lttng-tools and
lttng-modules (because either are optional). So we can be unlucky and
find ourselves in a situation where the modules are not available when
the session daemon is launched at installation, but only afterwards.

Re-introduce the lazy kernel module load behavior, since this is
expected by users.

Also, fix an issue with empty syscall list in those lazy initialization
scenario by moving invocation of syscall_init_table() from main() to
init_kernel_tracer().

While we are there, cleanup the following in session daemon:

- move kernel_tracer_fd from globals.c to kernel.c. It becomes a static
  variable,
- move module_proc_lttng from main.c to kernel.c,
- move init_kernel_tracer() from main.c to kernel.c,
- introduce kernel.c:cleanup_kernel_tracer(), invoke it from program
  cleanup,
- introduce kernel_tracer_is_initialized() to check the state of
  kernel tracer initialization,
- adapt kernel.c functions to use the static kernel_tracer_fd rather
  than expect it as parameter,
- update syscall_init_table, invoked from kernel.c, to pass the
  kernel_tracer_fd as parameter.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/globals.c
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/kernel.h
src/bin/lttng-sessiond/lttng-sessiond.h
src/bin/lttng-sessiond/lttng-syscall.c
src/bin/lttng-sessiond/lttng-syscall.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/notification-thread-events.c

index 02eac96e422f8c8f3067df10c7c040c9eb1d02cd..7b7642ea76baf2e20e759f618742ab5c0a06d688 100644 (file)
@@ -478,7 +478,7 @@ static int create_kernel_session(struct ltt_session *session)
 
        DBG("Creating kernel session");
 
-       ret = kernel_create_session(session, kernel_tracer_fd);
+       ret = kernel_create_session(session);
        if (ret < 0) {
                ret = LTTNG_ERR_KERN_SESS_FAIL;
                goto error_create;
@@ -879,6 +879,15 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
                        goto error;
                }
 
+               /* Kernel tracer check */
+               if (!kernel_tracer_is_initialized()) {
+                       /* Basically, load kernel tracer modules */
+                       ret = init_kernel_tracer();
+                       if (ret != 0) {
+                               goto error;
+                       }
+               }
+
                /* Consumer is in an ERROR state. Report back to client */
                if (uatomic_read(&kernel_consumerd_state) == CONSUMER_ERROR) {
                        ret = LTTNG_ERR_NO_KERNCONSUMERD;
index 1b73978f27f0e81d671987f05ae851e70e5acf47..82d92070398119fd60fce36adb55d17eb2aafc19 100644 (file)
@@ -1252,7 +1252,7 @@ error:
 /*
  * Start a kernel session by opening all necessary streams.
  */
-static int start_kernel_session(struct ltt_kernel_session *ksess, int wpipe)
+static int start_kernel_session(struct ltt_kernel_session *ksess)
 {
        int ret;
        struct ltt_kernel_channel *kchan;
@@ -1304,7 +1304,7 @@ static int start_kernel_session(struct ltt_kernel_session *ksess, int wpipe)
        }
 
        /* Quiescent wait after starting trace */
-       kernel_wait_quiescent(wpipe);
+       kernel_wait_quiescent();
 
        ksess->active = 1;
 
@@ -1336,7 +1336,7 @@ int cmd_disable_channel(struct ltt_session *session,
                        goto error;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -1394,7 +1394,7 @@ int cmd_track_pid(struct ltt_session *session, enum lttng_domain_type domain,
                        goto error;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -1445,7 +1445,7 @@ int cmd_untrack_pid(struct ltt_session *session, enum lttng_domain_type domain,
                        goto error;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -1525,7 +1525,7 @@ int cmd_enable_channel(struct ltt_session *session,
        switch (domain->type) {
        case LTTNG_DOMAIN_KERNEL:
        {
-               if (kernel_supports_ring_buffer_snapshot_sample_positions(kernel_tracer_fd) != 1) {
+               if (kernel_supports_ring_buffer_snapshot_sample_positions() != 1) {
                        /* Sampling position of buffer is not supported */
                        WARN("Kernel tracer does not support buffer monitoring. "
                                        "Setting the monitor interval timer to 0 "
@@ -1576,7 +1576,7 @@ int cmd_enable_channel(struct ltt_session *session,
                        goto error;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -1711,7 +1711,7 @@ int cmd_disable_event(struct ltt_session *session,
                        goto error_unlock;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -2161,7 +2161,7 @@ static int _cmd_enable_event(struct ltt_session *session,
                        goto error;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -2429,7 +2429,7 @@ ssize_t cmd_list_tracepoints(enum lttng_domain_type domain,
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
-               nb_events = kernel_list_events(kernel_tracer_fd, events);
+               nb_events = kernel_list_events(events);
                if (nb_events < 0) {
                        ret = LTTNG_ERR_KERN_LIST_FAIL;
                        goto error;
@@ -2609,7 +2609,7 @@ int cmd_start_trace(struct ltt_session *session)
        /* Kernel tracing */
        if (ksession != NULL) {
                DBG("Start kernel tracing session %s", session->name);
-               ret = start_kernel_session(ksession, kernel_tracer_fd);
+               ret = start_kernel_session(ksession);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -2686,7 +2686,7 @@ int cmd_stop_trace(struct ltt_session *session)
                        goto error;
                }
 
-               kernel_wait_quiescent(kernel_tracer_fd);
+               kernel_wait_quiescent();
 
                /* Flush metadata after stopping (if exists) */
                if (ksession->metadata_stream_fd >= 0) {
index a8536afa36a90d63146ccf1c3cb3e49265815097..ef57a960dd47365b87c6f506d7f1220cb974886d 100644 (file)
@@ -33,7 +33,6 @@ struct notification_thread_handle *notification_thread_handle;
 
 struct lttng_ht *agent_apps_ht_by_sock = NULL;
 
-int kernel_tracer_fd = -1;
 struct lttng_kernel_tracer_version kernel_tracer_version;
 struct lttng_kernel_tracer_abi_version kernel_tracer_abi_version;
 
index 53072f97187654dc37db1b6042f8100b375cbb70..b79503b7d0185fd90b076c705f54ae6b90b8b3c2 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <inttypes.h>
+#include <sys/types.h>
 
 #include <common/common.h>
 #include <common/trace-chunk.h>
 #include <common/kernel-ctl/kernel-ioctl.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 
+#include "lttng-sessiond.h"
+#include "lttng-syscall.h"
 #include "consumer.h"
 #include "kernel.h"
 #include "kernel-consumer.h"
 #include "kern-modules.h"
 #include "utils.h"
 #include "rotate.h"
+#include "modprobe.h"
 
 /*
  * Key used to reference a channel between the sessiond and the consumer. This
  */
 static uint64_t next_kernel_channel_key;
 
+static const char *module_proc_lttng = "/proc/lttng";
+
+static int kernel_tracer_fd = -1;
+
 #include <lttng/userspace-probe.h>
 #include <lttng/userspace-probe-internal.h>
 /*
@@ -92,7 +100,7 @@ error:
  * Create a new kernel session, register it to the kernel tracer and add it to
  * the session daemon session.
  */
-int kernel_create_session(struct ltt_session *session, int tracer_fd)
+int kernel_create_session(struct ltt_session *session)
 {
        int ret;
        struct ltt_kernel_session *lks;
@@ -107,7 +115,7 @@ int kernel_create_session(struct ltt_session *session, int tracer_fd)
        }
 
        /* Kernel tracer session creation */
-       ret = kernctl_create_session(tracer_fd);
+       ret = kernctl_create_session(kernel_tracer_fd);
        if (ret < 0) {
                PERROR("ioctl kernel create session");
                goto error;
@@ -836,9 +844,10 @@ error:
 /*
  * Make a kernel wait to make sure in-flight probe have completed.
  */
-void kernel_wait_quiescent(int fd)
+void kernel_wait_quiescent(void)
 {
        int ret;
+       int fd = kernel_tracer_fd;
 
        DBG("Kernel quiescent wait on %d", fd);
 
@@ -997,7 +1006,7 @@ error:
 /*
  * Get the event list from the kernel tracer and return the number of elements.
  */
-ssize_t kernel_list_events(int tracer_fd, struct lttng_event **events)
+ssize_t kernel_list_events(struct lttng_event **events)
 {
        int fd, ret;
        char *event;
@@ -1007,7 +1016,7 @@ ssize_t kernel_list_events(int tracer_fd, struct lttng_event **events)
 
        assert(events);
 
-       fd = kernctl_tracepoint_list(tracer_fd);
+       fd = kernctl_tracepoint_list(kernel_tracer_fd);
        if (fd < 0) {
                PERROR("kernel tracepoint list");
                goto error;
@@ -1081,13 +1090,12 @@ error:
 /*
  * Get kernel version and validate it.
  */
-int kernel_validate_version(int tracer_fd,
-               struct lttng_kernel_tracer_version *version,
+int kernel_validate_version(struct lttng_kernel_tracer_version *version,
                struct lttng_kernel_tracer_abi_version *abi_version)
 {
        int ret;
 
-       ret = kernctl_tracer_version(tracer_fd, version);
+       ret = kernctl_tracer_version(kernel_tracer_fd, version);
        if (ret < 0) {
                ERR("Failed to retrieve the lttng-modules version");
                goto error;
@@ -1099,7 +1107,7 @@ int kernel_validate_version(int tracer_fd,
                        version->major, VERSION_MAJOR);
                goto error_version;
        }
-       ret = kernctl_tracer_abi_version(tracer_fd, abi_version);
+       ret = kernctl_tracer_abi_version(kernel_tracer_fd, abi_version);
        if (ret < 0) {
                ERR("Failed to retrieve lttng-modules ABI version");
                goto error;
@@ -1372,12 +1380,12 @@ int kernel_syscall_mask(int chan_fd, char **syscall_mask, uint32_t *nr_bits)
  * Return 1 on success, 0 when feature is not supported, negative value in case
  * of errors.
  */
-int kernel_supports_ring_buffer_snapshot_sample_positions(int tracer_fd)
+int kernel_supports_ring_buffer_snapshot_sample_positions(void)
 {
        int ret = 0; // Not supported by default
        struct lttng_kernel_tracer_abi_version abi;
 
-       ret = kernctl_tracer_abi_version(tracer_fd, &abi);
+       ret = kernctl_tracer_abi_version(kernel_tracer_fd, &abi);
        if (ret < 0) {
                ERR("Failed to retrieve lttng-modules ABI version");
                goto error;
@@ -1480,3 +1488,109 @@ error:
        rcu_read_unlock();
        return ret;
 }
+
+/*
+ * Setup necessary data for kernel tracer action.
+ */
+LTTNG_HIDDEN
+int init_kernel_tracer(void)
+{
+       int ret;
+       bool is_root = !getuid();
+
+       /* Modprobe lttng kernel modules */
+       ret = modprobe_lttng_control();
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* Open debugfs lttng */
+       kernel_tracer_fd = open(module_proc_lttng, O_RDWR);
+       if (kernel_tracer_fd < 0) {
+               DBG("Failed to open %s", module_proc_lttng);
+               goto error_open;
+       }
+
+       /* Validate kernel version */
+       ret = kernel_validate_version(&kernel_tracer_version,
+                       &kernel_tracer_abi_version);
+       if (ret < 0) {
+               goto error_version;
+       }
+
+       ret = modprobe_lttng_data();
+       if (ret < 0) {
+               goto error_modules;
+       }
+
+       ret = kernel_supports_ring_buffer_snapshot_sample_positions();
+       if (ret < 0) {
+               goto error_modules;
+       }
+
+       if (ret < 1) {
+               WARN("Kernel tracer does not support buffer monitoring. "
+                       "The monitoring timer of channels in the kernel domain "
+                       "will be set to 0 (disabled).");
+       }
+
+       DBG("Kernel tracer fd %d", kernel_tracer_fd);
+
+       ret = syscall_init_table(kernel_tracer_fd);
+       if (ret < 0) {
+               ERR("Unable to populate syscall table. Syscall tracing won't "
+                       "work for this session daemon.");
+       }
+       return 0;
+
+error_version:
+       modprobe_remove_lttng_control();
+       ret = close(kernel_tracer_fd);
+       if (ret) {
+               PERROR("close");
+       }
+       kernel_tracer_fd = -1;
+       return LTTNG_ERR_KERN_VERSION;
+
+error_modules:
+       ret = close(kernel_tracer_fd);
+       if (ret) {
+               PERROR("close");
+       }
+
+error_open:
+       modprobe_remove_lttng_control();
+
+error:
+       WARN("No kernel tracer available");
+       kernel_tracer_fd = -1;
+       if (!is_root) {
+               return LTTNG_ERR_NEED_ROOT_SESSIOND;
+       } else {
+               return LTTNG_ERR_KERN_NA;
+       }
+}
+
+LTTNG_HIDDEN
+void cleanup_kernel_tracer(void)
+{
+       int ret;
+
+       DBG2("Closing kernel fd");
+       if (kernel_tracer_fd >= 0) {
+               ret = close(kernel_tracer_fd);
+               if (ret) {
+                       PERROR("close");
+               }
+               kernel_tracer_fd = -1;
+       }
+       DBG("Unloading kernel modules");
+       modprobe_remove_lttng_all();
+       free(syscall_table);
+}
+
+LTTNG_HIDDEN
+bool kernel_tracer_is_initialized(void)
+{
+       return kernel_tracer_fd >= 0;
+}
index c822e8d768f7acc524ad14c71d53ca689fcccb94..0f1abd1d66eebeb706aee22eb982c225b8bbe9dd 100644 (file)
@@ -34,7 +34,7 @@
 
 int kernel_add_channel_context(struct ltt_kernel_channel *chan,
                struct ltt_kernel_context *ctx);
-int kernel_create_session(struct ltt_session *session, int tracer_fd);
+int kernel_create_session(struct ltt_session *session);
 int kernel_create_channel(struct ltt_kernel_session *session,
                struct lttng_channel *chan);
 int kernel_create_event(struct lttng_event *ev, struct ltt_kernel_channel *channel,
@@ -52,10 +52,9 @@ int kernel_flush_buffer(struct ltt_kernel_channel *channel);
 int kernel_metadata_flush_buffer(int fd);
 int kernel_start_session(struct ltt_kernel_session *session);
 int kernel_stop_session(struct ltt_kernel_session *session);
-ssize_t kernel_list_events(int tracer_fd, struct lttng_event **event_list);
-void kernel_wait_quiescent(int fd);
-int kernel_validate_version(int tracer_fd,
-               struct lttng_kernel_tracer_version *kernel_tracer_version,
+ssize_t kernel_list_events(struct lttng_event **event_list);
+void kernel_wait_quiescent(void);
+int kernel_validate_version(struct lttng_kernel_tracer_version *kernel_tracer_version,
                struct lttng_kernel_tracer_abi_version *kernel_tracer_abi_version);
 void kernel_destroy_session(struct ltt_kernel_session *ksess);
 void kernel_free_session(struct ltt_kernel_session *ksess);
@@ -70,7 +69,10 @@ enum lttng_error_code kernel_rotate_session(struct ltt_session *session);
 int init_kernel_workarounds(void);
 ssize_t kernel_list_tracker_pids(struct ltt_kernel_session *session,
                int **_pids);
-int kernel_supports_ring_buffer_snapshot_sample_positions(int tracer_fd);
+int kernel_supports_ring_buffer_snapshot_sample_positions(void);
+int init_kernel_tracer(void);
+void cleanup_kernel_tracer(void);
+bool kernel_tracer_is_initialized(void);
 
 enum lttng_error_code kernel_create_channel_subdirectories(
                const struct ltt_kernel_session *ksess);
index 1cd9eeab6b692ddd4c25111b812962e03b403a18..8846262b6b9916fbc14d89ea679fa1a5b3e8669c 100644 (file)
@@ -75,7 +75,6 @@ extern const char default_home_dir[],
        default_global_apps_pipe[];
 
 /* Set in main.c at boot time of the daemon */
-extern int kernel_tracer_fd;
 extern struct lttng_kernel_tracer_version kernel_tracer_version;
 extern struct lttng_kernel_tracer_abi_version kernel_tracer_abi_version;
 
index b73f137b78c270078e6b801488de4cb9e8ba6f0b..2a7d1eaa0f026dee3297236df69c406aa0759db6 100644 (file)
@@ -38,7 +38,7 @@ static size_t syscall_table_nb_entry;
  * Return 0 on success and the syscall table is allocated. On error, a negative
  * value is returned.
  */
-int syscall_init_table(void)
+int syscall_init_table(int tracer_fd)
 {
        int ret, fd, err;
        size_t nbmem;
@@ -51,7 +51,7 @@ int syscall_init_table(void)
 
        DBG3("Syscall init system call table");
 
-       fd = kernctl_syscall_list(kernel_tracer_fd);
+       fd = kernctl_syscall_list(tracer_fd);
        if (fd < 0) {
                ret = fd;
                PERROR("kernelctl syscall list");
index a2708619c1357ff40c0bde20b112d25e5213e673..50da7cc74e281470441e34ae9b72e77ea1f42a4e 100644 (file)
@@ -51,7 +51,7 @@ struct syscall {
 extern struct syscall *syscall_table;
 
 /* Use to list kernel system calls. */
-int syscall_init_table(void);
+int syscall_init_table(int tracer_fd);
 ssize_t syscall_table_list(struct lttng_event **events);
 
 #endif /* LTTNG_SYSCALL_H */
index f698fae4c634be7b3445d9dc0e6d29253352f549..5f99bdbf63b66c01bb70d54a9839170b0e67d487 100644 (file)
@@ -61,7 +61,6 @@
 #include "event.h"
 #include "kernel.h"
 #include "kernel-consumer.h"
-#include "modprobe.h"
 #include "shm.h"
 #include "ust-ctl.h"
 #include "ust-consumer.h"
@@ -75,7 +74,6 @@
 #include "notification-thread.h"
 #include "notification-thread-commands.h"
 #include "rotation-thread.h"
-#include "lttng-syscall.h"
 #include "agent.h"
 #include "ht-cleanup.h"
 #include "sessiond-config.h"
@@ -155,8 +153,6 @@ static int apps_cmd_notify_pipe[2] = { -1, -1 };
  */
 static struct ust_cmd_queue ust_cmd_queue;
 
-static const char *module_proc_lttng = "/proc/lttng";
-
 /*
  * Section name to look for in the daemon configuration file.
  */
@@ -340,16 +336,7 @@ static void sessiond_cleanup(void)
        wait_consumer(&ustconsumer32_data);
 
        if (is_root && !config.no_kernel) {
-               DBG2("Closing kernel fd");
-               if (kernel_tracer_fd >= 0) {
-                       ret = close(kernel_tracer_fd);
-                       if (ret) {
-                               PERROR("close");
-                       }
-               }
-               DBG("Unloading kernel modules");
-               modprobe_remove_lttng_all();
-               free(syscall_table);
+               cleanup_kernel_tracer();
        }
 
        /*
@@ -371,81 +358,6 @@ static void sessiond_cleanup_options(void)
        run_as_destroy_worker();
 }
 
-/*
- * Setup necessary data for kernel tracer action.
- */
-static int init_kernel_tracer(void)
-{
-       int ret;
-
-       /* Modprobe lttng kernel modules */
-       ret = modprobe_lttng_control();
-       if (ret < 0) {
-               goto error;
-       }
-
-       /* Open debugfs lttng */
-       kernel_tracer_fd = open(module_proc_lttng, O_RDWR);
-       if (kernel_tracer_fd < 0) {
-               DBG("Failed to open %s", module_proc_lttng);
-               goto error_open;
-       }
-
-       /* Validate kernel version */
-       ret = kernel_validate_version(kernel_tracer_fd, &kernel_tracer_version,
-                       &kernel_tracer_abi_version);
-       if (ret < 0) {
-               goto error_version;
-       }
-
-       ret = modprobe_lttng_data();
-       if (ret < 0) {
-               goto error_modules;
-       }
-
-       ret = kernel_supports_ring_buffer_snapshot_sample_positions(
-                       kernel_tracer_fd);
-       if (ret < 0) {
-               goto error_modules;
-       }
-
-       if (ret < 1) {
-               WARN("Kernel tracer does not support buffer monitoring. "
-                       "The monitoring timer of channels in the kernel domain "
-                       "will be set to 0 (disabled).");
-       }
-
-       DBG("Kernel tracer fd %d", kernel_tracer_fd);
-       return 0;
-
-error_version:
-       modprobe_remove_lttng_control();
-       ret = close(kernel_tracer_fd);
-       if (ret) {
-               PERROR("close");
-       }
-       kernel_tracer_fd = -1;
-       return LTTNG_ERR_KERN_VERSION;
-
-error_modules:
-       ret = close(kernel_tracer_fd);
-       if (ret) {
-               PERROR("close");
-       }
-
-error_open:
-       modprobe_remove_lttng_control();
-
-error:
-       WARN("No kernel tracer available");
-       kernel_tracer_fd = -1;
-       if (!is_root) {
-               return LTTNG_ERR_NEED_ROOT_SESSIOND;
-       } else {
-               return LTTNG_ERR_KERN_NA;
-       }
-}
-
 static int string_match(const char *str1, const char *str2)
 {
        return (str1 && str2) && !strcmp(str1, str2);
@@ -1641,14 +1553,6 @@ int main(int argc, char **argv)
                /* Setup kernel tracer */
                if (!config.no_kernel) {
                        init_kernel_tracer();
-                       if (kernel_tracer_fd >= 0) {
-                               ret = syscall_init_table();
-                               if (ret < 0) {
-                                       ERR("Unable to populate syscall table. "
-                                               "Syscall tracing won't work "
-                                               "for this session daemon.");
-                               }
-                       }
                }
 
                /* Set ulimit for open files */
index 052689a0ebd8439dbf11db0172df7eb520c68605..bdbac0c4001f44f218ea0821eab5891972d35043 100644 (file)
@@ -1860,8 +1860,7 @@ int condition_is_supported(struct lttng_condition *condition)
                 * buffers. Therefore, we reject triggers that require that
                 * mechanism to be available to be evaluated.
                 */
-               ret = kernel_supports_ring_buffer_snapshot_sample_positions(
-                               kernel_tracer_fd);
+               ret = kernel_supports_ring_buffer_snapshot_sample_positions();
                break;
        }
        default:
This page took 0.037343 seconds and 4 git commands to generate.