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);
}

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

Отже: після всього цього мені стало цікаво: їм платили за кількість рядків та за надання надскладного алгоритму на розгляд замовника, чи це культурологічне - не дарма ж бо Індія є батьківщиною мільйонів богів та божків... ;)
From:
Anonymous( )Anonymous This account has disabled anonymous posting.
OpenID( )OpenID You can comment on this post while signed in with an account from many other sites, once you have confirmed your email address. Sign in using OpenID.
User
Account name:
Password:
If you don't have an account you can create one now.
Subject:
HTML doesn't work in the subject.

Message:

 
Notice: This account is set to log the IP addresses of everyone who comments.
Links will be displayed as unclickable URLs to help prevent spam.

Profile

je_suis_la_vie: (Default)
je_suis_la_vie

April 2017

S M T W T F S
      1
2345678
9101112131415
16 171819202122
23242526272829
30      

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 24th, 2017 02:20 am
Powered by Dreamwidth Studios