Selaa lähdekoodia

Today Work :)

Vinicius Teshima 3 kuukautta sitten
vanhempi
sitoutus
9dcdbfdfc0
2 muutettua tiedostoa jossa 351 lisäystä ja 74 poistoa
  1. 10 8
      first.c
  2. 341 66
      src/lib.h

+ 10 - 8
first.c

@@ -1,7 +1,9 @@
 #include <stdio.h>
 #include <stdbool.h>
+#include <stdarg.h>
 
 #include <sys/wait.h>
+#include <sys/stat.h>
 
 /* #define STR_SIZE_LIMIT 65536 */
 #define STR_SIZE_LIMIT 5458264
@@ -45,21 +47,21 @@ main(int argc, char *argv[])
 
     struct cmd cmd = {0};
 
+    /*
+    struct procs procs = {0};
+    */
+
+    GO_REBUILD_YOURSELF();
 
-    cmd = cmd_create_ns("/bin/echo", &err);
 
-    cmd_append_arg_ns(&cmd, "This is a test of execve", &err);
+    cmd = cmd_create_ns("ls", &err);
+
+    cmd_append_args_cstrs(&cmd, &err, "-lh", "first.c", "first");
 
     cmd_exec(&cmd, &err);
 
     cmd_destroy(&cmd, &err);
 
-    if ( err != ERR_OK ) {
-        cmd_destroy(&cmd, NULL);
-        fprintf(stderr, "Failed cmd: %s\n", err_to_name[err]);
-        return 1;
-    }
-
     /*
     bool was_rebuild = false;
     struct dyn_arr dirs = {0};

+ 341 - 66
src/lib.h

@@ -47,8 +47,8 @@
 # define UNUSED(arg) (void) arg
 
 enum err {
+    ERR_GENERAL_ERROR = -1,
     ERR_OK = 0,
-    ERR_GENERAL_ERROR,
     ERR_NOT_INT,
     ERR_TOO_BIG,
     ERR_NULL_ARG,
@@ -76,8 +76,8 @@ enum err {
 };
 
 const char *err_to_name[] = {
-    "ERR_OK",
     "ERR_GENERAL_ERROR",
+    "ERR_OK",
     "ERR_NOT_INT",
     "ERR_TOO_BIG",
     "ERR_NULL_ARG",
@@ -122,6 +122,8 @@ typedef unsigned char u8;
 
 /* ------------------------------ END INT DEF ------------------------------ */
 
+extern char **environ;
+
 void *malloc(u64 size);
 void *realloc(void *ptr, u64 new_size);
 void free(void *ptr);
@@ -131,15 +133,19 @@ char *getenv(const char *name);
 void abort(void);
 void exit(int exit_code);
 
-int execve(const char *path, char *const argv[],
-           char *const envp[]);
-
+int execv(const char *path, char *const argv[]);
+int execve(const char *path, char *const argv[], char *const envp[]);
+int execvpe(const char *path, char *const argv[], char *const envp[]);
 
 int fork(void);
 # ifndef WIFEXITED
 #  error "Must import <sys/wait.h> before lib.h!"
 # endif
 
+# if (! defined(_STDARG_H)) || (! defined(va_start))
+#  error "Must import <stdarg.h> before lib.h!"
+# endif
+
 /* ----------------------------- START LIB DEF ----------------------------- */
 
 # define TODO(msg) \
@@ -203,9 +209,11 @@ int fork(void);
 
 # define CAST(Type, Var) ((Type) (Var))
 
-# define LIB_FREE lib_free
+/*# define LIB_FREE lib_free*/
+# define LIB_FREE(Ptr) if ( (Ptr) != NULL ) { free((void *) (Ptr)); }
 
 void lib_free(const void *ptr);
+const char *temp_sprintf(const char *fmt, ...);
 
 # if defined(IMP) || defined(IMP_LIB)
 
@@ -217,6 +225,22 @@ lib_free(const void *ptr)
     free((void *)ptr);
 }
 
+const char *
+temp_sprintf(const char *fmt, ...)
+{
+    static char buf[1024] = {0};
+
+    {
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(buf, 1024, fmt, ap);
+        va_end(ap);
+    }
+    buf[1023] = 0;
+
+    return (const char *) buf;
+}
+
 # endif /* defined(IMP) || defined(IMP_LIB) */
 
 /* ------------------------------ END LIB DEF ------------------------------ */
@@ -575,35 +599,25 @@ dyn_arr_destroy(struct dyn_arr *da, enum err *out_err)
           (VarI) < (Da).size; \
           ++(VarI) )
 
-# define DA_APPEND(da, val, err_var) \
+# define DA_APPEND(Da, Val, OutErr) \
     do { \
-        if ( err_var != NULL ) { \
-            if ( *err_var != ERR_OK ) { \
-                break; \
-            } \
-        } \
-        if ( (da).size + 1 >= (da).cap ) { \
-            (da).cap *= 2; \
-            (da).data = realloc((da).data, (da).cap); \
-            if ( (da).data == NULL ) { \
-                LIB_SET_IF_NOT_NULL((err_var), ERR_FAILED_REALLOC); \
+        if ( (OutErr) != NULL ) { \
+            if ( *(OutErr) != ERR_OK ) { \
                 break; \
             } \
         } \
-        if ( (da).data == NULL ) { \
-            if ( (da).cap == 0 ) { \
-                (da).cap = 32; \
-                (da).size = 0; \
-            } \
-            (da).data = malloc(sizeof(*(da).data) * (da).cap); \
-            if ( (da).data == NULL ) { \
-                LIB_SET_IF_NOT_NULL((err_var), ERR_FAILED_ALLOC); \
+        if ( (Da).size + 1 >= (Da).cap ) { \
+            (Da).cap = (CAST(u64, ((Da).cap == 0) * 32) + (Da).cap) * 2; \
+            (Da).data = realloc((Da).data, sizeof(*(Da).data) * (Da).cap); \
+            if ( (Da).data == NULL ) { \
+                LIB_SET_IF_NOT_NULL((OutErr), ERR_FAILED_REALLOC); \
                 break; \
             } \
-            memset((da).data, 0, sizeof(*(da).data) * (da).cap); \
+            memset((Da).data + (Da).size, 0, \
+                   sizeof(*(Da).data) * ((Da).cap - (Da).size)); \
         } \
-        (da).data[(da).size++] = (val); \
-        LIB_SET_IF_NOT_NULL((err_var), ERR_OK); \
+        (Da).data[(Da).size++] = (Val); \
+        LIB_SET_IF_NOT_NULL((OutErr), ERR_OK); \
     } while(0)
 
 # define DA_APPEND_DATA(Da, Val, ItemNum, ErrVar) \
@@ -1211,6 +1225,7 @@ bool path_touch(struct path path, int (*open)(const char *, int),
         enum err *out_err);
 
 
+
 struct file {
     u8 *data;
     u64 size;
@@ -1220,6 +1235,11 @@ struct file path_file_read_all(const struct path *path, enum err *out_err);
 enum err path_file_save(const struct path *path, const struct file *file,
                 enum err *out_err);
 
+#  if defined(IMP_PATH) || defined(IMP)
+
+
+#  endif /* defined(IMP_PATH) || defined(IMP) */
+
 # endif /* defined(WANT_PATH) || defined(WANT_ALL) */
 
 /* ----------------------------- END PATH DEF ------------------------------ */
@@ -1938,24 +1958,56 @@ tokenizer_is_str_lit(struct tokenizer *tkn, struct str str)
 
 # if defined(WANT_CMD) || defined(WANT_ALL)
 
+#  ifdef unix
+#   define CC "cc"
+#  else
+#   error "No CC for this platform"
+#  endif
+
+struct procs {
+    i32 *data;
+    u64 size;
+    u64 cap;
+};
+
+enum err procs_wait(struct procs *_r_ procs, enum err *_r_ out_err);
+
 struct cmd {
-    char *exe;
     struct {
         char **data;
         u64 size;
         u64 cap;
     } args;
+    struct {
+        char **data;
+        u64 size;
+        u64 cap;
+    } envs;
 };
 
-#  define cmd_create_ns(Exe, OutErr) \
+struct __cmd_create_args {
+    bool copy_env;
+};
+#  define cmd_create(Exe, OutErr, ...) \
+    _cmd_create( \
+        (Exe), \
+        (struct __cmd_create_args) { \
+            .copy_env=true, \
+            __VA_ARGS__ \
+        }, \
+        (OutErr) \
+    )
+#  define cmd_create_ns(Exe, OutErr, ...) \
     cmd_create( \
-        (struct str) { \
+        ((struct str) { \
             .data=(Exe), \
             .size=cstr_len_max((Exe), STR_SIZE_LIMIT, NULL, (OutErr)) \
-        }, \
-        (OutErr) \
+        }), \
+        (OutErr), \
+        __VA_ARGS__ \
     )
-struct cmd cmd_create(struct str exe, enum err *_r_ out_err);
+struct cmd _cmd_create(struct str exe, struct __cmd_create_args args,
+                       enum err *_r_ out_err);
 
 #  define cmd_set_exe_ns(Cmd, Exe, OutErr) \
     cmd_set_exe( \
@@ -1981,28 +2033,102 @@ enum err cmd_set_exe(struct cmd *_r_ cmd, struct str exe,
 enum err cmd_append_arg(struct cmd *_r_ cmd, struct str arg,
                         enum err *_r_ out_err);
 
-enum err cmd_exec(struct cmd *_r_ cmd, enum err *_r_ out_err);
+#  define cmd_append_args_cstrs(Cmd, OutErr, Arg, ...) \
+    _cmd_append_args_cstrs( \
+        (Cmd), \
+        (const char *[]){(Arg), __VA_ARGS__, NULL}, \
+        (OutErr) \
+    )
+enum err _cmd_append_args_cstrs(struct cmd *_r_ cmd, const char **args,
+                                enum err *_r_ out_err);
+
+#  define cmd_append_env_ns(Cmd, Arg, OutErr) \
+    cmd_append_env( \
+        (Cmd), \
+        (struct str) { \
+            .data=(Arg), \
+            .size=cstr_len_max((Arg), STR_SIZE_LIMIT, NULL, (OutErr)) \
+        }, \
+        (OutErr) \
+    )
+enum err cmd_append_env(struct cmd *_r_ cmd, struct str env,
+                        enum err *_r_ out_err);
+
+struct __cmd_exec_args {
+    struct procs *procs;
+    bool reset;
+    bool search_path;
+};
+#  define cmd_exec(Cmd, OutErr, ...) \
+    _cmd_exec( \
+        (Cmd), \
+        (struct __cmd_exec_args) { \
+            .reset=true, \
+            .search_path=true, \
+            __VA_ARGS__ \
+        }, \
+        (OutErr) \
+    )
+enum err _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
+                   enum err *_r_ out_err);
 
+enum err cmd_clear_args(struct cmd *cmd, enum err *out_err);
 enum err cmd_destroy(struct cmd *cmd, enum err *out_err);
 
+#  define GO_REBUILD_YOURSELF() _cmd_go_rebuild_yourself(__FILE__, argv)
+void _cmd_go_rebuild_yourself(const char *src, char **argv);
+
+
 #  if defined(IMP_CMD) || defined(IMP)
 
+enum err
+procs_wait(struct procs *_r_ procs, enum err *_r_ out_err)
+{
+    enum err err = ERR_OK;
+    enum err *perr = &err;
+
+    i32 status = 0;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(procs, out_err);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(procs->data, out_err);
+
+    if ( out_err != NULL ) {
+        perr = out_err;
+    }
+
+    DA_FOREACH(*procs, it) {
+        if ( waitpid(*it, &status, 0) < 0 ) {
+            *perr = ERR_FAILED_WAITPID;
+            continue;
+        }
+
+        if ( WIFEXITED(status) == true ) {
+            if ( WEXITSTATUS(status) != 0 ) {
+                *perr = ERR_CMD_NON_ZERO_EXIT_CODE;
+            }
+        }
+    }
+
+    return *perr;
+}
+
 struct cmd
-cmd_create(struct str exe, enum err *_r_ out_err)
+_cmd_create(struct str exe, struct __cmd_create_args args,
+            enum err *_r_ out_err)
 {
+    enum err err = ERR_OK;
+    enum err *perr = &err;
+
     struct cmd empty = {0};
     struct cmd cmd = {0};
 
     LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty);
     LIB_ARG_MUST_NOT_BE_NULL(exe.data, out_err, empty);
 
-    cmd.exe = malloc(exe.size+1);
-    if ( cmd.exe == NULL ) {
-        LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC);
-        goto exit_err;
+    if ( out_err != NULL ) {
+        perr = out_err;
     }
-    cmd.exe[exe.size] = 0;
-    memcpy(cmd.exe, exe.data, exe.size);
 
     cmd.args.cap = 32;
     cmd.args.data = malloc(sizeof(*cmd.args.data) * cmd.args.cap);
@@ -2010,14 +2136,33 @@ cmd_create(struct str exe, enum err *_r_ out_err)
         LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC);
         goto exit_err;
     }
+    memset(cmd.args.data, 0, sizeof(*cmd.args.data) * cmd.args.cap);
+    cmd_append_arg(&cmd, exe, perr);
+    if ( *perr != ERR_OK ) {
+        goto exit_err;
+    }
+
+    cmd.envs.cap = 32;
+    cmd.envs.data = malloc(sizeof(*cmd.envs.data) * cmd.envs.cap);
+    if ( cmd.envs.data == NULL ) {
+        LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC);
+        goto exit_err;
+    }
+    memset(cmd.envs.data, 0, sizeof(*cmd.envs.data) * cmd.envs.cap);
 
-    DA_APPEND(cmd.args, cmd.exe, out_err);
+    if ( args.copy_env == true && environ != NULL ) {
+        char **envs = environ;
+        while ( *envs != NULL ) {
+            cmd_append_env_ns(&cmd, *envs, perr);
+            if ( *perr != ERR_OK ) goto exit_err;
+            ++envs;
+        }
+    }
 
     LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
     return cmd;
 exit_err:
-    LIB_FREE(cmd.exe);
-    LIB_FREE(cmd.args.data);
+    cmd_destroy(&cmd, perr);
     return (struct cmd){0};
 }
 
@@ -2028,19 +2173,17 @@ cmd_set_exe(struct cmd *_r_ cmd, struct str exe, enum err *_r_ out_err)
     LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
     LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(exe.data, out_err);
 
-    if ( cmd->exe != NULL ) {
-        LIB_FREE(cmd->exe);
+    if ( cmd->args.data[0] != NULL ) {
+        LIB_FREE(cmd->args.data[0]);
     }
 
-    cmd->exe = malloc(exe.size+1);
-    if ( cmd->exe == NULL ) {
+    cmd->args.data[0] = malloc(exe.size+1);
+    if ( cmd->args.data[0] == NULL ) {
         LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC);
         return ERR_FAILED_ALLOC;
     }
-    cmd->exe[exe.size] = 0;
-    memcpy(cmd->exe, exe.data, exe.size);
-
-    cmd->args.data[0] = cmd->exe;
+    cmd->args.data[0][exe.size] = 0;
+    memcpy(cmd->args.data[0], exe.data, exe.size);
 
     LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
     return ERR_OK;
@@ -2077,16 +2220,79 @@ cmd_append_arg(struct cmd *_r_ cmd, struct str arg, enum err *_r_ out_err)
 }
 
 enum err
-cmd_exec(struct cmd *_r_ cmd, enum err *_r_ out_err)
+_cmd_append_args_cstrs(struct cmd *_r_ cmd, const char **args,
+                       enum err *_r_ out_err)
+{
+    enum err err = ERR_OK;
+    enum err *perr = &err;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(args, out_err);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(args[0], out_err);
+
+    if ( out_err != NULL ) {
+        perr = out_err;
+    }
+
+    while ( *args != NULL ) {
+        cmd_append_arg_ns(cmd, *args, perr);
+        if ( *perr != ERR_OK ) return *perr;
+        ++args;
+    }
+
+    return *perr;
+}
+
+enum err
+cmd_append_env(struct cmd *_r_ cmd, struct str env, enum err *_r_ out_err)
+{
+    enum err err = ERR_OK;
+    enum err *perr = &err;
+
+    char *t = NULL;
+
+    LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(env.data, out_err);
+
+    if ( out_err != NULL ) {
+        perr = out_err;
+    }
+
+    t = malloc(env.size + 1);
+    if ( t == NULL ) {
+        LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC);
+        return ERR_FAILED_ALLOC;
+    }
+    t[env.size] = 0;
+    memcpy(t, env.data, env.size);
+
+    DA_APPEND(cmd->envs, t, perr);
+
+    return *perr;
+}
+
+enum err
+_cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
+          enum err *_r_ out_err)
 {
+    enum err err = ERR_OK;
+    enum err *perr = &err;
+
     i32 pid = -1;
     i32 status = 0;
 
     LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
     LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
-    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->exe, out_err);
     LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err);
 
+    if ( out_err != NULL ) {
+        perr = out_err;
+    }
+
     cmd->args.data[cmd->args.size] = NULL;
 
     pid = fork();
@@ -2096,16 +2302,23 @@ cmd_exec(struct cmd *_r_ cmd, enum err *_r_ out_err)
     }
 
     if ( pid == 0 ) {
-        /*
-        printf("exe=`%s`\n", cmd->exe);
-        DA_FOREACH(cmd->args, it) {
-            printf("arg=`%s`\n", *it);
-        }
-        */
-        execve(cmd->exe, cmd->args.data, NULL);
+        (
+            (args.search_path == true)
+                ? execvpe
+                : execve
+        ) (cmd->args.data[0], cmd->args.data, cmd->envs.data);
         exit(1);
     }
 
+    if ( args.reset == true ) {
+        cmd_clear_args(cmd, NULL);
+    }
+
+    if ( args.procs != NULL ) {
+        DA_APPEND(*args.procs, pid, perr);
+        return *perr;
+    }
+
     if ( waitpid(pid, &status, 0) < 0 ) {
         LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_WAITPID);
         return ERR_FAILED_WAITPID;
@@ -2123,24 +2336,86 @@ cmd_exec(struct cmd *_r_ cmd, enum err *_r_ out_err)
 }
 
 enum err
-cmd_destroy(struct cmd *cmd, enum err *out_err)
+cmd_clear_args(struct cmd *cmd, enum err *out_err)
 {
     LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
     LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
-    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->exe, out_err);
     LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err);
 
-    LIB_FREE(cmd->exe);
     DA_FOREACH(cmd->args, it) {
-        if ( *it == cmd->exe ) continue;
         LIB_FREE(*it);
     }
+    cmd->args.size = 0;
+
+    LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
+    return ERR_OK;
+}
+
+enum err
+cmd_destroy(struct cmd *cmd, enum err *out_err)
+{
+    LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
+    LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
+
+    if ( cmd->args.data != NULL ) {
+        DA_FOREACH(cmd->args, it) {
+            LIB_FREE(*it);
+        }
+    }
     LIB_FREE(cmd->args.data);
 
+    if ( cmd->envs.data != NULL ) {
+        DA_FOREACH(cmd->envs, it) {
+            LIB_FREE(*it);
+        }
+    }
+    LIB_FREE(cmd->envs.data);
+
+    cmd->args.data = NULL;
+    cmd->args.cap = 0;
+    cmd->args.size = 0;
+    cmd->envs.data = NULL;
+    cmd->envs.cap = 0;
+    cmd->envs.size = 0;
+
     LIB_SET_IF_NOT_NULL(out_err, ERR_OK);
     return ERR_OK;
 }
 
+#   ifdef _SYS_STAT_H
+void
+_cmd_go_rebuild_yourself(const char *src, char **argv)
+{
+    enum err err = ERR_OK;
+    struct stat src_stat = {0};
+    struct stat exec_stat = {0};
+
+    if ( err == ERR_OK ) err = stat(src, &src_stat);
+    if ( err == ERR_OK ) err = stat(argv[0] , &exec_stat);
+
+    if ( err == ERR_OK ) do {
+        if ( src_stat.st_mtime > exec_stat.st_mtime ) {
+            err = rename(argv[0], temp_sprintf("%s.old", argv[0]));
+
+            struct cmd cmd = cmd_create_ns(CC, &err);
+            cmd_append_arg_ns(&cmd, src, &err);
+            cmd_append_arg_ns(&cmd, "-o", &err);
+            cmd_append_arg_ns(&cmd, argv[0], &err);
+            cmd_exec(&cmd, &err);
+            cmd_destroy(&cmd, &err);
+
+            if ( err == ERR_OK ) execv(argv[0], argv);
+            if ( err == ERR_OK ) exit(0);
+        }
+    } while(0);
+
+    if ( err != ERR_OK ) {
+        fprintf(stderr, "Failed recompiling myself: %s\n", err_to_name[err]);
+        exit(1);
+    }
+}
+#   endif /* _SYS_STAT_H */
+
 #  endif /* defined(IMP_CMD) || defined(IMP) */
 
 # endif /* defined(WANT_CMD) || defined(WANT_ALL) */