je_suis_la_vie: (La Vie)
[personal profile] je_suis_la_vie
Як платити за працю програміста?
За рядки, чи за результат?

Цікаві індуси понаписали функції отримання номера групи та номера користувача.


Починається все з функції ініціації номерів користувачів та їхніх груп. З першого погляду все нормально. Ми бачимо виклики get_uid() та get_gid(), в разі, якщо номер користувача чи його групи не знайдеться, то повернеться "-1", а оскільки в системі гарантовано не існує ні номера користувача, ні номера його групи зі значенням "-1", то тут ми можемо бути цілком впевненими, що все буде під контролем.
Нормально. Проїхали.

int uidinit(int closeflag) {

if((auto_uida = get_uid(ALIASU)) == -1)> return(-1);
else if((auto_uidd = get_uid(QMAILD)) == -1) return(-1);
else if((auto_uidl = get_uid(QMAILL)) == -1) return(-1);
else if((auto_uido = get_uid(ROOTUSER)) == -1) return(-1);
else if((auto_uidp = get_uid(QMAILP)) == -1) return(-1);
else if((auto_uidq = get_uid(QMAILQ)) == -1) return(-1);
else if((auto_uidr = get_uid(QMAILR)) == -1) return(-1);
else if((auto_uids = get_uid(QMAILS)) == -1) return(-1);
else if((auto_uidv = get_uid(QMAILVU)) == -1) return(-1);
else if((auto_uidc = get_uid(QSCANDU)) == -1) return(-1);

else if((auto_gidn = get_gid(NOQMAILG)) == -1) return(-1);
else if((auto_gidq = get_gid(QMAILG)) == -1) return(-1);
else if((auto_gidv = get_gid(QMAILVG)) == -1) return(-1);
else if((auto_gidc = get_gid(QSCANDG)) == -1) return(-1);

 else {
    if(closeflag) {
      endpwent();
      endgrent();
    }
    return(0);
 }
}



Продовження вже цікавіше. Заходимо до самих функцій get_uid() та get_gid()
Візьмімо get_gid()...

Ось наші групи, зарезервовані для роботи поштовика:

static char    *user_gid_list[] = {
        QMAILG,
        NOQMAILG,
        QMAILVG,
        QSCANDG,
        ""
};



static int get_gid(char *group) {

int             i, len, len1, len2; // задекларували аж чотири змінних
struct group   *gr; // задекларували покажчик структури типу group, гараз...
static int      first; // статична змінна
static uid_t    gid_array[4] = {-1, -1, -1, -1}; // жорстко декларуємо, що ми маємо чотири групи, і проініціювали кожен елемент масиву мінус одиничками.

if(!first) { // це смішно: про всяк випадок ми пропускаюмо першу групу у базі даних груп, котра дорівнює нулю - тобто група всемогутнього юзера Charlie Root. Таки смішно, ниже побачите чому.
    for(;;) {//залізли у безкінечний цикл. Як я ненавиджу безкінечні цикли for(;;), бо ж простіше, якщо хочете самозадокументувати код, оголосити безкінечний цикл while( gr = getgrent()) { бла-бла; }
         if(!(gr = getgrent())) break; // ...а не пхати сюди цей виклик ТУПОГО і БЕЗДУМНОГО в данному випадку проходу по списку системних груп :-/
            for(i = 0; *user_gid_list[i]; i++) { // ідемо елементами списка з нашими груп-айді. Не розумію яку корисну функцію виконує тут цей прохід по списку УСІХ наявних у системі груп :)
                len = str_len(user_gid_list[i]); // довжину назви кожної групи (задекларували список вище user_gid_list) заміряти та зберегти у зміній len
                if(!str_diffn(user_gid_list[i], gr->gr_name, len)) gid_array[i] = gr->gr_gid; //порівняти назву групи списку з назвою, яку повернув покажчик на gr після виклику getgrent() - тобто gr->gr_name, і не просто порівняти, а порівняти len байт назви user_gid_list[i]. Ось тут почалася епопея... Той самий класичний баг, які зазвичай шукають тижнями, я впорався за день ;)))
        }
    }
    for(i = 0; *user_gid_list[i]; i++) { // На останок пройтися по масиву user_gid_list і перевірити чи ще якісь елементи часом не залишилися зі значенням "-1".
      if(gid_array[i] == -1) strerr_die(111, "getgrent: ", user_gid_list[i], ": No such group", 0, 0, 0, 0, 0, (struct strerr *) 0); //коли так, викинути назовні помилку і перервати роботу. Шо це було???
    }
    first++; // Charlie Root-а, ми щасливо уникнули :)))) if(!first) закінчилася.
} /* first */

for(i = 0; *user_gid_list[i]; i++) { //Цей цикл взагалі диво. Ідемо по тому ж списку наших чотирьох груп, що і вище.
    len1 = str_len(user_gid_list[i]);//заміряємо довжину user_gid_list[i], зберігаємо довжину у len1
    len2 = str_len(group);//заміряємо довжину group - це, як ви пам'ятаєте, змінна, що прийшла з аргументом функції: get_gid(char *group) вище. Згадали? І зберегти її у len2
    len = len2 > len1 ? len2 : len1; // після всього багатослівного базікання вище, нас чомусь потягло на лаконізм :))): якщо len2 більша за len1, то len дорівнюватиме len2, інакше - len1.
      if(!str_diffn(user_gid_list[i], group, len)) return(gid_array[i]); // зрештою порівняти, і якщо є збіг повернути назву групи, котру ми зберегли в i-йному елементі масиву gid_array.
}

return (-1); // це аварійний вихід, коли шось піде не так, нам треба повернути "-1", як ознаку НЕуспіху.
}


Я так і не зрозумів, нафіга стільки коду, щоби, передавши у функцію назву групи, отримати її номер (назви для зручності людей, а система працює лише з номерами), з яким двійковик працюватиме далі.

Ось повернімось до того смішного рядка вище:
if(!str_diffn(user_gid_list[i], gr->gr_name, len)) gid_array[i] = gr->gr_gid; //порівняти назву групи списку з назвою, яку повернув покажчик на gr після виклику getgrent() - тобто gr->gr_name, і не просто порівняти, а порівняти len байт назви user_gid_list[i]. Ось тут почалася епопея... Той самий класичний баг, які зазвичай шукають тижнями, я впорався за день ;)))
;)))"


Як я вже показував вище, у нас є список наперед визначених груп.
static char    *user_gid_list[] = {
        QMAILG,
        NOQMAILG,
        QMAILVG,
        QSCANDG,
        ""
};
Елементи масива заповнюються через означення
#define QMAILG          "qmail"
#define NOQMAILG        "noqmail"
#define QMAILVG         "qmailv"
#define QSCANDG         "qscand"

str_diffn(user_gid_list[i], gr->gr_name, len) Ця функція порівнює ім'я з елементу списка з ім'ям отриманим від виклику функції getgrent(). Функція порівнює len байт. Тож коли порівнявши qmail і повернувши NULL (що означає збіг), функція порівнює qmailv, вона доходить до кінця назви qmail, тут більше літер немає, вважається, що все збіглося, і функція повертає NULL, тобто назви збігаються. "v" із qmailv залишається за бортом, бо len бралася по qmail :)))
В результаті ми маємо двічі повернуте qmailv, і єрархія директорій черги поштовика отримує назву групи qmailv, замість qmail, що є архітектурною помилкою.

Таке враження, що й if(!first) {}, і той диво-цикл, що іде за ним писали різні люди.
І взагалі незрозуміло з якою метою було написано так багато коду заради того, щоб передати до функції назву групи, а у відповідь отримати її номер.

Я довго намагався зрозуміти, що автори хотіли сказати, потім бритвою Оккама відрізав усі зайві пояснення і залишилося найпростіше - щобільше коду, то більше центів. А один рядок - 12 центів.

Та мені плювати на центи, тому мій варіант цієї функції був таким:


static int get_gid(char *group) {

struct group *gr;

    if( !(gr = getgrnam(group))) return(-1);
    else return(gr->gr_gid);

return(-1);
}

Відчуйте різницю. :)

Те ж стосується і функції get_uid(), яку просто клонували з функції get_gid() лише виклик функції вибірки назв груп замінили на getpwent() - вибірка назв користувачів, покажчик структури struct passwd  *pw; і масив імен користувачів
static uid_t    uid_array[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};

Тож, така доля спіткала і цю функцію:

static int get_uid(char *user) {

struct passwd *pw;

    if( !(pw = getpwnam(user))) return(-1);
    else return(pw->pw_uid);

return(-1);
}

І все запрацювало як і очікувалось.

Отже: після всього цього мені стало цікаво: їм платили за кількість рядків та за надання надскладного алгоритму на розгляд замовника, чи це культурологічне - не дарма ж бо Індія є батьківщиною мільйонів богів та божків... ;)

АААААА

Date: 2010-09-06 08:43 pm (UTC)
From: [identity profile] yatswish.livejournal.com
Ги :))

Date: 2010-09-07 07:40 am (UTC)
From: [identity profile] vasyl.livejournal.com
Їх просто відірвали від випасання їх улюблених буйволів за їжу і заставили писати код :-)

Date: 2010-09-07 07:55 am (UTC)
From: [identity profile] je-suis-la-vie.livejournal.com
У нас теж є хлопці не гірші.

Наприклад зверталися до MySQL-я з запитом
SELECT * FROM table1, table2, table3;
А видану інформацію обробляли у PHP сторінці. Сам розумієш, коли записів у таблицях стало кілька десятків тисяч, веб сервер лягав і вже не вставав; його просто доводилося убивати kill-ом.
Мій бос, саме сидів на вихідних тоді в колупав код, думав що ж воно таке.
А потім у понеділок копняком з третього поверху обох звільнив. Бо пояснювати крутим програмерам, що SQL ще має якісь там WHERE, AND, зрештою імена колонок у таблицях і тому подібні речі йому було впадлу. І я його розумію, бо і мені було б в падлу... :)))

Date: 2010-09-07 07:59 am (UTC)
From: [identity profile] vasyl.livejournal.com
Ну наші хлопці "я_вам_любе_зроблю_ви_мені_тільки_платіть" то звичайно окрема історія. :-)
Хоча вони насправді теж відірвані батьками від пива з сємками чи рідних корів і запхані в програмування "бо там гроші платят".

Date: 2010-09-07 07:06 pm (UTC)
From: [identity profile] je-suis-la-vie.livejournal.com
Через таких бовдурів тут, щодалі то все більше мова не про грОші, а про грошІ. :)

Profile

je_suis_la_vie: (Default)
je_suis_la_vie

June 2017

S M T W T F S
    123
4 5678910
11121314151617
18192021222324
2526 27282930 

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 22nd, 2017 12:38 pm
Powered by Dreamwidth Studios