Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package zcfan for openSUSE:Factory checked 
in at 2025-01-01 23:07:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/zcfan (Old)
 and      /work/SRC/openSUSE:Factory/.zcfan.new.1881 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "zcfan"

Wed Jan  1 23:07:46 2025 rev:4 rq:1234116 version:1.4.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/zcfan/zcfan.changes      2024-02-29 
21:50:25.094126622 +0100
+++ /work/SRC/openSUSE:Factory/.zcfan.new.1881/zcfan.changes    2025-01-01 
23:07:53.656426634 +0100
@@ -1,0 +2,11 @@
+Tue Dec 31 08:30:07 UTC 2024 - Andrea Manzini <[email protected]>
+
+- update to 1.4.0:
+  * Mark zcfan.service as conflicting with thinkfan.service
+  * Make fan levels configurable in config
+  * On watchdog timeout, write to watchdog to avoid spinup on some models
+  * Detect suspend and handle fan level reset
+
+- mark as conflicts with thinkfan package
+
+-------------------------------------------------------------------

Old:
----
  zcfan-1.3.0.tar.gz

New:
----
  zcfan-1.4.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ zcfan.spec ++++++
--- /var/tmp/diff_new_pack.mblk5i/_old  2025-01-01 23:07:54.112445361 +0100
+++ /var/tmp/diff_new_pack.mblk5i/_new  2025-01-01 23:07:54.112445361 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           zcfan
-Version:        1.3.0
+Version:        1.4.0
 Release:        0
 Summary:        Zero-configuration fan control daemon for ThinkPads
 License:        MIT
@@ -30,6 +30,7 @@
 BuildRequires:  gcc >= 11
 %endif
 BuildRequires:  make
+Conflicts:      thinkfan
 
 %description
 Zero-configuration fan control daemon for ThinkPads with watchdog

++++++ move_executable_to_sbin.patch ++++++
--- /var/tmp/diff_new_pack.mblk5i/_old  2025-01-01 23:07:54.136446347 +0100
+++ /var/tmp/diff_new_pack.mblk5i/_new  2025-01-01 23:07:54.140446511 +0100
@@ -1,25 +1,15 @@
-diff --color -ur zcfan-1.2.1.orig/Makefile zcfan-1.2.1/Makefile
---- zcfan-1.2.1.orig/Makefile 2022-08-12 03:50:01.000000000 +0200
-+++ zcfan-1.2.1/Makefile  2023-09-04 10:14:18.332038220 +0200
-@@ -5,7 +5,7 @@
+diff --color -ur zcfan-1.4.0.orig/Makefile zcfan-1.4.0/Makefile
+--- zcfan-1.4.0.orig/Makefile  2024-12-18 01:36:27.000000000 +0100
++++ zcfan-1.4.0/Makefile       2024-12-31 09:28:33.344935876 +0100
+@@ -5,8 +5,8 @@
+ EXECUTABLES=$(patsubst %.c,%,$(SOURCES))
  
  INSTALL:=install
- prefix:=/usr/local
+-prefix:=/usr/local
 -bindir:=$(prefix)/bin
++prefix:=/usr
 +bindir:=$(prefix)/sbin
  datarootdir:=$(prefix)/share
  mandir:=$(datarootdir)/man
  
-diff --color -ur zcfan-1.2.1.orig/zcfan.service zcfan-1.2.1/zcfan.service
---- zcfan-1.2.1.orig/zcfan.service  2022-08-12 03:50:01.000000000 +0200
-+++ zcfan-1.2.1/zcfan.service 2023-09-04 10:15:28.486174496 +0200
-@@ -2,7 +2,7 @@
- Description=Zero-configuration fan control for ThinkPad
- 
- [Service]
--ExecStart=/usr/bin/zcfan
-+ExecStart=/usr/sbin/zcfan
- Restart=always
- RestartSec=500ms
- 
 

++++++ zcfan-1.3.0.tar.gz -> zcfan-1.4.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zcfan-1.3.0/Makefile new/zcfan-1.4.0/Makefile
--- old/zcfan-1.3.0/Makefile    2024-02-27 03:55:17.000000000 +0100
+++ new/zcfan-1.4.0/Makefile    2024-12-18 01:36:27.000000000 +0100
@@ -10,7 +10,13 @@
 datarootdir:=$(prefix)/share
 mandir:=$(datarootdir)/man
 
-all: $(EXECUTABLES)
+SERVICE_TEMPLATE=zcfan.service.in
+SERVICE=zcfan.service
+
+all: $(EXECUTABLES) $(SERVICE)
+
+$(SERVICE): $(SERVICE_TEMPLATE)
+       sed 's|@bindir@|$(bindir)|g' $< > $@
 
 %: %.c
        $(CC) $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LIBS) $(LDFLAGS)
@@ -24,7 +30,7 @@
 # Noisy clang build that's expected to fail, but can be useful to find corner
 # cases.
 clang-everything: CC=clang
-clang-everything: CFLAGS+=-Weverything -Wno-disabled-macro-expansion 
-Wno-padded -Wno-covered-switch-default -Wno-gnu-zero-variadic-macro-arguments
+clang-everything: CFLAGS+=-Weverything -Wno-disabled-macro-expansion 
-Wno-padded -Wno-covered-switch-default -Wno-gnu-zero-variadic-macro-arguments 
-Wno-declaration-after-statement
 clang-everything: all
 
 sanitisers: CFLAGS+=-fsanitize=address -fsanitize=undefined -fanalyzer
@@ -41,11 +47,11 @@
 install: all
        mkdir -p $(DESTDIR)$(bindir)/
        $(INSTALL) -pt $(DESTDIR)$(bindir)/ $(EXECUTABLES)
-       $(INSTALL) -Dp -m 644 zcfan.service 
$(DESTDIR)$(prefix)/lib/systemd/system/zcfan.service
+       $(INSTALL) -Dp -m 644 $(SERVICE) 
$(DESTDIR)$(prefix)/lib/systemd/system/$(SERVICE)
        $(INSTALL) -Dp -m 644 zcfan.1 $(DESTDIR)$(mandir)/man1/zcfan.1
 
 lint:
        clang-format -style=file --dry-run --Werror zcfan.c
 
 clean:
-       rm -f $(EXECUTABLES)
+       rm -f $(EXECUTABLES) $(SERVICE)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zcfan-1.3.0/README.md new/zcfan-1.4.0/README.md
--- old/zcfan-1.3.0/README.md   2024-02-27 03:55:17.000000000 +0100
+++ new/zcfan-1.4.0/README.md   2024-12-18 01:36:27.000000000 +0100
@@ -26,18 +26,28 @@
 
 If no trip temperature is reached, the fan will be turned off.
 
+The fan will also only be reduced once the temperature is now at least 10C
+below the trip temperature for the current fan state. This can be tuned with
+the config parameter `temp_hysteresis`.
+
 To override these defaults, you can place a file at `/etc/zcfan.conf` with
-updated trip temperatures in degrees celsius. As an example:
+updated trip temperatures in degrees celsius and/or fan levels. As an example:
 
     max_temp 85
     med_temp 70
     low_temp 55
+    temp_hysteresis 20
+
+    max_level full-speed
+    med_level 4
+    low_level 1
 
 ### Hysteresis
 
 We will only reduce the fan level again once:
 
-1. The temperature is now at least 10C below the trip point, and
+1. The temperature is now at least `temp_hysteresis` Celsius (default 10C)
+   below the trip point, and
 2. At least 3 seconds have elapsed since the initial trip.
 
 This avoids unnecessary fluctuations in fan speed.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zcfan-1.3.0/zcfan.1 new/zcfan-1.4.0/zcfan.1
--- old/zcfan-1.3.0/zcfan.1     2024-02-27 03:55:17.000000000 +0100
+++ new/zcfan-1.4.0/zcfan.1     2024-12-18 01:36:27.000000000 +0100
@@ -51,7 +51,9 @@
 
 We will only reduce the fan level again once:
 .IP "1." 3
-The temperature is now at least 10C below the trip point, and
+The temperature is now at least
+.I temp_hysteresis
+Celsius below the trip point (default 10C), and
 .IP "2." 3
 At least 3 seconds have elapsed since the initial trip.
 .PP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zcfan-1.3.0/zcfan.c new/zcfan-1.4.0/zcfan.c
--- old/zcfan-1.3.0/zcfan.c     2024-02-27 03:55:17.000000000 +0100
+++ new/zcfan-1.4.0/zcfan.c     2024-12-18 01:36:27.000000000 +0100
@@ -14,12 +14,15 @@
 #define FAN_CONTROL_FILE "/proc/acpi/ibm/fan"
 #define TEMP_INVALID INT_MIN
 #define TEMP_MIN INT_MIN + 1
+#define NS_IN_SEC 1000000000L  // 1 second in nanoseconds
+#define THRESHOLD_NS 200000000 // 0.2 seconds
 
 #define STR_HELPER(x) #x
 #define STR(x) STR_HELPER(x)
 #define DEFAULT_WATCHDOG_SECS 120
 #define S_DEFAULT_WATCHDOG_SECS STR(DEFAULT_WATCHDOG_SECS)
 
+#define info(fmt, ...) fprintf(stderr, "[INF] " fmt, ##__VA_ARGS__)
 #define err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ##__VA_ARGS__)
 #define max(x, y) ((x) > (y) ? (x) : (y))
 #define expect(x)                                                              
\
@@ -31,10 +34,13 @@
         }                                                                      
\
     } while (0)
 
+#define CONFIG_MAX_STRLEN 15
+#define S_CONFIG_MAX_STRLEN STR(CONFIG_MAX_STRLEN)
+
 /* Must be highest to lowest temp */
 enum FanLevel { FAN_MAX, FAN_MED, FAN_LOW, FAN_OFF, FAN_INVALID };
 struct Rule {
-    const char *tpacpi_level;
+    char tpacpi_level[CONFIG_MAX_STRLEN + 1];
     int threshold;
     const char *name;
 };
@@ -47,7 +53,7 @@
 
 static struct timespec last_watchdog_ping = {0, 0};
 static time_t watchdog_secs = DEFAULT_WATCHDOG_SECS;
-static const unsigned int fan_hysteresis = 10;
+static int temp_hysteresis = 10;
 static const unsigned int tick_hysteresis = 3;
 static char output_buf[512];
 static const struct Rule *current_rule = NULL;
@@ -55,6 +61,11 @@
 static int first_tick = 1; /* Stop running if errors are immediate */
 static glob_t temp_files;
 
+enum resume_state {
+    RESUME_NOT_DETECTED,
+    RESUME_DETECTED,
+};
+
 static void exit_if_first_tick(void) {
     if (first_tick) {
         err("Quitting due to failure during first run\n");
@@ -62,6 +73,36 @@
     }
 }
 
+static int64_t timespec_diff_ns(const struct timespec *start,
+                                const struct timespec *end) {
+    return ((int64_t)end->tv_sec - (int64_t)start->tv_sec) * NS_IN_SEC +
+           (end->tv_nsec - start->tv_nsec);
+}
+
+static enum resume_state detect_suspend(void) {
+    static struct timespec monotonic_prev, boottime_prev;
+    struct timespec monotonic_now, boottime_now;
+
+    expect(clock_gettime(CLOCK_MONOTONIC, &monotonic_now) == 0);
+    expect(clock_gettime(CLOCK_BOOTTIME, &boottime_now) == 0);
+
+    if (monotonic_prev.tv_sec == 0 && monotonic_prev.tv_nsec == 0) {
+        monotonic_prev = monotonic_now;
+        boottime_prev = boottime_now;
+        return RESUME_NOT_DETECTED;
+    }
+
+    int64_t delta_monotonic = timespec_diff_ns(&monotonic_prev, 
&monotonic_now);
+    int64_t delta_boottime = timespec_diff_ns(&boottime_prev, &boottime_now);
+
+    monotonic_prev = monotonic_now;
+    boottime_prev = boottime_now;
+
+    return delta_boottime > delta_monotonic + THRESHOLD_NS
+               ? RESUME_DETECTED
+               : RESUME_NOT_DETECTED;
+}
+
 static int glob_err_handler(const char *epath, int eerrno) {
     err("glob: %s: %s\n", epath, strerror(eerrno));
     return 0;
@@ -178,7 +219,7 @@
             if (tick_penalty) {
                 return 0; /* Must wait longer until able to move down levels */
             }
-            temp_penalty = fan_hysteresis;
+            temp_penalty = temp_hysteresis;
         }
 
         if (rule->threshold < temp_penalty ||
@@ -203,15 +244,24 @@
 static void maybe_ping_watchdog(void) {
     struct timespec now;
 
+    expect(current_rule);
     expect(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
 
+    if (detect_suspend() == RESUME_DETECTED) {
+        // On resume, some models need a manual fan write again, or they will
+        // revert to "auto".
+        info("Clock jump detected, possible resume. Rewriting fan level\n");
+        write_fan_level(current_rule->tpacpi_level);
+    }
+
     if (now.tv_sec - last_watchdog_ping.tv_sec <
         (watchdog_secs - WATCHDOG_GRACE_PERIOD_SECS)) {
         return;
     }
 
-    expect(current_rule); /* Already set up on first run by set_fan_level */
-    write_fan_level(current_rule->tpacpi_level);
+    // Transitioning from level 0 -> level 0 can cause a brief fan spinup on
+    // some models, so don't reset the timer by write_fan_level().
+    write_watchdog_timeout(watchdog_secs);
 }
 
 #define CONFIG_PATH "/etc/zcfan.conf"
@@ -225,6 +275,17 @@
         }                                                                      
\
     } while (0)
 
+#define fscanf_str_for_key(f, pos, name, dest)                                 
\
+    do {                                                                       
\
+        char val[CONFIG_MAX_STRLEN + 1];                                       
\
+        if (fscanf(f, name " %" S_CONFIG_MAX_STRLEN "s ", val) == 1) {         
\
+            strncpy(dest, val, CONFIG_MAX_STRLEN);                             
\
+            dest[CONFIG_MAX_STRLEN] = '\0';                                    
\
+        } else {                                                               
\
+            expect(fseek(f, pos, SEEK_SET) == 0);                              
\
+        }                                                                      
\
+    } while (0)
+
 static void get_config(void) {
     FILE *f;
 
@@ -245,6 +306,10 @@
         fscanf_int_for_key(f, pos, "med_temp", rules[FAN_MED].threshold);
         fscanf_int_for_key(f, pos, "low_temp", rules[FAN_LOW].threshold);
         fscanf_int_for_key(f, pos, "watchdog_secs", watchdog_secs);
+        fscanf_int_for_key(f, pos, "temp_hysteresis", temp_hysteresis);
+        fscanf_str_for_key(f, pos, "max_level", rules[FAN_MAX].tpacpi_level);
+        fscanf_str_for_key(f, pos, "med_level", rules[FAN_MED].tpacpi_level);
+        fscanf_str_for_key(f, pos, "low_level", rules[FAN_LOW].tpacpi_level);
         if (ftell(f) == pos) {
             while ((ch = fgetc(f)) != EOF && ch != '\n') {}
         }
@@ -296,7 +361,8 @@
 
     if (!full_speed_supported()) {
         err("level \"full-speed\" not supported, using level 7\n");
-        rules[FAN_MAX].tpacpi_level = "7";
+        strncpy(rules[FAN_MAX].tpacpi_level, "7", CONFIG_MAX_STRLEN);
+        rules[FAN_MAX].tpacpi_level[CONFIG_MAX_STRLEN] = '\0';
     }
 
     write_watchdog_timeout(watchdog_secs);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zcfan-1.3.0/zcfan.service 
new/zcfan-1.4.0/zcfan.service
--- old/zcfan-1.3.0/zcfan.service       2024-02-27 03:55:17.000000000 +0100
+++ new/zcfan-1.4.0/zcfan.service       1970-01-01 01:00:00.000000000 +0100
@@ -1,20 +0,0 @@
-[Unit]
-Description=Zero-configuration fan control for ThinkPad
-
-[Service]
-ExecStart=/usr/bin/zcfan
-Restart=always
-RestartSec=500ms
-
-MemoryDenyWriteExecute=yes
-NoNewPrivileges=yes
-ProtectControlGroups=yes
-RestrictAddressFamilies=
-RestrictRealtime=yes
-
-# We don't need to do any substantial clean up, so if something hangs it's
-# going to stay that way. Just forcefully kill and get it over with.
-TimeoutStopSec=2
-
-[Install]
-WantedBy=default.target
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/zcfan-1.3.0/zcfan.service.in 
new/zcfan-1.4.0/zcfan.service.in
--- old/zcfan-1.3.0/zcfan.service.in    1970-01-01 01:00:00.000000000 +0100
+++ new/zcfan-1.4.0/zcfan.service.in    2024-12-18 01:36:27.000000000 +0100
@@ -0,0 +1,21 @@
+[Unit]
+Description=Zero-configuration fan control for ThinkPad
+Conflicts=thinkfan.service
+
+[Service]
+ExecStart=@bindir@/zcfan
+Restart=always
+RestartSec=500ms
+
+MemoryDenyWriteExecute=yes
+NoNewPrivileges=yes
+ProtectControlGroups=yes
+RestrictAddressFamilies=
+RestrictRealtime=yes
+
+# We don't need to do any substantial clean up, so if something hangs it's
+# going to stay that way. Just forcefully kill and get it over with.
+TimeoutStopSec=2
+
+[Install]
+WantedBy=default.target

Reply via email to