чување bdab3f03d657a8149f169895901e6c5a61a34fab
родитељ a5c441d579f43728675954c4b729fc1729322918
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sat, 9 Mar 2024 20:56:39 +0100
Add pledge(2)/unveil(2); add macros for strlcat and strlcpy; copy code from sled dealing with symlinks
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 2 | -- |
| M | TODO.done | | | 2 | ++ |
| M | draw.c | | | 17 | ++++++----------- |
| M | draw.h | | | 4 | ++++ |
| M | po.c | | | 21 | ++++----------------- |
| M | poe.c | | | 341 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
| M | util.h | | | 23 | ++++++++++++++++++----- |
измењених датотека: 7, додавања: 220(+), брисања: 190(-)
diff --git a/TODO b/TODO
@@ -1,8 +1,6 @@
TODO
====
-[ ] Add pledge(2) and unveil(2)
-
[ ] Support Yudit's nonstandard PO format (no empty lines between individual
entries)
diff --git a/TODO.done b/TODO.done
@@ -1,6 +1,8 @@
Done todos
==========
+[x] Add pledge(2) and unveil(2)
+
[x] Switch to strlcpy, strlcat similar to sled; compare util.c and util.h to
versions of those files from sled
diff --git a/draw.c b/draw.c
@@ -91,6 +91,9 @@ init_drawstate(struct DrawState* state, char* error, char* filename,
{
state->error = error;
state->filename = filename;
+ state->real_filename = filename;
+ state->backup_filename = NULL;
+ state->rfn_len = 0;
state->search = NULL;
state->input_buffer = NULL;
state->input_changed_fuzzy = UNCHANGED;
@@ -132,6 +135,7 @@ init_drawstate(struct DrawState* state, char* error, char* filename,
state->obsolete_at_end_count = 0;
state->msgstr_index = 0;
state->first_shown_msgid = state->msgid_number;
+ state->backup_possible = 1;
}
void
@@ -614,18 +618,9 @@ draw_editbox(const struct DrawState* state)
struct PoEntry* entry = state->entries + state->msgid_number - 1;
size_t dlen = 0;
- if (strlcpy(flags_buf, "[ ", MAXFLAGSBUF + 4) >= MAXFLAGSBUF + 4)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY("[ ", flags_buf, MAXFLAGSBUF + 4);
format_flags(flags_buf + 2, MAXFLAGSBUF, entry);
- if (strlcpy(flags_buf + 2 + MAXFLAGSBUF - 1, " ]", MAXFLAGSBUF + 4 - 2)
- >= MAXFLAGSBUF + 4 - 2)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(" ]", flags_buf + 2 + MAXFLAGSBUF - 1, MAXFLAGSBUF + 4 - 2);
startx = w > maxx ? 0 : (maxx - w) / 2;
endx = w > maxx ? maxx - 1 : startx + w;
diff --git a/draw.h b/draw.h
@@ -41,6 +41,9 @@ struct DrawState {
char* error;
char* prompt;
char* filename;
+ char* real_filename; /* what symlink points to */
+ char* backup_filename;
+ size_t rfn_len;
uint32_t* search;
struct BufferLine* input_buffer; /* edit box */
int input_column;
@@ -89,6 +92,7 @@ struct DrawState {
size_t real_msgid_count; /* msgid_count + obsolete_count */
int msgstr_index; /* with msgstr[] */
size_t first_shown_msgid;
+ int backup_possible; /* is saving backup possible? */
};
struct Key {
diff --git a/po.c b/po.c
@@ -486,13 +486,8 @@ load_file(struct DrawState* dstate, long* lineno, long* col)
entry->obsolete = 1;
#ifndef PLURAL_STRING
if (has_plural_msgid && !dstate->entries->plural_forms)
- if (strlcpy(dstate->error, errors[ERR_NO_PLURAL_FORMS],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_NO_PLURAL_FORMS], dstate->error,
+ MAXBUFLINE);
#endif
}
@@ -555,16 +550,8 @@ save_file(const struct PoEntry* entries, const size_t real_msgid_count,
if (stat(real_filename, &st) == -1)
return SAVE_ERR_CANT_STAT_FILE;
}
- if (strlcpy(backup_filename, filename, MAXPATH) >= MAXPATH)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
- if (strlcat(backup_filename, backup_suffix, MAXPATH) >= MAXPATH)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(filename, backup_filename, MAXPATH);
+ STRLCAT(backup_suffix, backup_filename, MAXPATH);
if (rename(rfn_len > 0 ? real_filename : filename,
backup_filename)
== -1)
diff --git a/poe.c b/poe.c
@@ -31,6 +31,7 @@ extern const char* prompt_overwrite;
extern const char* program_name;
void cancel_callback(struct DrawState* state, struct tb_event* ev);
+char* dirname(char* path);
void goto_msgid(struct DrawState* state, const size_t msgid_number);
void handle_key_event(struct tb_event* ev, struct DrawState* state);
int insert_char(struct DrawState* state, uint32_t ch);
@@ -57,6 +58,35 @@ cancel_callback(struct DrawState* state, struct tb_event* ev)
state->prompt_callback = NULL;
}
+char*
+dirname(char* path)
+{
+ static char* result = NULL;
+ static const char* dot = ".";
+ char* p = NULL;
+ char* slash = NULL;
+
+ if (!path || !*path)
+ return NULL;
+
+ free(result);
+ result = malloc(MAXPATH);
+ memset(result, 0, MAXPATH);
+
+ STRLCPY(path, result, MAXPATH);
+ p = result + strlen(result) - 1;
+ if (*p == '/')
+ *p = 0;
+
+ slash = strrchr(result, '/');
+ if (!slash)
+ return (char*)dot;
+
+ *slash = 0;
+
+ return result;
+}
+
void
goto_msgid(struct DrawState* state, const size_t msgid_number)
{
@@ -120,12 +150,7 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
if (state->show_help)
{
- if (strlcpy(state->error, errors[ERR_DLG_OPEN_QUIT], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_DLG_OPEN_QUIT], state->error, MAXBUFLINE);
return;
}
else if (state->show_edit)
@@ -183,33 +208,11 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
}
if (state->edit_info_focused)
- {
- if (strlcpy(state->error, errors[ERR_DLG_FOCUS_EDIT], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
- }
+ STRLCPY(errors[ERR_DLG_FOCUS_EDIT], state->error, MAXBUFLINE);
else if (state->show_edit || state->show_search)
- {
- if (strlcpy(state->error, errors[ERR_UNKNOWN_KEY], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
- }
+ STRLCPY(errors[ERR_UNKNOWN_KEY], state->error, MAXBUFLINE);
else
- {
- if (strlcpy(state->error, errors[ERR_UNKNOWN_KEY_HELP],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
- }
+ STRLCPY(errors[ERR_UNKNOWN_KEY_HELP], state->error, MAXBUFLINE);
}
int
@@ -688,12 +691,8 @@ cancel_close(struct DrawState* state)
cancel_msgstr(state);
else if (state->show_search)
cancel_search(state);
- else if (strlcpy(state->error, errors[ERR_EXIT_KEY], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ else
+ STRLCPY(errors[ERR_EXIT_KEY], state->error, MAXBUFLINE);
return 0;
}
@@ -704,12 +703,7 @@ cancel_msgstr(struct DrawState* state)
if (!state->in_prompt && state->dirty)
{
state->in_prompt = 1;
- if (strlcpy(state->prompt, prompt_cancel_dirty, MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(prompt_cancel_dirty, state->prompt, MAXBUFLINE);
state->prompt_callback = cancel_callback;
return 0;
}
@@ -763,25 +757,14 @@ copy_msgid_to_input(struct DrawState* state)
if (!state->in_prompt && *state->input_buffer->text)
{
state->in_prompt = 1;
- if (strlcpy(state->prompt, prompt_overwrite, MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(prompt_overwrite, state->prompt, MAXBUFLINE);
state->prompt_callback = overwrite_copy_msgid_callback;
return 0;
}
if (state->msgid_number == 1)
{
- if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_ILLEGAL_ON_FIRST], state->error, MAXBUFLINE);
return 0;
}
@@ -943,13 +926,8 @@ erase_forward(struct DrawState* state)
{
if (!join_lines(state, state->input_row, 1))
{
- if (strlcpy(state->error, errors[ERR_CANT_ALLOC],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state->error,
+ MAXBUFLINE);
state->running = 0;
}
}
@@ -1149,23 +1127,13 @@ exit_program(struct DrawState* state)
{
if (state->show_edit)
{
- if (strlcpy(state->error, errors[ERR_DLG_OPEN], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_DLG_OPEN], state->error, MAXBUFLINE);
return 0;
}
if (state->dirty)
{
state->in_prompt = 1;
- if (strlcpy(state->prompt, prompt_dirty, MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(prompt_dirty, state->prompt, MAXBUFLINE);
state->prompt_callback = quit_callback;
}
else
@@ -1195,12 +1163,7 @@ insert_line(struct DrawState* state)
state->input_rows_count * sizeof(struct BufferLine));
if (!newbuf)
{
- if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state->error, MAXBUFLINE);
state->running = 0;
return 0;
}
@@ -1210,12 +1173,7 @@ insert_line(struct DrawState* state)
uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
if (!newtext)
{
- if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state->error, MAXBUFLINE);
state->running = 0;
return 0;
}
@@ -1796,25 +1754,14 @@ paste_paste_buffer_to_input(struct DrawState* state)
if (!state->in_prompt && *state->input_buffer->text)
{
state->in_prompt = 1;
- if (strlcpy(state->prompt, prompt_overwrite, MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(prompt_overwrite, state->prompt, MAXBUFLINE);
state->prompt_callback = overwrite_paste_callback;
return 0;
}
if (state->msgid_number == 1)
{
- if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_ILLEGAL_ON_FIRST], state->error, MAXBUFLINE);
return 0;
}
@@ -1939,13 +1886,8 @@ save_msgstr(struct DrawState* state)
to_save = calloc(to_save_size, sizeof(uint32_t));
if (!to_save)
{
- if (strlcpy(state->error, errors[ERR_CANT_ALLOC],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state->error,
+ MAXBUFLINE);
return 0;
}
struct BufferLine* pinput_buffer = NULL;
@@ -1992,12 +1934,7 @@ show_edit(struct DrawState* state)
{
if (!load_msgstr(state) || !load_info(state))
{
- if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state->error, MAXBUFLINE);
state->running = 0;
return 0;
}
@@ -2045,13 +1982,7 @@ toggle_fuzzy(struct DrawState* state)
{
if (state->msgid_number == 1)
{
- if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_ILLEGAL_ON_FIRST], state->error, MAXBUFLINE);
return 0;
}
if (state->msgid_count > 0)
@@ -2093,13 +2024,7 @@ yank_input_to_paste_buffer(struct DrawState* state)
if (state->msgid_number == 1)
{
- if (strlcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_ILLEGAL_ON_FIRST], state->error, MAXBUFLINE);
return 0;
}
@@ -2175,30 +2100,15 @@ write_file(struct DrawState* state)
switch (result)
{
case SAVE_ERR_CANT_ALLOC:
- if (strlcpy(state->error, errors[ERR_CANT_ALLOC], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state->error, MAXBUFLINE);
state->running = 0;
break;
case SAVE_ERR_CANT_OPEN_FILE:
- if (strlcpy(state->error, errors[ERR_CANT_SAVE], MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_SAVE], state->error, MAXBUFLINE);
state->running = 0;
break;
case SAVE_ERR_CANT_MOVE_FILE:
- if (strlcpy(state->error, strerror(errno), MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(strerror(errno), state->error, MAXBUFLINE);
state->running = 0;
break;
default:
@@ -2218,11 +2128,24 @@ main(int argc, char** argv)
char filename[MAXPATH];
int recalculate_size = 1;
struct stat st;
+ long lineno;
+ long col;
+ int result;
+ int dir_access;
+ int dir_access_errno;
+ char* dir = NULL;
*error = 0;
*prompt = 0;
*filename = 0;
+#ifdef __OpenBSD__
+ if (pledge("stdio tty unveil rpath wpath cpath fattr", NULL) < 0)
+ {
+ perror("sled: pledge");
+ exit(1);
+ }
+#endif
if (argc == 1)
return print_error(1, "No filename given");
@@ -2281,9 +2204,117 @@ main(int argc, char** argv)
init_drawstate(&state, error, filename, prompt);
- long lineno = 1;
- long col = 1;
- int result = load_file(&state, &lineno, &col);
+#ifdef __OpenBSD__
+ if (unveil(state.filename, "rwc") < 0)
+ {
+ perror("sled: unveil");
+ exit(1);
+ }
+#endif
+
+ dir = dirname(state.filename);
+#ifdef __OpenBSD__
+ if (unveil(dir, "rwc") < 0)
+ {
+ perror("sled: unveil");
+ exit(1);
+ }
+#endif
+#ifdef CREATE_BACKUPS
+ errno = 0;
+ if (lstat(state.filename, &st) != -1)
+ {
+ if (S_ISLNK(st.st_mode))
+ {
+ if (!(state.real_filename = calloc(MAXPATH, 1)))
+ return print_error(1,
+ "Allocation failed (out of memory?)");
+ state.rfn_len = readlink(state.filename,
+ state.real_filename, MAXPATH);
+ if (state.rfn_len == -1)
+ return print_error(1, strerror(errno));
+ state.real_filename[state.rfn_len] = 0;
+#ifdef __OpenBSD__
+ if (unveil(state.real_filename, "rwc") < 0)
+ {
+ perror("sled: unveil");
+ exit(1);
+ }
+#endif
+ if (stat(state.real_filename, &st) == -1)
+ return print_error(1, strerror(errno));
+ }
+ if (!(state.backup_filename = calloc(MAXPATH, 1)))
+ return print_error(1,
+ "Allocation failed (out of memory?)");
+
+ /* Backup filename is the target file + suffix if the file to
+ * write is a symlink, otherwise file + suffix */
+ STRLCPY(state.rfn_len > 0 ? state.real_filename : state.filename,
+ state.backup_filename, MAXPATH);
+ STRLCAT(backup_suffix, state.backup_filename, MAXPATH);
+#ifdef __OpenBSD__
+ if (unveil(state.backup_filename, "rwc") < 0)
+ {
+ perror("sled: unveil");
+ exit(1);
+ }
+#endif
+ }
+ else
+ return print_error(1, strerror(errno));
+#endif /* CREATE_BACKUPS */
+
+ if (state.rfn_len > 0)
+ {
+ dir = dirname(state.real_filename);
+#ifdef __OpenBSD__
+ if (unveil(dir, "rwc") < 0)
+ {
+ perror("sled: unveil");
+ exit(1);
+ }
+#endif
+ }
+
+ dir_access = access(dir, W_OK | X_OK);
+ dir_access_errno = errno;
+#ifdef BACKUP_FAIL_OK
+ state.backup_possible = dir_access != -1;
+#else /* !BACKUP_FAIL_OK */
+ if (dir_access == -1)
+ {
+ errno = dir_access_errno;
+ goto file_error;
+ }
+#endif /* BACKUP_FAIL_OK */
+ if (stat(state.filename, &st) == -1)
+ {
+ errno = dir_access_errno;
+ goto file_error;
+ }
+
+ if (!S_ISREG(st.st_mode))
+ return print_error(EINVAL, "Is not a regular file");
+
+#ifdef __OpenBSD__
+ if (unveil(NULL, NULL) < 0)
+ {
+ perror("sled: unveil");
+ exit(1);
+ }
+#endif
+
+ if (access(state.filename, F_OK | R_OK | W_OK) == -1)
+ goto file_error;
+
+ if (state.rfn_len > 0
+ && access(state.real_filename, F_OK | R_OK | W_OK) == -1)
+ goto file_error;
+
+ lineno = 1;
+ col = 1;
+ result = load_file(&state, &lineno, &col);
switch (result)
{
case LOAD_ERR_CANT_ALLOC:
@@ -2307,7 +2338,13 @@ main(int argc, char** argv)
}
state.msgid_number = state.msgid_count > 0 ? 1 : 0;
state.first_shown_msgid = state.msgid_number;
+ goto init_termbox;
+file_error:
+ perror(program_name);
+ return errno;
+
+init_termbox:
tb_init();
*error = 0;
state.maxx = 0;
@@ -2327,13 +2364,7 @@ main(int argc, char** argv)
state.maxy = tb_height();
if (!draw(&state))
- if (strlcpy(state.error, errors[ERR_CANT_ALLOC],
- MAXBUFLINE)
- >= MAXBUFLINE)
- {
- print_error(1, "strlcpy:%d: Overflow", __LINE__);
- exit(1);
- }
+ STRLCPY(errors[ERR_CANT_ALLOC], state.error, MAXBUFLINE);
tb_present();
result = tb_poll_event(&ev);
if (result == TB_OK && ev.type == TB_EVENT_RESIZE)
diff --git a/util.h b/util.h
@@ -8,6 +8,24 @@
#define LEN(x) (sizeof(x) / sizeof(x[0]))
#define MAX(a, b) ((a > b) ? a : b)
#define MIN(a, b) ((a < b) ? a : b)
+#define STRLCAT(tail, head, totallen) \
+ do \
+ { \
+ if (strlcat(head, tail, totallen) >= totallen) \
+ { \
+ print_error(1, "strlcat:%d: Overflow", __LINE__); \
+ exit(1); \
+ } \
+ } while (0)
+#define STRLCPY(from, to, tolen) \
+ do \
+ { \
+ if (strlcpy(to, from, tolen) >= tolen) \
+ { \
+ print_error(1, "strlcpy:%d: Overflow", __LINE__); \
+ exit(1); \
+ } \
+ } while (0)
enum {
ERR_UNKNOWN_KEY,
@@ -36,13 +54,8 @@ enum {
extern int utlerrno;
-#ifndef strlcpy
size_t strlcpy(char* dst, const char* src, size_t dsize);
-#endif
-#ifndef strlcat
size_t strlcat(char* dst, const char* src, size_t dsize);
-#endif
-
size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max);
size_t unicode_string_to_u8(char* s, const size_t s_size, const uint32_t* us,
const size_t max);