static void test_sc_string_init__normal() { char buf[1] = { 0xFF }; sc_string_init(buf, sizeof buf); g_assert_cmpint(buf[0], ==, 0); }
const char *sc_umount_cmd(char *buf, size_t buf_size, const char *target, int flags) { sc_string_init(buf, buf_size); sc_string_append(buf, buf_size, "umount"); if (flags & MNT_FORCE) { sc_string_append(buf, buf_size, " --force"); } if (flags & MNT_DETACH) { sc_string_append(buf, buf_size, " --lazy"); } if (flags & MNT_EXPIRE) { // NOTE: there's no real command line option for MNT_EXPIRE sc_string_append(buf, buf_size, " --expire"); } if (flags & UMOUNT_NOFOLLOW) { // NOTE: there's no real command line option for UMOUNT_NOFOLLOW sc_string_append(buf, buf_size, " --no-follow"); } if (target != NULL) { sc_string_append(buf, buf_size, " "); sc_string_append(buf, buf_size, target); } return buf; }
static void test_sc_string_init__NULL_buf() { if (g_test_subprocess()) { sc_string_init(NULL, 1); g_test_message("expected sc_string_init not to return"); g_test_fail(); return; } g_test_trap_subprocess(NULL, 0, 0); g_test_trap_assert_failed(); g_test_trap_assert_stderr("cannot initialize string, buffer is NULL\n"); }
static void test_sc_string_append_char_pair__normal() { char buf[16]; size_t len; sc_string_init(buf, sizeof buf); len = sc_string_append_char_pair(buf, sizeof buf, 'h', 'e'); g_assert_cmpstr(buf, ==, "he"); g_assert_cmpint(len, ==, 2); len = sc_string_append_char_pair(buf, sizeof buf, 'l', 'l'); g_assert_cmpstr(buf, ==, "hell"); g_assert_cmpint(len, ==, 4); len = sc_string_append_char_pair(buf, sizeof buf, 'o', '!'); g_assert_cmpstr(buf, ==, "hello!"); g_assert_cmpint(len, ==, 6); }
static void test_sc_string_init__empty_buf() { if (g_test_subprocess()) { char buf[1] = { 0xFF }; sc_string_init(buf, 0); g_test_message("expected sc_string_init not to return"); g_test_fail(); return; } g_test_trap_subprocess(NULL, 0, 0); g_test_trap_assert_failed(); g_test_trap_assert_stderr ("cannot initialize string, buffer is too small\n"); }
const char *sc_mount_opt2str(char *buf, size_t buf_size, unsigned long flags) { unsigned long used = 0; sc_string_init(buf, buf_size); #define F(FLAG, TEXT) do { \ if (flags & (FLAG)) { \ sc_string_append(buf, buf_size, #TEXT ","); flags ^= (FLAG); \ } \ } while (0) F(MS_RDONLY, ro); F(MS_NOSUID, nosuid); F(MS_NODEV, nodev); F(MS_NOEXEC, noexec); F(MS_SYNCHRONOUS, sync); F(MS_REMOUNT, remount); F(MS_MANDLOCK, mand); F(MS_DIRSYNC, dirsync); F(MS_NOATIME, noatime); F(MS_NODIRATIME, nodiratime); if (flags & MS_BIND) { if (flags & MS_REC) { sc_string_append(buf, buf_size, "rbind,"); used |= MS_REC; } else { sc_string_append(buf, buf_size, "bind,"); } flags ^= MS_BIND; } F(MS_MOVE, move); // The MS_REC flag handled separately by affected flags (MS_BIND, // MS_PRIVATE, MS_SLAVE, MS_SHARED) // XXX: kernel has MS_VERBOSE, glibc has MS_SILENT, both use the same constant F(MS_SILENT, silent); F(MS_POSIXACL, acl); F(MS_UNBINDABLE, unbindable); if (flags & MS_PRIVATE) { if (flags & MS_REC) { sc_string_append(buf, buf_size, "rprivate,"); used |= MS_REC; } else { sc_string_append(buf, buf_size, "private,"); } flags ^= MS_PRIVATE; } if (flags & MS_SLAVE) { if (flags & MS_REC) { sc_string_append(buf, buf_size, "rslave,"); used |= MS_REC; } else { sc_string_append(buf, buf_size, "slave,"); } flags ^= MS_SLAVE; } if (flags & MS_SHARED) { if (flags & MS_REC) { sc_string_append(buf, buf_size, "rshared,"); used |= MS_REC; } else { sc_string_append(buf, buf_size, "shared,"); } flags ^= MS_SHARED; } flags ^= used; // this is just for MS_REC F(MS_RELATIME, relatime); F(MS_KERNMOUNT, kernmount); F(MS_I_VERSION, iversion); F(MS_STRICTATIME, strictatime); #ifndef MS_LAZYTIME #define MS_LAZYTIME (1<<25) #endif F(MS_LAZYTIME, lazytime); #ifndef MS_NOSEC #define MS_NOSEC (1 << 28) #endif F(MS_NOSEC, nosec); #ifndef MS_BORN #define MS_BORN (1 << 29) #endif F(MS_BORN, born); F(MS_ACTIVE, active); F(MS_NOUSER, nouser); #undef F // Render any flags that are unaccounted for. if (flags) { char of[128] = { 0 }; sc_must_snprintf(of, sizeof of, "%#lx", flags); sc_string_append(buf, buf_size, of); } // Chop the excess comma from the end. size_t len = strnlen(buf, buf_size); if (len > 0 && buf[len - 1] == ',') { buf[len - 1] = 0; } return buf; }
const char *sc_mount_cmd(char *buf, size_t buf_size, const char *source, const char *target, const char *fs_type, unsigned long mountflags, const void *data) { sc_string_init(buf, buf_size); sc_string_append(buf, buf_size, "mount"); // Add filesysystem type if it's there and doesn't have the special value "none" if (fs_type != NULL && strncmp(fs_type, "none", 5) != 0) { sc_string_append(buf, buf_size, " -t "); sc_string_append(buf, buf_size, fs_type); } // Check for some special, dedicated options, that aren't represented with // the generic mount option argument (mount -o ...), by collecting those // options that we will display as command line arguments in // used_special_flags. This is used below to filter out these arguments // from mount_flags when calling sc_mount_opt2str(). int used_special_flags = 0; // Bind-ounts (bind) if (mountflags & MS_BIND) { if (mountflags & MS_REC) { sc_string_append(buf, buf_size, " --rbind"); used_special_flags |= MS_REC; } else { sc_string_append(buf, buf_size, " --bind"); } used_special_flags |= MS_BIND; } // Moving mount point location (move) if (mountflags & MS_MOVE) { sc_string_append(buf, buf_size, " --move"); used_special_flags |= MS_MOVE; } // Shared subtree operations (shared, slave, private, unbindable). if (MS_SHARED & mountflags) { if (mountflags & MS_REC) { sc_string_append(buf, buf_size, " --make-rshared"); used_special_flags |= MS_REC; } else { sc_string_append(buf, buf_size, " --make-shared"); } used_special_flags |= MS_SHARED; } if (MS_SLAVE & mountflags) { if (mountflags & MS_REC) { sc_string_append(buf, buf_size, " --make-rslave"); used_special_flags |= MS_REC; } else { sc_string_append(buf, buf_size, " --make-slave"); } used_special_flags |= MS_SLAVE; } if (MS_PRIVATE & mountflags) { if (mountflags & MS_REC) { sc_string_append(buf, buf_size, " --make-rprivate"); used_special_flags |= MS_REC; } else { sc_string_append(buf, buf_size, " --make-private"); } used_special_flags |= MS_PRIVATE; } if (MS_UNBINDABLE & mountflags) { if (mountflags & MS_REC) { sc_string_append(buf, buf_size, " --make-runbindable"); used_special_flags |= MS_REC; } else { sc_string_append(buf, buf_size, " --make-unbindable"); } used_special_flags |= MS_UNBINDABLE; } // If regular option syntax exists then use it. if (mountflags & ~used_special_flags) { char opts_buf[1000] = { 0 }; sc_mount_opt2str(opts_buf, sizeof opts_buf, mountflags & ~used_special_flags); sc_string_append(buf, buf_size, " -o "); sc_string_append(buf, buf_size, opts_buf); } // Add source and target locations if (source != NULL && strncmp(source, "none", 5) != 0) { sc_string_append(buf, buf_size, " "); sc_string_append(buf, buf_size, source); } if (target != NULL && strncmp(target, "none", 5) != 0) { sc_string_append(buf, buf_size, " "); sc_string_append(buf, buf_size, target); } return buf; }
void sc_string_quote(char *buf, size_t buf_size, const char *str) { if (str == NULL) { die("cannot quote string: string is NULL"); } const char *hex = "0123456789abcdef"; // NOTE: this also checks buf/buf_size sanity so that we don't have to. sc_string_init(buf, buf_size); sc_string_append_char(buf, buf_size, '"'); for (unsigned char c; (c = *str) != 0; ++str) { switch (c) { // Pass ASCII letters and digits unmodified. case '0' ... '9': case 'A' ... 'Z': case 'a' ... 'z': // Pass most of the punctuation unmodified. case ' ': case '!': case '#': case '$': case '%': case '&': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\'': case ']': case '^': case '_': case '`': case '{': case '|': case '}': case '~': sc_string_append_char(buf, buf_size, c); break; // Escape special whitespace characters. case '\n': sc_string_append_char_pair(buf, buf_size, '\\', 'n'); break; case '\r': sc_string_append_char_pair(buf, buf_size, '\\', 'r'); break; case '\t': sc_string_append_char_pair(buf, buf_size, '\\', 't'); break; case '\v': sc_string_append_char_pair(buf, buf_size, '\\', 'v'); break; // Escape the escape character. case '\\': sc_string_append_char_pair(buf, buf_size, '\\', '\\'); break; // Escape double quote character. case '"': sc_string_append_char_pair(buf, buf_size, '\\', '"'); break; // Escape everything else as a generic hexadecimal escape string. default: sc_string_append_char_pair(buf, buf_size, '\\', 'x'); sc_string_append_char_pair(buf, buf_size, hex[c >> 4], hex[c & 15]); break; } } sc_string_append_char(buf, buf_size, '"'); }