Երեկ թունելը աշխատում էր, իսկ այս առավոտ unit-ը մեռած է, մատյանում կա Failed at step EXEC spawning /usr/local/bin/vpnclient։ Հավատարմագրերը, երթուղիները և հաշիվը երբեք չեն մտնում այդ նախադասության մեջ։ systemd-ը ExecStart-ը լուծեց ուղու, խնդրեց կորնելին գործարկել այն, և կորնելը մերժեց, ամենից հաճախ որովհետև այդ ուղում ոչինչ չկա կամ ֆայլը գործարկելի չէ։ Վերաբերվեք խափանմանը որպես ֆայլի և argv-ի խնդրի, քանի դեռ վերլուծված հրամանը չի ապացուցել հակառակը։

Ինչու է EXEC-ը ձախողվում մինչև նույնականացման մեկնարկը

systemd-ը ExecStart-ը չի գործարկում shell-ի միջոցով։ Այն կատարում է fork, տողից կառուցում է արգումենտների վեկտոր և execve է կանչում առաջին տարրի վրա։ Եթե այդ կանչը ձախողվի, ծառայությունը երբեք չի հասնում VPN հաճախորդի սեփական կոդին, ուստի պրոֆիլի խմբագրումը կամ հավատարմագրերի ստուգումը չեն օգնի։

Կարգավիճակի կոդը բաժանում է այս ընտանիքը սովորական խափանումներից։ status=203/EXEC-ով դուրս եկած unit-ը երբեք գործընթաց չի սկսել. unit-ը, որը սկսվում է և հետո դուրս է գալիս status=1 -ով, հնարավոր է ձախողվել է նույնականացման, DNS-ի կամ երթուղավորման փուլում։ Կոդը կարդացեք հաճախորդի մատյանից առաջ, որովհետև առաջին դեպքում հաճախորդի մատյանը դատարկ կլինի։

Մատյանի ուղին այն ուղին է, որն օգտագործել է systemd-ը, ոչ պարտադիր այն, որը դուք խմբագրել եք։ Drop-in ֆայլերը և գեներատորի ելքը կարող են վերագրանցել մատակարարի ֆայլը, իսկ հնացած daemon-reload-ը հին տողը թողնում է հիշողության մեջ։ Դրա համար առաջին ախտորոշումը systemd-ից հարցնելն է, թե ինչ է նա համարում հրամանը, այլ ոչ թե բացել այն ֆայլը, որը հիշում եք, թե փոխել եք։

Երեք տեղ, որտեղ գրվում է բինար ֆայլի ուղին

Տարածման փաթեթից, մատակարարի սկրիպտից և թողարկման tarball-ից տեղադրված VPN հաճախորդը կարող է հայտնվել երեք տարբեր նախածանցերում։ unit-ը, արտոնության կանոնը և տեղադրիչը յուրաքանչյուրը գրանցել է այդ նախածանցերից մեկը, և խափանումը հայտնվում է, երբ երեքից երկուսը չեն համընկնում։

RecordCommon valueHow to read it
Unit or drop-in/usr/local/bin/vpnclientsystemctl cat vpnclient.service
Installed binary/usr/bin/vpnclientcommand -v vpnclient, then ls -l the result
Sudoers grant/opt/vpnclient/bin/vpnclientsudo grep -r vpnclient /etc/sudoers.d/

Կոնկրետ անհամապատասխանությունն այսպես է՝ մատակարարի սկրիպտը տեղադրում է /usr/local/bin, tarball-ը բացվել է /opt-ի տակ, իսկ unit-ը դեռ նշում է նախորդ փաթեթի հին /usr/bin ուղին։ Այդ ֆայլերից գոյություն ունի միայն մեկը, և հազվադեպ է, որ դա ExecStart-ում եղած ֆայլն է։

Որոշեք, թե որ ուղին է կանոնական, նախքան ֆայլերից որևէ մեկը փոխելը։ Եթե բինար ֆայլը պատկանում է տարածման փաթեթին, կանոնականը փաթեթի ուղին է, և unit-ը պետք է հետևի դրան։ Եթե այն պատկանում է մատակարարի սկրիպտին, նույն կանոնը գործում է մատակարարի նախածանցի համար։ Բինար ֆայլը նախածանցերի միջև պատճենելը ստեղծում է երկու պատճեն, որոնք հաջորդ թարմացման ժամանակ կտարանջատվեն։

Երբ չակերտների մեջ դրված հրամանը դառնում է ֆայլի անուն

Երկրորդ խափանման ձևը թաքնված է մատյանի նույն տողի հետևում։ Ինչ-որ մեկը սա գրում է unit-ի մեջ և ակնկալում, որ հաճախորդը կմիանա բեռնման ընթացքում՝

ExecStart=/usr/bin/"vpnclient connect office"

systemd-ը արժեքը բաժանում է բառերի, ուստի առաջին բառը դառնում է /usr/bin/vpnclient connect office, ընդ որում չակերտները հանվում են որպես խմբավորման շարահյուսություն։ Այնուհետև կորնելը փնտրում է ֆայլ, որի անվան մեջ բացատներ կան, և այդպիսին չկա։ Սխալը նույնական է բացակայող բինար ֆայլի սխալին, թեև ֆայլը տեղադրված է։

Աջակցվող ձևը իրական գործարկելի ֆայլն է, որին հաջորդում են առանձին արգումենտներ, օրինակ՝ ExecStart=/usr/bin/vpnclient connect office։ Եթե աշխատանքի հոսքը իսկապես պահանջում է խողովակ կամ շղթա, դրեք այն սկրիպտի մեջ և կանչեք սկրիպտը, որովհետև ExecStart-ը չունի &&, չունի խողովակներ և չունի glob ընդլայնում։

Ուղղեք unit-ը, ոչ թե ֆայլային համակարգը

Գայթակղիչ վերանորոգումը սիմվոլիկ հղումն է սպասվող ուղուց դեպի իրական բինար ֆայլը։ Այն աշխատում է այնքան, մինչև փաթեթը թարմացվի և հղումը ցույց տա հեռացված ֆայլի, կամ մինչև SELinux պիտակը այլևս չհամապատասխանի թիրախին։ Ավելի լավ է unit-ը խմբագրել drop-in-ի միջոցով, որպեսզի մատակարարի ֆայլը մնա անձեռնմխելի, իսկ թարմացումները՝ կանխատեսելի։

Արտոնության կանոնը պետք է համապատասխանի նույն ուղուն և նույն ենթահրամաններին։ /usr/local/bin/vpnclient-ի համար sudoers գրառումը չի լիազորում /usr/bin/vpnclient-ը, իսկ ցանկացած արգումենտ թույլատրող գրառումը թույլ է տալիս ցանկացած լոկալ գործընթացի վերակարգավորել կամ կանգնեցնել թունելը։ Տվեք այն երկու բայերը, որոնք unit-ին անհրաժեշտ են, և ապամոնտաժումը պահեք դրանից դուրս, եթե ծառայության կանգը արդեն փակում է ինտերֆեյսը։

Այստեղ է, որ համեմատությունն արդարացնում է իրեն՝ unit-ը, փաթեթների տվյալների բազան և sudoers-ը պետք է բոլորն անվանեն մեկ ուղի։ Երբ այդպես է, EXEC սխալը վերանում է առանց վերագործարկման և առանց բինար ֆայլի պատճենի երրորդ տեղում։

Ապացուցեք վերլուծված հրամանը մինչև վերագործարկումը

sudo systemctl daemon-reload
sudo systemctl cat vpnclient.service
systemctl show -p ExecStart vpnclient.service
systemd-analyze verify /etc/systemd/system/vpnclient.service
sudo systemctl restart vpnclient.service
systemctl status vpnclient.service --no-pager

systemctl show-ը վճռորոշ ելքն է, որովհետև այն տպում է այն argv-ն, որը systemd-ը իրականում վերլուծել է, ներառյալ ցանկացած drop-in։ systemd-analyze verify-ը բռնում է բացակայող կամ ոչ գործարկելի ուղին նախքան վերագործարկելը, իսկ վերագործարկումից հետո status հրամանը ասում է՝ գործընթացը հիմա գոյություն ունի՞։

Եթե unit-ը սկսվում է և հետո ձախողվում, դուք թողել եք EXEC ընտանիքը և մտել հաճախորդի սեփական սխալների մշակման մեջ։ Մատյանում փնտրեք հաճախորդի հաղորդագրությունը, ոչ թե ևս մեկ execve խափանում։ Պահեք unit-ի diff-ը և sudoers-ի diff-ը միասին փոփոխության գրառման մեջ, որպեսզի հաջորդ թարմացումը լուռ չվերադարձնի բաժանված ուղին։

Առնչվող հոդվածներ