Приветствую!Есть такая проблемка. Простенькая программка берет из коммандной строки аргумент и, в зависимости от его значения, выдает в COM порт байтик. При ее запуске от root все работает отлично. А если запускать например от www (эту программку дергает php скриптик), то программа отрабатывает, но в ком порт ничего не выдает и не ругается ни в одной из ключевых точек, таких как открытие порта, заполнение буффера передаваемым байтиком и т.д... НО методом тыка было выясненно, что если убрать неприметный printf из кода, то все начинает работать под любым юзером. Компилится все под FreeBSD 6.0.
Далее код. Место со злополучным printf помеченно.
#include <fcntl.h>
#include <sys/time.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>void AddToLOG(char *logname, char *logstr);
#define BAUDRATE B115200
#define DEFAULT_LOG "server.log"char InCOMbuf[56];
fd_set readfds;
int fdCOM;int main (int argc, char* argv[])
{
if (argc < 2)
{
printf("\n Usage: trigger on -turns TX ON \n");
printf(" off -turns TX OFF\n\n");
exit(1);
}
if ((strcmp(argv[1],"on") != 0) && (strcmp(argv[1], "off") != 0))
{
printf("\n Usage: trigger on -turns da TX ON \n");
printf(" off -turns da TX OFF\n\n");
exit(1);
}char buf[128];
struct termios oldtioA, newtioA;// AddToLOG(DEFAULT_LOG, "started");
fdCOM = open ("/dev/cuad1", O_RDWR | O_NOCTTY | O_NONBLOCK | O_SYNC);
if(fdCOM < 0)
{
// AddToLOG(DEFAULT_LOG, "Can't open dev/cuad1 !");
printf("Can't open dev/cuad1 ! \n");
exit (-1);
}
tcgetattr (fdCOM, &oldtioA);
bzero (&newtioA, sizeof (newtioA));
newtioA.c_cflag = CS8 | CLOCAL | CREAD;
newtioA.c_iflag = IGNPAR;
newtioA.c_oflag = 0;
newtioA.c_lflag = 0;
newtioA.c_cc[VTIME] = 0;
newtioA.c_cc[VMIN] = 1;
cfsetispeed (&newtioA, BAUDRATE);
cfsetospeed (&newtioA, BAUDRATE);
tcsetattr (fdCOM, TCSANOW, &newtioA);
tcflush (fdCOM, TCIFLUSH);FD_ZERO(&readfds);
FD_SET(fdCOM, &readfds);
if (strcmp(argv[1], "on") == 0) {sprintf(buf, "o"); /*printf("\nTX ON\n\n");*/ }
if (strcmp(argv[1], "off") == 0) {sprintf(buf, "f"); /*printf("\nTX OFF\n\n");*/ }/*
!!!!!
Если расскомментировать любой из printf выше, то программа перестает обрабатывать соответствующий аргумент, при этом второй арг. обрабатывается нормально. Т.е. если раскомментировать например первый printf, то программа запущенная с аргументом on выполниться, но в ком порт ничего не выдаст. При этом с аргументом off все пройдем нормально. Еще раз повторюсь, глюки наблюдаются, ТОЛЬКО если программу запускать не из под root'a.
!!!!!
*/
printf("combuf=%s",buf);//!!!!! Интересно еще и то, что buf во всех случаях несет абсолютно верную информацию.
write(fdCOM, buf, 1);
printf("\n\n TRIGGED \n \n");
tcsetattr (fdCOM, TCSANOW, &oldtioA);
return(0);
}/////////////////////////////////////////////////////////////////////////////
// //
// FUNCTION: AddToLOG //
// //
// Opens 'logname' file for append access gets current time //
// and write to it 'logstr' when closes file and return //
// //
/////////////////////////////////////////////////////////////////////////////
void AddToLOG(char *logname, char *logstr)
{
FILE *log;
char out[2048];
struct tm *t;
time_t tt;if((log = fopen(logname, "a+")) == NULL)
{
//file not found then return
printf("!!!FATAL!!! Can't create: %s\n", logname);
exit(1);
}if(logstr[strlen(logstr)-1] == 0x0A) logstr[strlen(logstr)-1]='\0';
tt = time(NULL);
t = localtime(&tt);
sprintf(out, "[d:d:d] %s\n", t->tm_hour, t->tm_min, t->tm_sec, logstr);fputs(out, log);
fclose(log);
}
Начни с#define DEFAULT_LOG "/tmp/server.log"
а потом разберись толком, кто куда должен складывать лог. Учти, что если ты пускал root'ом, то другие пользователи не смогут этого сделать - /tmp/server.log будет существовать, принадлежать root'у и скорее всего только он сможет открыть его на запись (уточни umask).
>Начни с
>
>#define DEFAULT_LOG "/tmp/server.log"
>
>а потом разберись толком, кто куда должен складывать лог. Учти, что если
>ты пускал root'ом, то другие пользователи не смогут этого сделать -
>/tmp/server.log будет существовать, принадлежать root'у и скорее всего только он сможет
>открыть его на запись (уточни umask).
В том коде который я привел вызов лога нигде не производится. Для честности эксперимента я вообще убрал функцию и ее прототип... Эффект остался тот же.
1. вы бы проверили может ли вообще пользователь www что-то писать в порт,
и получается ли поставить скорость 115200, то есть надо проверить результат
всех операций tcXXX, cfXXX и на всякий случай посмотреть значение fdCOM.2. насколько понимаю, приведённый код - вырезка из реального, а 'странное'
поведение очень похоже на запаханную память :)
>1. вы бы проверили может ли вообще пользователь www что-то писать в
>порт,Да может. Этот код которы
>и получается ли поставить скорость 115200, то есть надо проверить результат
>всех операций tcXXX, cfXXX и на всякий случай посмотреть значение fdCOM.>2. насколько понимаю, приведённый код - вырезка из реального, а 'странное'
>поведение очень похоже на запаханную память :)
>1. вы бы проверили может ли вообще пользователь www что-то писать в
>порт,Да может. С закомментированными printf юзер www без проблем выполняет эту программу и происходит запись в компорт. Если расскомментировать printf, то программа исполняется, но в ком порт ничего не пишется. НО, при этом от имени root все выполняется без каких либо проблем даже с printf.
>и получается ли поставить скорость 115200, то есть надо проверить результат
>всех операций tcXXX, cfXXX и на всякий случай посмотреть значение fdCOM.
>Да. С этим все ОК.
>2. насколько понимаю, приведённый код - вырезка из реального, а 'странное'
>поведение очень похоже на запаханную память :)Нет это абсолютно боевой код. Можно копировать и комилить.
>Нет это абсолютно боевой код. Можно копировать и комилить.Странно тогда, поскольку симптомы действительно указывают на запорченную память, а ничего такого в приведенном коде на первый взгляд не наблюдается.
>а ничего такого в приведенном коде на первый взгляд не наблюдается.Дикое предположение - несоответствие выравнивания полей и прочего структуры termios между библиотекой и программой.
void AddToLOG(char *logname, char *logstr){if(logstr[strlen(logstr)-1] == 0x0A) logstr[strlen(logstr)-1]='\0';
//а если статическую строку передашь (типа AddToLOG(DEFAULT_LOG, "started")) - потенциальная ошибка
...
sprintf(out, "[d:d:d] %s\n", t->tm_hour, t->tm_min, t->tm_sec, logstr);
//Что это за квадратики??!!! Процент поставь - здесь похоже и есть ошибка
}
>void AddToLOG(char *logname, char *logstr){
>
>if(logstr[strlen(logstr)-1] == 0x0A) logstr[strlen(logstr)-1]='\0';
>//а если статическую строку передашь (типа AddToLOG(DEFAULT_LOG, "started")) - потенциальная ошибка
>...
>sprintf(out, "[d:d:d] %s\n", t->tm_hour, t->tm_min, t->tm_sec, logstr);
>//Что это за квадратики??!!! Процент поставь - здесь похоже и есть ошибка
>
>}
Ребят, функция AddToLOG ни разу не вызывалась, посмотрите внимательно код... Чтоб она вам глаза не мазолила, еще раз приведу код без нее. Проблемы те же...
#include <fcntl.h>
#include <sys/time.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>#define BAUDRATE B115200
char InCOMbuf[56];
fd_set readfds;
int fdCOM;int main (int argc, char* argv[])
{
if (argc < 2)
{
printf("\n Usage: trigger on -turns TX ON \n");
printf(" off -turns TX OFF\n\n");
exit(1);
}
if ((strcmp(argv[1],"on") != 0) && (strcmp(argv[1], "off") != 0))
{
printf("\n Usage: trigger on -turns da TX ON \n");
printf(" off -turns da TX OFF\n\n");
exit(1);
}char buf[128];
struct termios oldtioA, newtioA;fdCOM = open ("/dev/cuad1", O_RDWR | O_NOCTTY | O_NONBLOCK | O_SYNC);
if(fdCOM < 0)
{printf("Can't open dev/cuad1 ! \n");
exit (-1);
}
tcgetattr (fdCOM, &oldtioA);
bzero (&newtioA, sizeof (newtioA));
newtioA.c_cflag = CS8 | CLOCAL | CREAD;
newtioA.c_iflag = IGNPAR;
newtioA.c_oflag = 0;
newtioA.c_lflag = 0;
newtioA.c_cc[VTIME] = 0;
newtioA.c_cc[VMIN] = 1;
cfsetispeed (&newtioA, BAUDRATE);
cfsetospeed (&newtioA, BAUDRATE);
tcsetattr (fdCOM, TCSANOW, &newtioA);
tcflush (fdCOM, TCIFLUSH);FD_ZERO(&readfds);
FD_SET(fdCOM, &readfds);
if (strcmp(argv[1], "on") == 0) {sprintf(buf, "o"); /*printf("\nTX ON\n\n");*/ }
if (strcmp(argv[1], "off") == 0) {sprintf(buf, "f");}/////////// В таком варианте компиляции получаем следующий результат:
/////////// Запуск от root с ключем on - успешно
/////////// Запуск от root с ключем off - успешно
/////////// Запуск от www с ключем on - успешно
/////////// Запуск от www с ключем off - успешно////////// Далее раскомментируем printf десятью строками выше, получаем:
/////////// Запуск от root с ключем on - успешно
/////////// Запуск от root с ключем off - успешно
/////////// Запуск от www с ключем on - прога отрабатывает, printf("combuf=%s",buf); выдет то что положено. Но в ком порт ничего не сыпеться.
/////////// Запуск от www с ключем off - успешно
printf("combuf=%s",buf);
write(fdCOM, buf, 1);
printf("\n\n TRIGGED \n \n");
tcsetattr (fdCOM, TCSANOW, &oldtioA);
return(0);
}
1 - компилять с ключами -Wall -Wextra и забороть ВСЕ предупреждения
2 - переделать код в чистый C, натравить на него splint и забороть все разумные предупреждения
3 - удалить из кода ВСЁ лишнее (FD_SET и проч как неиспользуемое)
4 - заменить bzero как depricated функцию на memset
5 - перед злосщастным вызовом write(fdCOM,buf,1)
вывести и проверить значения fdCOM,buf и его содержимого
6 - после write добавить tcdrain() чтобы точно дождаться вывода если он не произошёл
7 - прогнать под отладчиком под разными пользователями и сравнить ВЕСЬ ход исполнениясообщить о любом результате
>1 - компилять с ключами -Wall -Wextra и забороть ВСЕ предупреждения
>2 - переделать код в чистый C, натравить на него splint и
>забороть все разумные предупреждения
>3 - удалить из кода ВСЁ лишнее (FD_SET и проч как неиспользуемое)
>
>4 - заменить bzero как depricated функцию на memset
>5 - перед злосщастным вызовом write(fdCOM,buf,1)
>вывести и проверить значения fdCOM,buf и его содержимого
>6 - после write добавить tcdrain() чтобы точно дождаться вывода если он
>не произошёл
>7 - прогнать под отладчиком под разными пользователями и сравнить ВЕСЬ ход
>исполнения
>
>сообщить о любом результате8. заменить
if (strcmp(argv[1], "on") == 0) {sprintf(buf, "o"); /*printf("\nTX ON\n\n");*/ }
на
if (strcmp(argv[1], "on") == 0) strcpy(buf, "o"); /*printf("\nTX ON\n\n");*/ }по смыслу: (sprintf() без спецификаторов)- из разряда мистики
по стилю: юзать 'тяжелый' sprintf() в данном случае не стоит :)
упс, потер случайно фигурную скобку=)
if (strcmp(argv[1], "on") == 0) { strcpy(buf, "o"); /*printf("\nTX ON\n\n");*/ }
>упс, потер случайно фигурную скобку=)
>if (strcmp(argv[1], "on") == 0) { strcpy(buf, "o"); /*printf("\nTX ON\n\n");*/ }
>
тут, строго говоря, хватило бы вообще {buf[0]='o'; /*printf("\nTX ON\n\n");*/ }
но дело не в этом. если "некрасиво" не работает, а "красиво" - работает, значит, сделав "красиво" ты завел бомбу замедленного действия. ибо даже sprintf в этом контексте не криминал, не работает по другой причине!!!\^P^/
>>упс, потер случайно фигурную скобку=)
>>if (strcmp(argv[1], "on") == 0) { strcpy(buf, "o"); /*printf("\nTX ON\n\n");*/ }
>>
>тут, строго говоря, хватило бы вообще {buf[0]='o'; /*printf("\nTX ON\n\n");*/ }
>но дело не в этом. если "некрасиво" не работает, а "красиво" -
>работает, значит, сделав "красиво" ты завел бомбу замедленного действия. ибо даже
>sprintf в этом контексте не криминал, не работает по другой причине!!!
>
>
>\^P^/строго говоря, тут все переписать надо :)
Но дело не этом. Бомбу заводить будет автор топика если вместо того чтобы откопать истинную причину, оставит вдруг заработавший (не верится) 'красивый' код.некоторая осторожность относительно sprintf у меня из темного прошлого =)
[...]
>Но дело не этом. Бомбу заводить будет автор топика если вместо того
>чтобы откопать истинную причину, оставит вдруг заработавший (не верится) 'красивый' код.
я, собсно, от этого и предостерегаю (вдруг всеже заработает - случайно?)\^P^/