2008-11-13 17 views
5

मैं स्थानीय नेटवर्क ब्राउज़ करें और "प्रणाली" का उपयोग कर MPlayer के लिए फ़ाइल नाम पर पारित करने के लिए एक साधारण प्रोग्राम लिख रहा हूँ से एक तार से बचने के लिए। हालांकि, कभी-कभी फ़ाइल नामों में रिक्त स्थान या उद्धरण होते हैं। जाहिर है मैं उन से बचने के लिए अपने खुद के समारोह लिख सकता है, लेकिन मुझे यकीन है कि वर्ण है या भागने की जरूरत नहीं है कि वास्तव में क्या नहीं कर रहा हूँ।कैसे सुरक्षित रूप से सी ++

क्या सीआरटी में या कहीं भी लिनक्स हेडर में कोई फ़ंक्शन उपलब्ध है ताकि कमांड लाइन को पास करने के लिए सुरक्षित रूप से स्ट्रिंग से बच सकें?

उत्तर

7

कोई भी समाधान नहीं है जो हर जगह काम करता है क्योंकि अलग-अलग गोले के अलग-अलग विचार होते हैं कि वे किस विशेष वर्ण हैं और उनका व्याख्या कैसे किया जाता है। बैश के लिए, आप शायद '"'"' के साथ फ़ाइल नाम में प्रत्येक एकल उद्धरण को प्रतिस्थापित करने के बाद एकल कोट्स में पूरे फ़ाइल नाम के साथ दूर हो सकते हैं (पहला एकल उद्धरण अनुक्रम को रोकता है, "'" स्ट्रिंग में शाब्दिक एकल उद्धरण जोड़ता है, अंतिम एकल उद्धरण उद्धृत अनुक्रम फिर से शुरू होता है)। एक बेहतर समाधान के लिए एक रास्ता इस तरह के कार्यकारी कार्यों में से एक के साथ कांटा का उपयोग कर तो कोई खोल प्रक्षेप द्वारा के रूप में, प्रणाली का उपयोग कर के बिना कार्यक्रम कॉल करने के लिए खोजने के लिए किया जाएगा।

+0

आप सही हैं। यह न केवल है '' लेकिन ' "'" ': पी –

+0

यह एक विशिष्ट खोल के लिए एक सुरक्षित समाधान बनाने के लिए संभव है, लेकिन मैं जवाब प्रश्न पूछा, स्वीकार किया कि यह इसके बारे में जाने के लिए सबसे अच्छा तरीका नहीं था, और एक सुरक्षित प्रदान की वैकल्पिक। मुझे नहीं लगता कि यह एक कम वोट के लायक है। –

2

जबकि मुझे ऐसा कोई फ़ंक्शन नहीं पता है, तो आप '...' के साथ अपने प्रत्येक तर्क को घेर सकते हैं, और '"'"' द्वारा मूल तर्क में ' को प्रतिस्थापित कर सकते हैं। system("mplayer 'foo'\"'\"' bar'"); mplayer को एक भी तर्क देगा जो foo 'bar है और " या \n जैसी अजीब चीज़ों को रखने की अनुमति है। नोट के ऊपर (\") " से पहले भागने केवल यह मान्य सी ++ बनाना है।

आपको ऐसे फ़ंक्शन का उपयोग करने पर विचार करना चाहिए जो प्रत्येक अलग-अलग तर्क स्वीकार करता है, इस प्रकार ऐसे मुद्दों से परहेज करता है। विकिपीडिया के पास प्रसिद्ध कांटा और निष्पादन पैटर्न के बारे में एक अच्छा लेख है। http://en.wikipedia.org/wiki/Fork-exec

8

अन्य उत्तरों में इस कांटा और निष्पादन समाधान शामिल है, लेकिन मेरा दावा है कि यह करने का यह एकमात्र सही तरीका है।

खोल तर्कों से बचने से बग और समय की बर्बादी होती है, जैसे एसक्यूएल पैरामीटर से बचने की कोशिश करना एक मूर्ख विचार है जब सुरक्षित और अधिक कुशल पैरामीटर बाइंडिंग एपीआई मौजूद हैं। अब यहाँ

void play(const char *path) 
{ 
    /* Fork, then exec */ 
    pid = fork(); 

    if(pid < 0) { 
     /* This is an error! */ 
     return; 
    } 

    if(pid == 0) { 
     /* This is the child */ 
     freopen("/dev/null", "r", stdin); 
     freopen("/dev/null", "w", stdout); 
     freopen("/dev/null", "w", stderr); 

     execlp("mplayer", "mplayer", path, (char *)0); 
     /* This is also an error! */ 
     return; 
    } 
} 
+0

आप वास्तव में सही हैं यह एकमात्र सही तरीका है। लेकिन फिर भी, सवाल यह था कि आप खोल के लिए सी ++ में कैसे भागते हैं। इसलिए हमने पहले इसका जवाब दिया, और फिर दिखाया कि यह सही तरीके से कैसे करें। –

+0

मैं उल्लेख किया है, कांटा/कार्यकारी यह करने के लिए बेहतर तरीका है, लेकिन यह * * सुरक्षित रूप से किसी दिए गए खोल जो मैं अपने जवाब में शामिल के बाद से है कि प्रश्न पूछा था के लिए इस संभाल करने के लिए संभव है। मुझे ऐसा करना पड़ा जहां कांटा/निष्पादन एक विकल्प नहीं था, इसलिए यह हमेशा समय बर्बाद नहीं होता है। –

+0

हर कोई पहले से ही उद्धरण को कवर कर चुका था इसलिए मैंने कांटा/निष्पादन पर विस्तार देने का फैसला किया और एक ही समय में अपनी राय व्यक्त की। किसी के लिए कोई अपराध नहीं है। –

0

और खोल भागने समस्या के लिए एक पूर्ण समाधान है:

यहां एक नमूना कार्य है। हालांकि यह शैल के लिए स्ट्रिंग से बचने के सटीक प्रश्न का उत्तर नहीं देता है। यह कार्यक्रम के लिए तर्क पारित करने की समस्या हल करता है। यह समाधान आदेशों को निष्पादित करने के लिए आदेशों को निष्पादित करने के लिए आदेशों को निष्पादित करने के लिए एक पॉज़िक्स पोर्टेबल तरीका है जो उन्हें बचने की आवश्यकता के बारे में चिंता किए बिना कमांड में पास किया गया है।

#include <cstdio> 
#include <cstdlib> 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <sys/stat.h> 
#include <vector> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <string.h> 

std::vector<std::string> split(std::string delimiter, std::string str){ 
    std::size_t nextPos = 0; 
    std::size_t delimiterSize = delimiter.size(); 
    std::vector<std::string> list; 
    while(true){ 
     std::size_t pos = str.find(delimiter, nextPos); 
     std::string subStr; 

     if(pos == std::string::npos){ 
      list.push_back(str.substr(nextPos)); 
      break; 
     } 
     subStr = str.substr(nextPos, pos - nextPos); 
     list.push_back(subStr); 

     nextPos = pos + delimiterSize; 
    } 
    return list; 
} 


bool isFileExecutable(const std::string &file) 
{ 
    struct stat st; 

    if (stat(file.c_str(), &st) < 0) 
     return false; 
    if ((st.st_mode & S_IEXEC) != 0) 
     return true; 
    return false; 
} 

std::string ensureEndsWithSlash(std::string path){ 
    if(path[path.length()-1] != '/'){ 
     path += "/"; 
    } 
    return path; 
} 
std::string findProgram(std::string name){ 
    // check if it's relative 
    if(name.size() > 2){ 
     if(name[0] == '.' && name[1] == '/'){ 
      if(isFileExecutable(name)){ 
       return name; 
      } 
      return std::string(); 
     } 
    } 
    std::vector<std::string> pathEnv = split(":", getenv("PATH")); 
    for(std::string path : pathEnv){ 
     path = ensureEndsWithSlash(path); 
     path += name; 
     if(isFileExecutable(path)){ 
      return path; 
     } 
    } 
    return std::string(); 
} 

// terminal condition 
void toVector(std::vector<std::string> &vector, const std::string &str){ 
    vector.push_back(str); 
} 
template<typename ...Args> 
void toVector(std::vector<std::string> &vector, const std::string &str, Args ...args){ 
    vector.push_back(str); 
    toVector(vector, args...); 
} 

int waitForProcess(pid_t processId){ 
    if(processId == 0){ 
     return 0; 
    } 
    int status = 0; 
    int exitCode = -1; 
    while(waitpid(processId, &status, 0) != processId){ 
     // wait for it 
    } 
    if (WIFEXITED(status)) { 
     exitCode = WEXITSTATUS(status); 
    } 
    return exitCode; 
} 

/** 
    Runs the process and returns the exit code. 

    You should change it so you can detect process failure 
    vs this function actually failing as a process can return -1 too 

    @return -1 on failure, or exit code of process. 
*/ 
template<typename ...Args> 
int mySystem(Args ...args){ 
    std::vector<std::string> command; 
    toVector(command, args...); 
    command[0] = findProgram(command[0]); 
    if(command[0].empty()){ 
     // handle this case by returning error or something 
     // maybe std::abort() with error message 
     return -1; 
    } 
    pid_t pid = fork(); 
    if(pid) { 
     // parent wait for child 
     return waitForProcess(pid); 
    } 

    // we are child make a C friendly array 
    // this process will be replaced so we don't care about memory 
    // leaks at this point. 
    std::vector<char*> c_command; 
    for(int i = 0; i < command.size(); ++i){ 
     c_command.push_back(strdup(command[i].c_str())); 
    } 
    // null terminate the sequence 
    c_command.push_back(nullptr); 
    execvp(c_command[0], &c_command[0]); 
    // just incase 
    std::abort(); 
    return 0; 
} 



int main(int argc, char**argv){ 

    // example usage 
    mySystem("echo", "hello", "world"); 

} 
संबंधित मुद्दे