1. Си / Говнокод #13768

    +129

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    #include <stdio.h>
    #include <dlfcn.h>
    #include <getopt.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define int64 long long
    
    const char* help =
    "       -h,--help  это сообщение\
            -f,--func  имя функции\
            -n,--num   количество аргументов функции\
            -a,--arg1  первый аргумент\
            -b,--arg2  второй аргумент";
    
    struct option longopts[] ={
            {"func",1,NULL,'f'},
            {"help",1,NULL,'h'},
            {"num", 1,NULL,'n'},
            {"arg1",1,NULL,'a'},
            {"arg2",1,NULL,'b'},
            {0,0,0,0}
    };
    
    void strtoa(void** arg, char* optarg){
        int tmp;
        char* e;
        tmp = strtol(optarg,&e,10);
        if (e != optarg + strlen(optarg)){
            *arg = malloc(strlen(optarg));
            strcpy((char*)*arg,optarg);
        } else *arg = (void*)tmp;
    
    }
            
    int64 main(int argc, char** argv){
      
      int opt, num = 0;
      void *a,*b;
      char* e;
    
      void* (*func2)(void*,void*), 
            (*func1)(void*), 
            (*func0)(), *func = 0;
      
      while((opt = getopt_long(argc,argv,"f:h:n:a:b:",longopts,NULL)) != -1){
          switch (opt){
              case 'h':
                  fprintf(stderr,"%s",help);
                  exit(0);
              case 'f':
                  func = dlsym(NULL,optarg);
                  break;
              case 'n':
                  num = atoi(optarg);
                  if (num > 2) exit(1);
                  break;
              case 'a':
                  strtoa(&a,optarg);
                  break;
              case 'b':
                  strtoa(&b,optarg);
                  break;
          }
      }
      
      if(func != 0){
          switch (num){
              case 0: 
                func0 = func;
                (*func0)();
                break;
              case 1:
                func1 = func;
                (*func1)(a);
                break;
              case 2:
                func2 = func;
                (*func2)(a,b);
          }
      }
      
      return 0;
    }

    Запускает любую функцию линукс, содержащую до 2-х аргументов. В хелпе все написано. Собирать так c флагом -dl.
    Использовать так:
    a.out -f sleep -n 1 -a 1 - sleep на 1 секунду
    a.out -f printf -n 1 -a OK - выводит без конца строки
    вдохновлен этим:
    http://govnokod.ru/13763

    Я, crastinus97, говорю вам: этого способа нет в man. Я его сам открыл.

    Запостил: crastinus, 11 Сентября 2013

    Комментарии (27) RSS

    • С хелпом накосячено. После h нужно убрать двоеточие,в longopts поставить 0 вместо одного, и расставить символы перевода строки.
      Ответить
      • и вместо `-dl` сборщику очевидно передавать `-ldl`.

        ЗЫ как по мне проще было бы нечто в духе:
        perl -mPOSIX="" -e func_name'(params)'
        потому что там уже есть все нужные функции.
        Ответить
        • Но для этого нужен perl)
          Ответить
          • перл предустановлен почти на всех *них системах.

            чего (не смотря на стандарт) не скажешь о с компиляторе.
            Ответить
            • Вот про перл я очень серьезно сомневаюсь. За все никсы не скажу, но на дебиане я его ставил, когда запускал тесты mysql.
              Ответить
              • ты что-то перепутал. может быть перепутал с апдейтом или установкой какой библотекой (DBD::mysql?).

                большая часть apt-* написана на перле. установить дебиан без перла невозможно. и если попытаться удалить перл, то apt начинает кидать очень страшные предупреждения, предрекая конец света и подобное.
                Ответить
                • А вот православный yum...
                  Блин, он на пайтоне.
                  Ответить
      • Еще навскидку косяк в строках 42-44: нужно больше звездочек.
        Ответить
        • Или меньше. Но с текущим количеством не феншуй.
          Ответить
    • > Запускает любую функцию линукс
      Я для венды когда-то такую тулзу писал...

      Аргументов можно было передавать сколько угодно, писались они с префиксами примерно вот так: /i <int> или /s <string>.

      А еще там была поддержка сессий - если добавить опцию /f <sid>, то программка "форкалась" (вернее CreateProcess'ила себя), и дальнейшие команды с тем же sid выполнялись в этом демонёнке. Зачем нужны сессии? А чтобы выполнять наборы взаимосвязанных API, например открыть файл, записать что-нибудь, закрыть файл.

      Результат, который возвращала апишка, вываливался на stdout как число или строка в зависимости от ключа /ri или /rs.

      Вот как-то так ;)
      Ответить
      • я вижу ты уже свой собственный (и улучшенный!) VB написал :)
        Ответить
      • Код остался? Не поделишься?
        Ответить
        • > Код остался?
          Очень маловероятно... Если найду - выложу на гитхаб.

          P.S. Даже если и не найду, то там мало интересного: крейтпроцесс, пайп да парсер аргументов. Самое интересное было в асмовой части, аналог которой можно прочесть комментом ниже ;)
          Ответить
    • Ёбаный изврат вызов произвольной функции (x86, 32 бита, cdecl):
      uint32_t raw_call(void *f, uint32_t *args, size_t nargs) {
          uint32_t result;
          __asm(
              /* начинаем новый стековый фрейм */
              "push %%ebp\n\t"
              "mov %%esp, %%ebp\n\t"
              /* резервируем место под аргументы*/
              "lea (, %[nargs], 4), %%eax\n\t"
              "sub %%eax, %%esp\n\t"
              /* и копируем их */
              "mov %%esp, %%edi\n\t"
              "rep movsd\n\t"
              /* вызываем функцию f */
              "call 1f\n\t"
              "jmp 2f\n"
              "1:\n\t"
              "push %[f]\n\t"
              "ret\n"
              "2:\n\t"
              /* убираем фрейм со стека */
              "mov %%ebp, %%esp\n\t"
              "pop %%ebp\n\t"
              : [args] "+S" (args), [nargs] "+c" (nargs), [result] "=&a" (result)
              : [f] "r" (f)
              : "%edi"
          );
          return result;
      }
      Ответить
      • Здесь функция получается вызывается по ссылке, а не через динамический компоновщик?
        Ответить
        • > не через динамический компоновщик
          Ну адрес функции получать все равно придется через dlsym.

          > вызывается по ссылке
          В коде из топика она точно так же вызывается по ссылке ;) Просто там сссылка кастуется в нужный тип, а у меня так и остается void *.
          Ответить
      • bormand, ты ювелир.
        упростил до
        a.out функция параметры
        http://pastebin.com/Gfbb4hUX
        Ответить
        • > e != optarg + strlen(optarg)
          *e :)

          > int64 main
          Эээ, нестандартненько как-то.

          P.S. Автокаст в инты, имхо, опасная вещь. При попытке вывести какое-нибудь 42 (./raw_call printf "%s" 42) код распидорасит... Из-за этого я тогда и пилил эти дурацкие /i и /s перед каждым аргументом.
          Ответить
          • >нестандартненько как-то
            Стеб над суперхакером)
            Ответить
        • > bormand, ты ювелир.
          Да этот raw_call черезжопие то еще. За пределами gcc/x86/cdecl не работает. Да и те же даблы хрен передашь. До кошерного уровня ее еще пилить и пилить...
          Ответить
          • Я смотрю ты любишь капитанские речи:))
            Ответить
            • > капитанские речи
              А еще у меня на плече сидит попугай, который умеет кричать "borrrrmand torrrt", а вместо скролла я юзаю корабельный штурвал.
              Ответить
              • А это идея...
                Ответить
                • Предлагаю назначить борманда глобальным кэпом.
                  Ответить
                  • Я уже предлагал завести капиатнский акк.
                    Ответить
                    • И зачем? Это вызовет распри среди участников, ибо все друг перед другом равны изначально.

                      Пусть все, что скажет кэп, будет в курсиве, чтобы участники могли понять, что это говорит кэп
                      Ответить
              • На каком корабле служишь?
                Ответить

    Добавить комментарий